Generic Transmission

概述

Generic Transmission 提供数据传输功能。可以将 log、dump 等信息通过如 UART、Flash 等端口传输给不同的设备。

功能特性

  • 提供信息传输枢纽的功能。

  • 支持 UART、Flash、SPP 等媒介输出。

  • 支持多种 TID, 多种优先级。

  • 支持缓存 buffer 长度自配置。

  • 支持 ACK, 重传机制

帧格式说明

../../_images/Generic_transmission_packet_format.png

Generic Transmission Frame Format 由四部分构成: Preamble、Header、Payload、FCS, 说明如下:

Field

描述

长度

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 的设计框图:

../../_images/Generic_transmission_arch.png
  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 重传或丢弃.
../../_images/Generic_transmission_send_with_ack.png

API 介绍

Defines

GTB_ST_DISABLE

generic transmission domani in disable status

GTB_ST_ENABLE

generic transmission domani in enable status

GTB_ST_IN_PANIC

generic transmission domani in panic output status

GTB_ST_PANIC_END

generic transmission domani in panic output end status

GTB_ST_NOT_INIT

generic transmission domani in initial status

Typedefs

typedef void (*wq_generic_transmission_data_rx_cb_t)(wq_generic_transmission_io_t io, wq_generic_transmission_tid_t tid, wq_generic_transmission_data_type_t type, uint8_t *data, uint32_t data_len, wq_generic_transmission_data_rx_cb_st_t status)
typedef bool (*wq_generic_transmission_repack_cb_t)(const uint8_t *buffer)
typedef int32_t (*wq_generic_transmission_io_send_t)(const uint8_t *buf, uint32_t len)
typedef int32_t (*wq_generic_transmission_io_send_panic_t)(const uint8_t *buf, uint32_t len)
typedef int32_t (*wq_generic_transmission_io_query_t)(void *info)
typedef void (*wq_generic_transmission_io_init_t)(void)
typedef void (*wq_generic_transmission_io_deinit_t)(void)

Enums

enum wq_generic_transmission_io_t

Values:

enumerator GENERIC_TRANSMISSION_IO_UART0

generic transmission IO methold UART0

enumerator GENERIC_TRANSMISSION_IO_SPP

generic transmission IO methold SPP

enumerator GENERIC_TRANSMISSION_IO_FLASH

generic transmission IO methold FLASH

enumerator GENERIC_TRANSMISSION_IO_CDC

generic transmission IO methold USB-CDC

enumerator GENERIC_TRANSMISSION_IO_NUM
enum wq_generic_transmission_tid_t

Values:

enumerator GENERIC_TRANSMISSION_TID0
enumerator GENERIC_TRANSMISSION_TID1
enumerator GENERIC_TRANSMISSION_TID2
enumerator GENERIC_TRANSMISSION_TID3
enumerator GENERIC_TRANSMISSION_TID4
enumerator GENERIC_TRANSMISSION_TID5
enumerator GENERIC_TRANSMISSION_TID6
enumerator GENERIC_TRANSMISSION_TID7
enumerator GENERIC_TRANSMISSION_TID_NUM
enum wq_generic_transmission_prio_t

Values:

enumerator GENERIC_TRANSMISSION_PRIO0
enumerator GENERIC_TRANSMISSION_PRIO1
enumerator GENERIC_TRANSMISSION_PRIO2
enumerator GENERIC_TRANSMISSION_PRIO3
enumerator GENERIC_TRANSMISSION_PRIO4
enumerator GENERIC_TRANSMISSION_PRIO5
enumerator GENERIC_TRANSMISSION_PRIO6
enumerator GENERIC_TRANSMISSION_PRIO7
enumerator GENERIC_TRANSMISSION_PRIO_NUM
enum wq_generic_transmission_data_type_t

Values:

enumerator GENERIC_TRANSMISSION_DATA_TYPE_DFT

generic transmission default data type

enumerator GENERIC_TRANSMISSION_DATA_TYPE_STREAM_LOG

generic transmission sub data type stream log

enumerator GENERIC_TRANSMISSION_DATA_TYPE_RAW_LOG

generic transmission sub data type raw log

enumerator GENERIC_TRANSMISSION_DATA_TYPE_CLI

generic transmission sub data type cli

enumerator GENERIC_TRANSMISSION_DATA_TYPE_AUDIO_DUMP

generic transmission sub data type audio dump data type

enumerator GENERIC_TRANSMISSION_DATA_TYPE_PANIC_LOG

generic transmission sub data type panic log

enumerator GENERIC_TRANSMISSION_DATA_TYPE_HCI_LOG

generic transmission sub data type bt controller hci log

enumerator GENERIC_TRANSMISSION_DATA_TYPE_NUM
enum wq_generic_transmission_tx_mode_t

Values:

enumerator GENERIC_TRANSMISSION_TX_MODE_LAZY

generic transmission output with lazy mode

enumerator GENERIC_TRANSMISSION_TX_MODE_ASAP

generic transmission output with as soon as possible mode

enumerator GENERIC_TRANSMISSION_TX_MODE_NUM
enum wq_generic_transmission_data_rx_cb_st_t

Values:

enumerator GENERIC_TRANSMISSION_DATA_RX_CB_ST_OK

Functions

int32_t wq_generic_transmission_data_tx(wq_generic_transmission_tx_mode_t mode, wq_generic_transmission_data_type_t type, wq_generic_transmission_tid_t tid, wq_generic_transmission_io_t io, const uint8_t *data, uint32_t data_len, bool need_ack)

Tx data by generic_transmission.

