python cobs协议编解码算法demo

1. Summary

COBS(Consistent Overhead Byte Stuffing)是一种算法,直译为一致的开销字节填充。简而言之,无论数据包的内容如何,都能通过产生高效可靠明确的数据包帧,从而使接受端能够从损坏的包中恢复。通常使用0x00来作为数据包的分隔符,即切割数据包的片分隔符。当使用0x00作为分隔符时,此算法会把每个零数据字节替换为非零值,这样数据包中就不会出现零数据字节,从而被误解为数据包分隔符。字节填充则是将可能包含"非法"或"保留"值,比如说数据包分隔符的数据字节序列,转换成不含这些值的序列的过程,当然可能会让这个序列变得更长,转换后的序列的额外长度通常被称为该算法的“开销”。关于开销有个例子,有个HDLC帧结构字节填充技术,大多数情况下开销很小,不到1%,但是最坏的情况下,数据包完全由需要转义的字节组成时,开销会达到100%。假设有一段数据需要通过HDLC帧结构传输,且该数据由一些特殊字节组成,这些字节需要进行转义处理:

  • 原始数据:

    7E 7D 7E
    
    • 这里,7E是HDLC帧的结束标志,7D是转义字符。
  • 经过HDLC字节填充后的数据:

    7D 5E 7D 5D 7D 5E
    
    • 7E被转义为7D 5E7D被转义为7D 5D,另一个7E再次转义为7D 5E

在这种情况下,原始数据的长度是3个字节,但经过HDLC字节填充后,长度变成了6个字节,数据大小翻倍,开销达到了100%。

那么,COBS算法严格限制了最坏开销的情况,COBS最少需要一个字节的开销,对于长度为N的数据包,需要最大的(n/254)字节开销。因此,传输编码字节序列的时间是高度可预测的,这使得COBS对于可能存在抖动问题的实时应用程序非常有效。算法计算成本也是不高的,除了最坏情况的开销外,与HDLC这种算法相比也是要更低的。但是在传输他的第一个字节前,他必须要知道接下来254个字节中的第一个0字节。

2. Packet Framing And Stuffing

当分组数据通过串行协议发送时,需要一些协议来划分数据包的边界。这是通过使用帧标记来完成的,这是一个特殊的位序列或字符值,指示数据包之间的边界在哪里。数据填充是指在传输前对数据包数据进行转换以消除所有出现的分帧标记的过程,这样当接收方检测到标记时,就可以确定该标记表示数据包之间的边界。COBS将[0,255]范围内的任意字节串转换为[1,255]范围内的字节串。消除了数据中的所有零字节后,现在可以使用零字节明确地标记转换后数据的结束。这是通过向转换后的数据附加一个零字节来实现的,从而形成一个由cobs编码的数据(有效负载)组成的数据包,以明确地标记数据包的末尾。(可以保留任何其他字节值作为数据包分隔符,但使用零可以简化描述。)

在这里插入图片描述

COBS编码过程:

1.添加首个byte,这个byte指的是下一个0的位置,那么从上图可以看出,第三个位置是0,所以首个byte是03

2.而当数据中有0时,需要被改写,改写的值就是距离下一个0的距离,0距离最后一个00差2,所以改写为02

3.每一个数据包的最后都要加上00

3. Example

ExampleUnencoded data (hex)Encoded with COBS (hex)
10001 01 00
200 0001 01 01 00
300 11 0001 02 11 01 00
411 22 00 3303 11 22 02 33 00
511 22 33 4405 11 22 33 44 00
611 00 00 0002 11 01 01 01 00
701 02 03 … FD FEFF 01 02 03 … FD FE 00
800 01 02 … FC FD FE01 FF 01 02 … FC FD FE 00
901 02 03 … FD FE FFFF 01 02 03 … FD FE 02 FF 00
1002 03 04 … FE FF 00FF 02 03 04 … FE FF 01 01 00
1103 04 05 … FF 00 01FE 03 04 05 … FF 02 01 00

4. Python Code

由于工作需要需要支持cobs协议,所以上位机用python做了一个cobs的编解码器。借鉴了网上相关java的算法,采用的滑动窗口的方法,进行编解码。

Encode

def cobs_encoded(data_in):
    encode_list = [0]
    len_data = len(data_in)
    zero_pos = 0
    zero_adds = 1

    # 复制输入数据到encode_list
    encode_list.extend(data_in)
    encode_list.append(0)

    i = 1
    while i < len(encode_list):
        temp = encode_list[i]
        if temp == 0:
            encode_list[zero_pos] = zero_adds
            zero_pos += zero_adds
            zero_adds = 0
        zero_adds += 1
        if zero_adds >= 0xFF:
            encode_list[zero_pos] = 0xFF
            if i == len_data:
                break

            encode_list.insert(i + 1, 0)
            i += 1
            zero_pos += zero_adds
            zero_adds = 1
        i += 1

    return encode_list

Decode

def cobs_decode(data):
    # 将输入数据转换为列表
    encode_list = list(data)

    z_value = encode_list[0]
    z_index = 0

    i = 0
    while i < len(encode_list):
        temp = encode_list[i]
        if z_index == z_value:
            if z_value == 0xFF:
                temp = encode_list[i]  # 关键位置
                encode_list.pop(i)

                if i+1 <= len(encode_list) and encode_list[i+1] == 1:
                    encode_list[i] = 0
            else:
                encode_list[i] = 0

            z_index = 0
            z_value = temp
        z_index += 1
        i += 1

    # 移除第一位包头
    encode_list.pop(0)

    # 移除结尾的0(如果存在)
    if encode_list and encode_list[-1] == 0x00:
        encode_list.pop()

    return encode_list

Test Result

ExampleUnencoded data (hex)Encoded with COBS (hex)Encode ResultDecode Result
10001 01 00PassPass
200 0001 01 01 00PassPass
300 11 0001 02 11 01 00PassPass
411 22 00 3303 11 22 02 33 00PassPass
511 22 33 4405 11 22 33 44 00PassPass
611 00 00 0002 11 01 01 01 00PassPass
701 02 03 … FD FEFF 01 02 03 … FD FE 00PassPass
800 01 02 … FC FD FE01 FF 01 02 … FC FD FE 00PassPass
901 02 03 … FD FE FFFF 01 02 03 … FD FE 02 FF 00PassPass
1002 03 04 … FE FF 00FF 02 03 04 … FE FF 01 01 00PassPass
1103 04 05 … FF 00 01FE 03 04 05 … FF 02 01 00PassPass

github上附有对应的测试用例数据,可以看下,觉得有用可以帮忙star下~

reference

https://en.wikipedia.org/wiki/Consistent_Overhead_Byte_Stuffing wiki百科官方解释

  • 27
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值