• 使用 stream buffer 传递数据


    使用 stream buffer 传递数据

    概述

    如前所述,队列虽然提供了任务之间传递数据的功能,但没有对通知机制进行优化,即不方便实现多次采集不同长度的数据,然后触发一次通知接收的机制。

    特性概述

    Streambuffer 的中文含意是“流式缓冲区”,其特点可以概述如下:

    1)发送消息的一方(发送方)与获取消息的一方(接收方)之间可以按任意长度的字节流的方式进行数据传递。

    2)可以设置触发唤醒通知的字节数,仅在缓冲区中的数据达到一定长度时,才唤醒接收方接收数据。

    在这里插入图片描述

    3)适用于仅有一个发送方、一个接收方的场景。如果有多个发送方、接收方,则需要在发送、接收处添加互斥保护,特别地,多个接收方时应将接收阻塞时间设置为0。

    Streambuffer 的基本结构如图所示,主要由消息缓冲区、管理消息缓冲区的相关字段、解阻塞字节数标记、以及两个阻塞延时列表组成。一定程度上,Streambuffer 可以看作在触发接收的机制上改良的队列。
    在这里插入图片描述

    相关 API

    // 创建新的流缓冲区
    StreamBufferHandle_t xStreamBufferCreate(xBufferSizeBytes, // 流缓冲区的总字节数。
    					xTriggerLevelBytes) // 触发唤醒的字节数,流缓冲区中必须存在不少该字节数的数据才能唤醒等待数据的任务(设置为0时,将按照如1的方式处理,设置的数比buffer_size还大时,创建无效)
    					
    // 向流缓冲区去发送数据
    size_t xStreamBufferSend(StreamBufferHandle_t xStreamBuffer, // 要从中发送字节的流缓冲区的句柄。
    						const void *pvTxData, // 指向要复制到流缓冲区中的字节的缓冲区的指针。
    						size_t xDataLengthBytes, // 从 pvTxData 复制到流缓冲区的最大字节数。
    						TickType_t xTicksToWait) // 若无法完成发送 xDataLengthBytes 个字节数据的目的,则等待该延时时间
        
    // 从流缓冲区中接收数据
    size_t xStreamBufferReceive(StreamBufferHandle_t xStreamBuffer, // 要从中接收字节的流缓冲区的句柄。
    							void *pvRxData,                     // 指向将接收的字节复制到的缓冲区的指针。
    							size_t xBufferLengthBytes, // 设置一个要接收的最大字节数。
    							TickType_t xTicksToWait) // 如果流缓冲区为空,则任务应保持“blocked”状态以等待数据变为可用的最长时间,时间以tick周期为基本单位。
        
    // 重置流缓冲区
    // 将流缓冲区重置为其初始空状态。流缓冲区中的任何数据都将被丢弃。仅当没有任务被阻止等待发送到流缓冲区或从流缓冲区接收时,才能重置流缓冲区。
     BaseType_t xStreamBufferReset(StreamBufferHandle_txStreamBuffer) // 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    注意,Receive 返回的情况有两种可能:

    1)获取到不小于唤醒长度的数据。

    2)超时返回,此时实际获取的数据长度为 [0,TriggerLevel]。

    API 参考:stream buffer API, 读者可以通过点击网页自行查看每个 API 的使用方法和参数。

    需求及功能解析

    示例创建了一个 TriggerLevel 为 5 的streambuf,来实现 task1 中每产生五个数据就自动唤醒 task2 处理数据的逻辑。

    示例解析

    示例输出:

    This is esp32 chip with 2 CPU core(s), WiFi/BT/BLE, Minimum free heap size: 295348 bytes
    TASK1: flag=0
    TASK2: timeout and read some data
    TASK2: The buffer data is as follows:00 
    TASK1: flag=1
    TASK1: flag=2
    TASK1: flag=3
    TASK1: flag=4
    TASK1: flag=5
    TASK2: read triggle level bytes
    TASK2: The buffer data is as follows:01 02 03 04 05 
    TASK1: flag=6
    TASK1: flag=7
    TASK1: flag=8
    TASK1: flag=9
    TASK1: flag=10
    TASK2: read triggle level bytes
    TASK2: The buffer data is as follows:06 07 08 09 0a
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    这种自动的触发机制,比上节使用队列的情况要简单了一些。

    讨论

    Streambuffer 虽然实现了可以发送不定长度的数据串,并规定了一定的触发唤醒机制:即数据量至少达到 TriggerLevel 才唤醒等待数据的任务。

    但是一些情况下,发送的数据是不定长度的数据块,每个数据块都具有指定的格式,具备不同的长度,并且不能被拆分和组合。

    比如发送数据的任务发送人的身份证号、手机号码。接收数据的任务要准确地识别这些数据,必须知道数据的长度,否则无法区分那部分数据属于身份证数据、手机号码数据。

    流式缓冲区无法描述这些不定长数据块的具体长度。我们将在下一节介绍处理不定长离散数据块的通信组件。

    总结

    1)Streambuffer 可看作针对单一生产者、消费者传输不定长数据通信场景而优化的 queue。

    2)Streambuffer 还优化了唤醒机制,可以设置触发唤醒通知的字节数,仅在缓冲区中的数据达到一定长度时,才唤醒接收方接收数据。

    3)Streambuffer 可以传输没有固定结构的不定长数据,但是它无法描述这些不定长数据块的具体长度。

    资源链接

    1)Learning-FreeRTOS-with-esp32 系列博客介绍
    2)对应示例的 code 链接 (点击直达代码仓库)

    3)下一篇:使用 message buffer 传递数据

  • 相关阅读:
    药品研发--工艺技术人员积分和职务考核评估管理办法
    CTF-python爬虫学习笔记
    PAT 1004 Counting Leaves
    leetcode每天5题-Day54(贪心3)
    安卓实现网格布局的效果
    @Transactional失效的几种情况说明
    【百日刷题计划 第十一天】——熟悉函数,递归及递推 函数,递归及递推基础题
    SEO搜索引擎
    基于辐射转移模型的多层回归学习,用于估计高光谱图像中的阴影图(Matlab代码实现)
    ssh远程安装teamviewer与正在连接...问题解决方法
  • 原文地址:https://blog.csdn.net/wangyx1234/article/details/127660414