参数:
  • mode -- tx mode

  • type -- data type

  • tid -- transport id, can be used to set different priority

  • io -- IO method, such as UART0/UART1/BLE/I2C and etc.

  • data -- data pointer

  • data_len -- data length

  • need_ack -- whether this data transmission need ack by remote device or not. Warning!!!: TX with the same TID must use unique need_ack value, or it may cause data missing!!!

返回:

>= 0 - handled size, < 0 - fail.

void wq_generic_transmission_set_panic_rtc_tick(void)

set current panic core rtc tick

uint8_t wq_generic_transmission_get_first_panic_core(void)

get first panic core by panic rtc tick

返回:

first panic core id

void wq_generic_transmission_panic_start(void)

Set generic transmission in panic status Used for indicate each share memory in panic status. In panic status, the tx process is different form normal status.

void wq_generic_transmission_panic_end(void)

Set generic transmission in panic end status. This status means panic is end. For exmpale, if core1 is in panic, then core0 is in panic, too. Core0 should call wq_generic_transmission_consumer_tx_process_panic to handler the data which is in TX Queue and in share memory in excpetion context(ISR), wq_generic_transmission_consumer_tx_process_panic will return, When core1 call wq_generic_transmission_panic_end. Then core0 can handle itself's panic log.

uint8_t wq_generic_transmission_get_status(uint8_t buffer_id)

Get the buffer id generic transmission status. return GTP status.

bool wq_generic_transmission_in_panic(void)

Get the system_status in panic or not, get true if in panic status, otherwise get false. return system gtp status in panic or not.

int32_t wq_generic_transmission_data_tx_panic(wq_generic_transmission_tx_mode_t mode, wq_generic_transmission_data_type_t type, wq_generic_transmission_tid_t tid, wq_generic_transmission_io_t io, const uint8_t *data, uint32_t data_len)

Tx data type in panic, force to not need ack.

参数:
  • mode -- tx mode

  • type -- data type

  • tid -- transport id, can be used to set different priority

  • io -- IO method, such as UART0/UART1/BLE/I2C and etc.

  • data -- data pointer

  • data_len -- data length

返回:

>= 0 - handled size, < 0 - fail.

void wq_generic_transmission_consumer_tx_process_panic(void)

TX process other share memory instead of consumer task in core0 panic,.

int32_t wq_generic_transmission_register_rx_callback(wq_generic_transmission_tid_t tid, wq_generic_transmission_data_rx_cb_t cb)

register RX callback function when recieve packet. only allow it be called on core0. The other cores call it will cause return failure value.

参数:
  • tid -- data stream tid

  • cb -- callback function

返回:

0 - success, other value - fail.

int32_t wq_generic_transmission_set_tid_priority(wq_generic_transmission_tid_t tid, wq_generic_transmission_prio_t prio)

set priority for specified TID. only allow it be called on core0. The other cores call it will cause return failure value.

参数:
  • tid -- transport ID

  • prio -- priority value

返回:

0 - success, other value - fail.

int32_t wq_generic_transmission_register_repack_callback(wq_generic_transmission_data_type_t type, wq_generic_transmission_repack_cb_t cb)

register repack data callback function when send packet. will modify send data before put pata to share memory

参数:
  • type -- data type

  • cb -- callback function

返回:

0 - success, other value - fail.

int32_t wq_generic_transmission_set_priority(uint8_t priority)

set priority of generic transmission protocol

参数:

priority -- priority of generic transmission consumer task and generic transmission profile task

返回:

0 - success, other value - fail.

int32_t wq_generic_transmission_restore_priority(void)

restore priority of generic transmission protocol to default

返回:

0 - success, other value - fail.

void wq_generic_transmission_init(void)

Initialise generic transmission module.

void wq_generic_transmission_deinit(void)

De-initialise generic transmission module.

int32_t wq_generic_transmission_query(wq_generic_transmission_io_t io, void *info)

Query io log info, write index and total len, special used in non-valatile device,like flash.

参数:
  • io -- IO method, such as UART0/UART1/BLE/I2C and etc.

  • info -- Query io log information, special with IO

返回:

0 - success, other value - fail.

int32_t wq_generic_transmission_io_method_register(wq_generic_transmission_io_t io, wq_generic_transmission_io_method_t *method)

Register IO methods to generic transmission IO abstract layer, generic transmission IO abstract layer will call the function pointer of these methods.

参数:
  • io -- IO method, such as UART0/UART1/BLE/I2C and etc.

  • method -- methods structure pointer.

返回:

= 0 - success, other - fail.

void wq_generic_transmission_io_recv(wq_generic_transmission_io_t io, const uint8_t *data, uint32_t data_len, bool in_isr)

IO owner should call this function when it want transfer its RX data to generic transmssion IO abstract layer.

参数:
  • io -- IO method, such as UART0/UART1/BLE/I2C and etc.

  • data -- RX data pointer.

  • data_len -- RX data length.

  • in_isr --

struct wq_generic_transmission_io_method_t

Public Members

wq_generic_transmission_io_send_t send

< send is necessary, each IO owner should implement it send_panic is not necessary. It is used for log output in panic

wq_generic_transmission_io_send_panic_t send_panic

query is not necessary. It is used for dumping log, often use in flash io

wq_generic_transmission_io_query_t query

If the IO initialise need be called by generic transmission, it's necessary. Otherwise, if IO initialise is called by IO owner, init is not necessary.

wq_generic_transmission_io_init_t init

If the IO de-initialise need be called by generic transmission, it's necessary. Otherwise, if IO de-initialise is called by IO owner, init is not necessary.

wq_generic_transmission_io_deinit_t deinit