Generic Transmission ===================== 概述 ------ Generic Transmission 提供数据传输功能。可以将 log、dump 等信息通过如 UART、Flash 等端口传输给不同的设备。 功能特性 ------------------- - 提供信息传输枢纽的功能。 - 支持 UART、Flash、SPP 等媒介输出。 - 支持多种 TID, 多种优先级。 - 支持缓存 buffer 长度自配置。 - 支持 ACK, 重传机制 帧格式说明 ------------------- .. image:: ../../../_static/Generic_transmission_packet_format.png :align: center Generic Transmission Frame Format 由四部分构成: Preamble、Header、Payload、FCS, 说明如下: .. csv-table:: :header: Field, 描述, 长度 :widths: 5, 20, 10 "Preamble", "固定 4 字节, 固定内容 0xc1c5d2d0, 因为丢包的存在, 用于查找 Packet 起始位置", "4 Bytes" "Header", "| **Header Field** | **.Version**: 用来标准协议版本信息, 以供对端确定是否兼容 | **.Packet Length**: 包含了从整个包的长度, 包括 Header、Payload | 和 FCS(如果 Frame Control 指示 CRC Enable 的话),Packet Length | 放在最前面, 是方便在 变长传输模式下, 方便获取整个包长和解析包结构。 | **.Major Type**: 目前指定了主类型目前支持 Control 和 Data 两种类型 | **.Sub Type**: 在主类型的基础上,指定了子类型, | 例如 DATA 主类下的 stream log、cli、raw log 等等,control 类型下的 ACK 帧 | **.Transport ID (TID)**: 这个用来区分不同的数据流,这里 TID 只对 DATA 包有效, | 不同的 Data Sub Type 可以共用同一个 TID,发送端会对 同一个 TID 的数据进行时间排序, | 不会对不同的 TID 进行时间排序。比如 RAW log 和 Stream log 想要进行混合时间排序, | 那么这两个 Data Sub Type 需要公用同一个 TID;而 CLI 和 Audio Dump 想要独立出来, | 那么 CLI 和 Audio Dump 分别用另外一个 TID | **.Fragment**: 这个用来区分不同的数据流,这里 TID 只对 DATA 包有效, | 不同的 Data Sub Type 可以共用同一个 TID,发送端会对 同一个 TID 的数据进行时间排序, | 不会对不同的 TID 进行时间排序。比如 RAW log 和 Stream log 想要进行混合时间排序, | 那么这两个 Data Sub Type 需要公用同一个 TID;而 CLI 和 Audio Dump 想要独立出来, | 那么 CLI 和 Audio Dump 分别用另外一个 TID | **.Need ACK**: 指示 Remote 收到此 Packet 时,是否需要回复 Ack Packet (如 Single Ack), | 这里的 Ack Packet 只是用来确认对应的 Packet 有没有收到,不用于控制类型的业务处理 | **.Sequence**: 用于记录当前包的序号,不同的 TID 的 data 包,使用各自独立的 Sequence; | Control 和 Management 类型也分别使用各自独立的 Sequence, 在传输过程中, | 因为 Remote 设备回复 Ack 的情况不同,可能导致 乱序发生; | Receiver 在收到 Packet 时,应当检查 Sequence 并进行 Re-order","8 Bytes" "Payload", "Data 包的 Payload 就是原始数据本身, Control 包的 Payload 根据不同的 Type 应当不一样。", "NA" "FCS", "帧校验序列,这里选用的时 CRC32。检验的内容包括 Packet Header 和 Packet Payload", "4 Bytes" 设计框架 ------------------- 下图是 Generic transmission 的设计框图: .. image:: ../../../_static/Generic_transmission_arch.png :align: center 1. 主体设计原理分为两大块: (1) 通过 Share Memory 将 slave Core 的数据送到 master core, master Core 上的 Generic Transmission Consumer Task 负责从 对应的 Share Memory 去出数据,会从 Heap 中分 配一个新的 Buffer, Copy 之后,存入对应的 TX Queue. (2) Master core 上 Generic Transmission Profile TX Task 和 Generic Transmission Profile RX Task 分别负责 TX/RX 协议的处理。从 Tx Queue 中取出数据,进行 UART 发 送;同时将收到 ACK 的数据从 TX Queue 中释放 2. 特征说明: (1) Share Memory 操作的 API 的返回值,描述了写入了多少 Length;这样 User 向 Share Memory 写入数据时,发现没有写完,可以自行决定丢弃数据,还是继续写入(当 DTOP 的 Generic Transmission Consumer Task 从 Share Memory 读取后, User 可以 继续写入成功)。每个 User 都可以使用指定的 TID 、 IO 、 DATA TYPE 、 LAZY/ASAP MODE 等参数,这些参数 会写入 Share Memory,同时会记录调用 API 时的 TimeStamp,用 于排序. (2) Generic Transmission Consumer Task 会有个 最大分配 Packet 总大小 (Data 类型 和 Control 类型会独立设定限制),会根据 剩余 Heap 来设定上限,避免占用过 多的 Memory。当现有 Queue 中的 Packet 总大小超过阈值时,后面想要分配 Packet 并写 入 TX Queue 的操作会被 Block 住,直到 Packet 总大小低于阈值。Blocking 的方式可以避因 软件处理不正确而丢包。 Generic Transmission Consumer Task 按照 TimeStamp 从 Share Memory 中取出对应的数据并送入 TX Queue (3) Generic Transmission Profile TX Task 会将 Packet 传输到 PC,传输时会 按设定的 TID Prio 进行 TX,并自动做负载均衡,当当前 TX Queue 降到 Water Mark 以 下,就会发送其他 TX Queue ;当所有 TX Queue 均降到 Water Mark 以下,再按 TID Prio 发送 剩余数据 (4) IO RX Handler 通常在中断上下问执行,将 RX 数据填入 Ring Buffer,并 Post Generic Transmission Profile RX Task 进行收包处理。如果 RX 结果是发送 Ack 或其他控制 类 packet,则调用 TX 相关的函数,将 Ack 包送到对应的 TX Queue ; 如果是需要调用 RX Callback 通知 User,则建议 Post message 到对应的 User Task 进行处理,不建议 直接在 RX callback 里处理过多的代码。 重传协议 ------------------- 1. 没有 Ack 机制的传输情况 | 传输过程: | Sender 向 Receiver 发包 | Receiver 收到包: CRC 正确,包收下 | CRC 错误,包丢弃, 或者报错 | 这种情况发生了数据丢失;即使将错包收下,后续使用数据也会出现问题。 2. 带 ACK 和重传的 传输情况 | 重传发生的几种情况: | 1. 超时未收到 Ack | 2. 收到的 ACK 中的 ACK STATUS 为某些异常值 | 传输过程: | Sender 发送包: | Sender 等待 ACK,Timeout 内等到 ACK 包, 检查 CRC,Send 收到 ACK 包 CRC 正确, 检查 Seq,Seq 存在, 检查 ACKSTATUS,ACKSTATUS 正确, 此 Packet 发送完毕 (释放 Packet 所占的 Memory) | ACK STATUS 错误, 则进行重传 Seq 不存在, 则丢弃. Sender 收到 ACK CRC 不正确, 丢弃 (等到某个包一直没有收到 ACK, 会进行超时强制重传). | Timeout 还没有收到 ACK 包, 进行强制重传 (所有未能正常收到 ACK 的包, 最终都会进行重传, 再重复上述流畅, 直到收到为止) | Receiver 收到包: | 查找 Preamble(从 ReadIndex 开始查找), 没有找到, 则继续收包, 直到找到第一个出现的 Preamble(此时的 Preamble 可能是真, 可能是假, 没关系, 如果是假的, 后续 HEC 和 CRC 极大的概率会出错), | 若找到, 则记录当前 Preamble 位置读取 Header, 并检查 HEC,HEC 正确: 继续处理 Payload 部分, HEC 错误: 直接认为 Header 不可信, 当前 ReadIndex 跳到刚才找到的 Preamble 末尾, 读取 Payload, 并检查 CRC, | 1. CRC 正确. | 认为 Sequence 是要收的数据, 则回复 ACK(ackstatus=0), 并检查 RXcache, 进行 Re-order 触发正常收包. | 认为 Sequence 已经收过的数据, 则回复 ACK(ackstatus=0), 但忽略此包. | 认为 Sequence 不是当前要收的数据, 则回复 Ack(ackstatus=0), 将包先存入 RXCache. | 当前 ReadIndex 跳到刚才找到的该 Packet 末尾. | 2. CRC 错误 (两种选择)HEC 正确, 说明 Sequence 可信, 根据实际情况, 发送 ACK(ackstatus=ForceRetry 或其他 status), 要求 Sender 重传或丢弃. .. image:: ../../../_static/Generic_transmission_send_with_ack.png :align: center API 介绍 ------------ .. doxygenfile:: generic_transmission.h