├── Kconfig ├── SConscript ├── c++ ├── upacker.cpp └── upacker.h ├── c ├── upacker.c └── upacker.h ├── java ├── MsgCallback.java └── Upacker.java ├── lisense.txt ├── package.json ├── python └── upacker.py └── readme.md /Kconfig: -------------------------------------------------------------------------------- 1 | 2 | # Kconfig file for package UPACKER 3 | menuconfig PKG_USING_UPACKER 4 | bool "building and parsing data frames to be sent over a serial interface" 5 | default n 6 | 7 | 8 | if PKG_USING_UPARAM 9 | 10 | config PKG_UPARAM_PATH 11 | string 12 | default "/packages/misc/upacker" 13 | 14 | choice 15 | prompt "Version" 16 | default PKG_USING_UPACKER_LATEST_VERSION 17 | help 18 | Select the package version 19 | 20 | config PKG_USING_UPACKER_LATEST_VERSION 21 | bool "latest" 22 | endchoice 23 | 24 | config PKG_UPARAM_VER 25 | string 26 | default "latest" if PKG_USING_UPACKER_LATEST_VERSION 27 | 28 | endif 29 | 30 | -------------------------------------------------------------------------------- /SConscript: -------------------------------------------------------------------------------- 1 | from building import * 2 | 3 | cwd = GetCurrentDir() 4 | CPPPATH = [cwd, cwd + '/c', str(Dir('#'))] 5 | 6 | src = Glob('c/*.c') 7 | 8 | 9 | group = DefineGroup('upacker', src, depend = ['PKG_USING_UPACKER'], CPPPATH = CPPPATH) 10 | 11 | Return('group') 12 | 13 | -------------------------------------------------------------------------------- /c++/upacker.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | ****************************************************************************** 3 | * @file drv_packer.c 4 | * @author zpw 5 | * @version V1.0 6 | * @date 7 | * @brief 链路层通讯协议 8 | ****************************************************************************** 9 | * @attention 10 | * 链路层通讯协议,数据封包解包 11 | ****************************************************************************** 12 | */ 13 | #include "upacker.h" 14 | 15 | 16 | using namespace std; 17 | /** 18 | * @brief 使用动态内存时需要初始化 19 | * @note size pack缓存的长度,大于最大的数据包长度就行,使用PACK_SIZE 20 | 无rtos最好用静态内存,不然要改heap 21 | * @param *cmd_packer: 22 | * @param *handler: 23 | * @retval None 24 | */ 25 | int Upacker::upacker_init(PACKER_CB handler, PACKER_CB s) 26 | { 27 | #if USE_DYNAMIC_MEM 28 | packer->data = (uint8_t *)UP_MALLOC(MAX_PACK_SIZE); 29 | if (!packer->data) 30 | { 31 | return -1; 32 | } 33 | #endif 34 | 35 | cb = handler; 36 | send = s; 37 | return 0; 38 | } 39 | 40 | /** 41 | * @brief 封包数据并发送 42 | * @note 43 | * @param *packer: 44 | * @param *buff: 45 | * @param size: 46 | * @retval None 47 | */ 48 | void Upacker::upacker_pack(uint8_t *buff, uint16_t size) 49 | { 50 | frame_encode(buff, size); 51 | } 52 | 53 | /** 54 | * @brief 解包输入数据 55 | * @note 56 | * @param cmd_packer: 57 | * @param *buff: 58 | * @param size: 59 | * @retval None 60 | */ 61 | void Upacker::upacker_unpack(uint8_t *buff, uint16_t size) 62 | { 63 | for (uint16_t i = 0; i < size; i++) 64 | { 65 | if (frame_decode(buff[i])) 66 | { 67 | //解析成功,回调处理 68 | this->cb(this->data, this->flen); 69 | } 70 | } 71 | } 72 | 73 | uint8_t Upacker::frame_decode(uint8_t d) 74 | { 75 | if (this->state == 0 && d == STX_L) 76 | { 77 | this->state = 1; 78 | this->calc = 0x55; 79 | } 80 | else if (this->state == 1) 81 | { 82 | this->flen = d; 83 | this->calc ^= d; 84 | this->state = 2; 85 | } 86 | else if (this->state == 2) 87 | { 88 | //长度信息 89 | this->flen |= (uint16_t)d << 8; 90 | this->calc ^= d & 0x3F; 91 | 92 | //数据包超长得情况下直接丢包 93 | if ((this->flen & 0x3FFF) > MAX_PACK_SIZE) 94 | { 95 | this->state = 0; 96 | } 97 | this->state = 3; 98 | this->cnt = 0; 99 | } 100 | else if (this->state == 3) 101 | { 102 | //header校验 103 | uint8_t hc = ((d & 0x03) << 4) | ((this->flen & 0xC000) >> 12); 104 | 105 | this->check = d; 106 | if(hc != (this->calc & 0X3C)){ 107 | this->state = 0; 108 | return 0; 109 | } 110 | this->state = 4; 111 | this->flen &= 0x3FFF; 112 | } 113 | else if (this->state == 4) 114 | { 115 | this->data[this->cnt++] = d; 116 | this->calc ^= d; 117 | 118 | if (this->cnt == this->flen) 119 | { 120 | this->state = 0; 121 | 122 | //接收完,检查check 123 | if((this->calc & 0xFC) == (this->check & 0XFC)){ 124 | return 1; 125 | }else{ 126 | return 0; 127 | } 128 | } 129 | } 130 | else 131 | { 132 | this->state = 0; 133 | } 134 | return 0; 135 | } 136 | 137 | uint8_t Upacker::frame_encode(uint8_t *data, uint16_t size) 138 | { 139 | uint8_t tmp[4] = {0}; 140 | uint8_t crc = 0; 141 | 142 | if(size > 16384){ 143 | return 0; 144 | } 145 | 146 | tmp[0] = 0x55; 147 | tmp[1] = size & 0xff; 148 | tmp[2] = (size >> 8) & 0x3f; //低14位用来保存size;header校验4位 149 | crc = tmp[0] ^ tmp[1] ^ tmp[2]; 150 | tmp[2] |= (crc & 0x0C) << 4; //tmp[2][7:6]保存header检验[3:2] 151 | tmp[3] = 0x03 & (crc >> 4) ; //tmp[3][1:0]保存header校验[5:4] 152 | for (int i = 0; i < size; i++) 153 | { 154 | crc ^= data[i]; 155 | } 156 | 157 | tmp[3] |= (crc & 0xfc) ; //tmp[3][7:2]保存data check[7:2] 158 | this->send(tmp, 4); 159 | this->send(data, size); 160 | 161 | return 1; 162 | } 163 | -------------------------------------------------------------------------------- /c++/upacker.h: -------------------------------------------------------------------------------- 1 | #ifndef _DRV_PACKER_H_ 2 | #define _DRV_PACKER_H_ 3 | 4 | #include "stdint.h" 5 | #include 6 | 7 | using namespace std; 8 | 9 | #define USE_DYNAMIC_MEM 0 //使用动态内存 10 | 11 | #if USE_DYNAMIC_MEM 12 | #define UP_MALLOC 13 | #define UP_FREE 14 | #endif 15 | 16 | #define MAX_PACK_SIZE 16384 //最长消息长度,最大可用14位即16384 17 | #define STX_L 0X55 //数据包头 18 | 19 | typedef std::function PACKER_CB; 20 | 21 | 22 | class Upacker 23 | { 24 | 25 | 26 | public: 27 | #if !USE_DYNAMIC_MEM 28 | uint8_t data[MAX_PACK_SIZE]; //用来做payload序列化的内存 29 | #else 30 | uint8_t *data; //用来做payload序列化的内存 31 | #endif 32 | uint16_t flen; //frame长度 33 | uint8_t calc; //frame校验计算值 34 | uint8_t check; //frame校验值 35 | uint8_t state; //frame解析状态 36 | uint16_t cnt; //frame数据接收cnt 37 | 38 | PACKER_CB cb; //frame数据接收cnt 39 | PACKER_CB send; //数据发送回调 40 | 41 | 42 | int upacker_init(PACKER_CB handler, PACKER_CB s); 43 | void upacker_pack(uint8_t *buff, uint16_t size); 44 | void upacker_unpack(uint8_t *buff, uint16_t size); 45 | private: 46 | uint8_t frame_decode(uint8_t d); 47 | uint8_t frame_encode(uint8_t *data, uint16_t size); 48 | } ; 49 | 50 | 51 | 52 | 53 | 54 | #endif 55 | -------------------------------------------------------------------------------- /c/upacker.c: -------------------------------------------------------------------------------- 1 | /** 2 | ****************************************************************************** 3 | * @file drv_packer.c 4 | * @author zpw 5 | * @version V1.0 6 | * @date 7 | * @brief 链路层通讯协议 8 | ****************************************************************************** 9 | * @attention 10 | * 链路层通讯协议,数据封包解包 11 | ****************************************************************************** 12 | */ 13 | #include "upacker.h" 14 | 15 | static uint8_t frame_decode(upacker_inst_t packer, uint8_t d); 16 | static uint8_t frame_encode(upacker_inst_t packer, uint8_t *data, uint16_t size); 17 | 18 | /** 19 | * @brief 使用动态内存时需要初始化 20 | * @note size pack缓存的长度,大于最大的数据包长度就行,使用PACK_SIZE 21 | 无rtos最好用静态内存,不然要改heap 22 | * @param *cmd_packer: 23 | * @param *handler: 24 | * @retval None 25 | */ 26 | int upacker_init(upacker_inst_t packer, PACKER_CB h, PACKER_CB s) 27 | { 28 | 29 | #if USE_DYNAMIC_MEM 30 | packer->data = (uint8_t *)UP_MALLOC(MAX_PACK_SIZE); 31 | if (!packer->data) 32 | { 33 | return -1; 34 | } 35 | #endif 36 | 37 | packer->cb = h; 38 | packer->send = s; 39 | return 0; 40 | } 41 | 42 | /** 43 | * @brief 解包输入数据 44 | * @note 45 | * @param cmd_packer: 46 | * @param *buff: 47 | * @param size: 48 | * @retval None 49 | */ 50 | void upacker_unpack(upacker_inst_t packer, uint8_t *buff, uint16_t size) 51 | { 52 | for (uint16_t i = 0; i < size; i++) 53 | { 54 | if (frame_decode(packer, buff[i])) 55 | { 56 | //解析成功,回调处理 57 | packer->cb(packer->data, packer->flen); 58 | } 59 | } 60 | } 61 | 62 | /** 63 | * @brief 封包数据并发送 64 | * @note 65 | * @param *packer: 66 | * @param *buff: 67 | * @param size: 68 | * @retval None 69 | */ 70 | void upacker_pack(upacker_inst_t packer, uint8_t *buff, uint16_t size) 71 | { 72 | frame_encode(packer, buff, size); 73 | } 74 | 75 | static uint8_t frame_decode(upacker_inst_t packer, uint8_t d) 76 | { 77 | 78 | if (packer->state == 0 && d == STX_L) 79 | { 80 | packer->state = 1; 81 | packer->calc = 0x55; 82 | } 83 | else if (packer->state == 1) 84 | { 85 | packer->flen = d; 86 | packer->calc ^= d; 87 | packer->state = 2; 88 | } 89 | else if (packer->state == 2) 90 | { 91 | //长度信息 92 | packer->flen |= (uint16_t)d << 8; 93 | packer->calc ^= d & 0x3F; 94 | 95 | //数据包超长得情况下直接丢包 96 | if ((packer->flen & 0x3FFF) > MAX_PACK_SIZE) 97 | { 98 | packer->state = 0; 99 | } 100 | packer->state = 3; 101 | packer->cnt = 0; 102 | } 103 | else if (packer->state == 3) 104 | { 105 | //header校验 106 | uint8_t hc = ((d & 0x03) << 4) | (packer->flen & 0xC000) >> 12; 107 | 108 | packer->check = d; 109 | if (hc != (packer->calc & 0X3C)) 110 | { 111 | packer->state = 0; 112 | return 0; 113 | } 114 | packer->state = 4; 115 | packer->flen &= 0x3FFF; 116 | } 117 | else if (packer->state == 4) 118 | { 119 | packer->data[packer->cnt++] = d; 120 | packer->calc ^= d; 121 | 122 | if (packer->cnt == packer->flen) 123 | { 124 | packer->state = 0; 125 | 126 | //接收完,检查check 127 | if ((packer->calc & 0xFC) == (packer->check & 0XFC)) 128 | { 129 | return 1; 130 | } 131 | else 132 | { 133 | return 0; 134 | } 135 | } 136 | } 137 | else 138 | { 139 | packer->state = 0; 140 | } 141 | return 0; 142 | } 143 | 144 | static uint8_t frame_encode(upacker_inst_t packer, uint8_t *data, uint16_t size) 145 | { 146 | 147 | uint8_t tmp[4] = {0}; 148 | uint8_t crc = 0; 149 | 150 | if (size > 16384) 151 | { 152 | return 0; 153 | } 154 | 155 | tmp[0] = 0x55; 156 | tmp[1] = size & 0xff; 157 | tmp[2] = (size >> 8) & 0x3f; //低14位用来保存size;header校验4位 158 | crc = tmp[0] ^ tmp[1] ^ tmp[2]; 159 | tmp[2] |= (crc & 0x0C) << 4; //tmp[2][7:6]保存header检验[3:2] 160 | tmp[3] = 0x03 & (crc >> 4); //tmp[3][1:0]保存header校验[5:4] 161 | for (int i = 0; i < size; i++) 162 | { 163 | crc ^= data[i]; 164 | } 165 | 166 | tmp[3] |= (crc & 0xfc); //tmp[3][7:2]保存data check[7:2] 167 | packer->send(tmp, 4); 168 | packer->send(data, size); 169 | 170 | return 1; 171 | } 172 | -------------------------------------------------------------------------------- /c/upacker.h: -------------------------------------------------------------------------------- 1 | #ifndef _DRV_PACKER_H_ 2 | #define _DRV_PACKER_H_ 3 | 4 | #include "stdint.h" 5 | 6 | #ifdef __cplusplus 7 | extern "C" 8 | { 9 | #endif 10 | 11 | //使用动态内存 12 | #define USE_DYNAMIC_MEM 0 13 | 14 | #if USE_DYNAMIC_MEM 15 | #define UP_MALLOC 16 | #define UP_FREE 17 | #endif 18 | 19 | #define MAX_PACK_SIZE 1024 //最长消息长度,最大可用14位即16384 20 | #define STX_L 0X55 //数据包头 21 | 22 | typedef void (*PACKER_CB)(uint8_t *d, uint16_t s); 23 | 24 | typedef struct 25 | { 26 | 27 | #if !USE_DYNAMIC_MEM 28 | uint8_t data[MAX_PACK_SIZE]; //payload的内存 29 | #else 30 | uint8_t *data; //用来做payload序列化的内存 31 | #endif 32 | uint16_t flen; //frame长度 33 | uint8_t calc; //frame校验计算值 34 | uint8_t check; //frame校验值 35 | uint8_t state; //frame解析状态 36 | uint16_t cnt; //frame数据接收cnt 37 | 38 | PACKER_CB cb; //数据包处理回调 39 | PACKER_CB send; //数据发送回调 40 | 41 | } upacker_inst; 42 | 43 | typedef upacker_inst *upacker_inst_t; 44 | 45 | int upacker_init(upacker_inst_t packer, PACKER_CB handle, PACKER_CB send); 46 | void upacker_pack(upacker_inst_t packer, uint8_t *buff, uint16_t size); 47 | void upacker_unpack(upacker_inst_t packer, uint8_t *buff, uint16_t size); 48 | 49 | #ifdef __cplusplus 50 | } 51 | #endif 52 | #endif 53 | -------------------------------------------------------------------------------- /java/MsgCallback.java: -------------------------------------------------------------------------------- 1 | package ltd.zlink.ae_tracer.msg; 2 | 3 | public interface MsgCallback { 4 | void onMsgPrased(byte[] data, int len); 5 | 6 | void onMsgFailed(); 7 | } 8 | -------------------------------------------------------------------------------- /java/Upacker.java: -------------------------------------------------------------------------------- 1 | package ltd.zlink.ae_tracer.msg; 2 | 3 | public class Upacker { 4 | 5 | // 最长消息长度 6 | private final int MAX_PACK_SIZE = 5012; 7 | private final byte STX_L = 0X55; 8 | 9 | private final int RET_FAILED = -1; 10 | private final int RET_SUCCESS = 0; 11 | private final int RET_PROCESS = 1; 12 | 13 | //cmd数据 14 | private byte[] data; 15 | 16 | // cmd长度 17 | private int flen; 18 | 19 | // cmd 校验 20 | private int check; 21 | 22 | // cmd 校验计算值 23 | private int calc; 24 | 25 | // cmd 解析状态 26 | private int state; 27 | 28 | // cmd数据接收cnt 29 | private int cnt; 30 | 31 | private MsgCallback msgCallback; 32 | 33 | Upacker(final MsgCallback cb) { 34 | msgCallback = cb; 35 | } 36 | 37 | 38 | /** 39 | * 解析封包 40 | * 41 | * @param buff 42 | */ 43 | public void unpack(byte[] buff) { 44 | int ret = 0; 45 | for (byte i : buff) { 46 | ret = frameDecode(i); 47 | if (ret == RET_SUCCESS) { 48 | msgCallback.onMsgPrased(data, flen); 49 | } else if (ret == RET_FAILED) { 50 | msgCallback.onMsgFailed(); 51 | } 52 | } 53 | } 54 | 55 | private int frameDecode(byte d) { 56 | 57 | if (state == 0 && d == STX_L) { 58 | state = 1; 59 | calc = STX_L; 60 | } else if (state == 1) { 61 | flen = d & 0xff; 62 | calc ^= d & 0xff; 63 | state = 2; 64 | } else if (state == 2) { 65 | flen |= (d & 0xff) << 8; 66 | calc ^= d & 0x3F; 67 | // 数据包超长得情况下直接丢包 68 | if ((flen & 0x3FFF) > MAX_PACK_SIZE) { 69 | state = 0; 70 | 71 | return RET_FAILED; 72 | } else { 73 | data = new byte[flen & 0x3FFF]; 74 | 75 | } 76 | state = 3; 77 | cnt = 0; 78 | } else if (state == 3) { 79 | int header_crc = ((d & 0x03) << 4) | ((flen & 0xC000) >> 12); 80 | check = d; 81 | if (header_crc != (calc & 0X3C)) { 82 | state = 0; 83 | 84 | return RET_FAILED; 85 | } 86 | state = 4; 87 | flen &= 0x3FFF; 88 | } else if (state == 4) { 89 | data[cnt++] = d; 90 | calc ^= d; 91 | if (cnt == flen) { 92 | state = 0; 93 | //接收完,检查check 94 | if ((calc & 0xFC) == (check & 0XFC)) { 95 | 96 | return RET_SUCCESS; 97 | } else { 98 | return RET_FAILED; 99 | } 100 | } 101 | } else { 102 | state = 0; 103 | } 104 | return RET_PROCESS; 105 | } 106 | 107 | /** 108 | * 打包数据,静态方法 109 | * 110 | * @param data 111 | * @return 112 | */ 113 | public static byte[] frameEncode(byte[] data) { 114 | 115 | byte tmp[] = new byte[4 + data.length]; 116 | int crc = 0; 117 | tmp[0] = 0x55; 118 | tmp[1] = (byte) (data.length & 0xff); 119 | tmp[2] = (byte) ((data.length >> 8) & 0xff); 120 | crc = tmp[0] ^ tmp[1] ^ tmp[2]; 121 | tmp[2] |= (byte) ((crc & 0x0C) << 4); 122 | tmp[3] = (byte) (0x03 & (crc >> 4)); 123 | 124 | for (int i = 0; i < data.length; i++) { 125 | crc ^= data[i]; 126 | } 127 | tmp[3] |= (crc & 0xfc); 128 | System.arraycopy(data, 0, tmp, 4, data.length); 129 | 130 | return tmp; 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /lisense.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 aeo123 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "UPACKER", 3 | "description": "building and parsing data frames to be sent over a serial interface", 4 | "description_zh": "串行通信链路协议", 5 | "keywords": [ 6 | "LedBlink" 7 | ], 8 | "category": "peripherals", 9 | "author": { 10 | "name": "zpw", 11 | "email": "aeo1234@qq.com" 12 | }, 13 | "license": "GPL-2.0", 14 | "repository": "https://github.com/aeo123/upacker.git", 15 | "icon": "unknown", 16 | "homepage": "https://github.com/aeo123/upacker.git", 17 | "doc": "https://github.com/aeo123/upacker.git", 18 | "site": [ 19 | { 20 | "version": "latest", 21 | "URL": "https://github.com/aeo123/upacker.git", 22 | "filename": "Null for git package", 23 | "VER_SHA": "master" 24 | } 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /python/upacker.py: -------------------------------------------------------------------------------- 1 | import struct 2 | 3 | 4 | class Upacker(): 5 | def __init__(self): 6 | self._STX_L = 0x55 7 | self._MAX_PACK_SIZE = 1024 + 4 + 128 8 | self._calc = 0 9 | self._check = 0 10 | self._cnt = 0 11 | self._flen = 0 12 | self._state = 0 13 | self._data = bytearray() 14 | 15 | def _decode(self, d): 16 | if (self._state == 0 and d == self._STX_L): 17 | self._state = 1 18 | self._calc = self._STX_L 19 | elif self._state == 1: 20 | self._flen = d & 0xff 21 | self._calc ^= d & 0xff 22 | self._state = 2 23 | elif self._state == 2: 24 | self._flen |= (d & 0xff) << 8 25 | self._calc ^= d & 0x3F 26 | # 数据包超长得情况下直接丢包 27 | if ((self._flen & 0x3FFF) > self._MAX_PACK_SIZE): 28 | self._state = 0 29 | return -1 30 | else: 31 | self._data = bytearray(self._flen & 0x3FFF) 32 | self._state = 3 33 | self._cnt = 0 34 | elif self._state == 3: 35 | header_crc = ((d & 0x03) << 4) | ((self._flen & 0xC000) >> 12) 36 | self._check = d 37 | if (header_crc != (self._calc & 0X3C)): 38 | self._state = 0 39 | return -1 40 | self._state = 4 41 | self._flen &= 0x3FFF 42 | elif self._state == 4: 43 | self._data[self._cnt] = d 44 | self._cnt += 1 45 | self._calc ^= d 46 | if self._cnt == self._flen: 47 | self._state = 0 48 | #接收完,检查check 49 | if ((self._calc & 0xFC) == (self._check & 0XFC)): 50 | return 0 51 | else: 52 | return -1 53 | else: 54 | self._state = 0 55 | 56 | return 1 57 | 58 | # 解包 59 | def unpack(self, bytes_data, callback): 60 | ret = 0 61 | for i in bytes_data: 62 | ret = self._decode(i) 63 | if ret == 0: 64 | callback(self._data) 65 | # print(self._data) 66 | elif ret == -1: 67 | # callback(None) 68 | print("err") 69 | 70 | # 打包 71 | def enpack(self, data): 72 | tmp = bytearray(4) 73 | tmp[0] = 0x55 74 | tmp[1] = len(data) & 0xff 75 | tmp[2] = (len(data) >> 8) & 0xff 76 | crc = tmp[0] ^ tmp[1] ^ tmp[2] 77 | tmp[2] |= (crc & 0x0c) << 4 78 | tmp[3] = 0x03 & (crc >> 4) 79 | 80 | for i in range(len(data)): 81 | crc ^= data[i] 82 | tmp[3] |= (crc & 0xfc) 83 | 84 | frame = struct.pack("BBBB%ds" % len(data), tmp[0], tmp[1], tmp[2], 85 | tmp[3], data) 86 | print(frame.hex()) 87 | return frame 88 | 89 | 90 | def print_hex(bytes): 91 | hex_byte = [hex(i) for i in bytes] 92 | print(" ".join(hex_byte)) 93 | 94 | 95 | if __name__ == '__main__': 96 | buf = bytearray([0x00, 0x01, 0x02,0x03]) 97 | pack = Upacker() 98 | pkt = pack.enpack(buf) 99 | pack.unpack(pkt, print_hex) 100 | 101 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | 2 | # Upacker 3 | 用于段对端通讯数据封包、解包,解决各种粘包、分包问题。极简内存占用。 4 | 5 | 软件包位置: /packages/misc/upacker 6 | 7 | ## 数据帧格式 8 | 9 | --- 10 | 每包数据负载长度最长位14位16384字节。 11 | 每帧数据含4字节Header和N字节负载,包含14位数据长度,4位Header校验,6位负载校验 12 | 13 | ``` C 14 | Header 4BYTE Load 15 | ---------------------------------------------------------------------- 16 | D0[7:0] |D1[7:0] |D2[5:0] |D2[7:6] |D3[1:0] |D3[7:2] 17 | ---------------------------------------------------------------------- 18 | 包头 |包长(低8) |包长(高6) |Header校验[3:2] |Header校验[5:4] |check[7:2] |data 19 | ---------------------------------------------------------------------- 20 | 0x55 |0XFF |0X3F |0X0C |0X30 |0XFC |XXXXX 21 | ``` 22 | 23 | ### 使用 24 | 25 | #### 配置 26 | 27 | packer内部需要一段内存用于保存解析完成的包,可以配置为静态内存或者动态内存。 28 | 内存分配的长度为MAX_PACK_SIZE,根据应用需要自行调节 29 | ```C 30 | #define USE_DYNAMIC_MEM 0 31 | #define MAX_PACK_SIZE 1024 //最长消息长度,最大可用14位即16384 32 | ``` 33 | 完整的packer结构体 34 | ```C 35 | //使用动态内存 36 | #define USE_DYNAMIC_MEM 0 37 | 38 | #if USE_DYNAMIC_MEM 39 | #define UP_MALLOC 40 | #define UP_FREE 41 | #endif 42 | 43 | #define MAX_PACK_SIZE 1024 //最长消息长度,最大可用14位即16384 44 | #define STX_L 0X55 //数据包头 45 | 46 | typedef void (*PACKER_CB)(uint8_t *d, uint16_t s); 47 | 48 | typedef struct 49 | { 50 | #if !USE_DYNAMIC_MEM 51 | uint8_t data[MAX_PACK_SIZE]; //payload的内存 52 | #else 53 | uint8_t *data; //用来做payload序列化的内存 54 | #endif 55 | uint16_t flen; //frame长度 56 | uint8_t calc; //frame校验计算值 57 | uint8_t check; //frame校验值 58 | uint8_t state; //frame解析状态 59 | uint16_t cnt; //frame数据接收cnt 60 | 61 | PACKER_CB cb; //数据包处理回调 62 | PACKER_CB send; //数据发送回调 63 | } upacker_inst; 64 | ``` 65 | 66 | 实例一个packer 67 | 68 | ``` C 69 | #include "upacker.h" 70 | upacker_inst msg_packer; 71 | ``` 72 | 73 | #### 初始化,需要用户自行实现两个函数 74 | 75 | ``` C 76 | void data_send(uint8_t *d, uint16_t size); //发送数据 77 | void handle_callback(uint8_t *d, uint16_t size); //解包成功后的处理回调 78 | ``` 79 | 80 | ``` C 81 | /** 82 | * @brief 串口dma发送接口 83 | * @note 84 | * @param *d: 85 | * @param size: 86 | * @retval None 87 | */ 88 | static void uart_send(uint8_t *d, uint16_t size) 89 | { 90 | dbuff_push(&uart3_dbuff, d, size); 91 | } 92 | 93 | 94 | /** 95 | * @brief 消息解析回调 96 | * @note 97 | * @param *d: 98 | * @param size: 99 | * @retval None 100 | */ 101 | static void handle_cb(uint8_t *d, uint16_t size) 102 | { 103 | //接收到payload 104 | rt_kprintf("pack len%d", size); 105 | } 106 | 107 | 108 | //init packer 109 | upacker_init(&msg_packer, handle_cb, uart_send); 110 | ``` 111 | 112 | #### 解析数据 113 | 114 | ```C 115 | //使用串口dma接收数据的示例 116 | static void thread_entry(void *parameter) 117 | { 118 | struct rx_msg msg; 119 | rt_err_t result; 120 | rt_uint32_t rx_length; 121 | static char rx_buffer[UART_QUE_LEN + 1]; 122 | 123 | while (1) 124 | { 125 | rt_memset(&msg, 0, sizeof(msg)); 126 | /* 从消息队列中读取消息*/ 127 | result = rt_mq_recv(&rx_mq, &msg, sizeof(msg), 10); 128 | if (result == RT_EOK) 129 | { 130 | /* 从串口读取数据*/ 131 | rx_length = rt_device_read(msg.dev, 0, rx_buffer, msg.size); 132 | //丢到packer解析,成功了调用callback 133 | upacker_unpack(&msg_packer, (uint8_t *)rx_buffer, msg.size); 134 | } 135 | } 136 | } 137 | 138 | ``` 139 | 140 | #### 封包数据 141 | 142 | ```C 143 | buff[0] = 0x40; 144 | buff[1] = 0x40; 145 | upacker_pack(&msg_packer, (uint8_t *)buff, 2); 146 | ``` 147 | 148 | ## 应用建议 149 | --- 150 | 最简单的协议示例,一个字节用来设置指令类型,后面接数据。 151 | 152 | ```C 153 | #define CMD1_CODE 0X40 154 | #define CMD2_CODE 0X41 155 | 156 | static void handle_cb(uint8_t *d, uint16_t size) 157 | { 158 | //接收到payload 159 | rt_kprintf("pack len%d", size); 160 | 161 | if(d[0] == CMD1_CODE){ 162 | //处理功能1的数据 163 | rt_kprintf("cmd1 data: %d", d[1]); 164 | }else if(d[0] == CMD2_CODE){ 165 | //处理功能2的数据 166 | rt_kprintf("cmd2 data: %d", d[1]); 167 | } 168 | } 169 | 170 | //发送cmd1数据 171 | void send_cmd1(){ 172 | buff[0] = 0x40; 173 | buff[1] = 55; 174 | upacker_pack(&msg_packer, (uint8_t *)buff, 2); 175 | } 176 | ``` 177 | --- 178 | 使用json序列化数据,把json用来pack传输,收到一帧直接反序列化 179 | 180 | --- 181 | 使用msgpack序列化数据,和json类似 182 | 183 | --- 184 | 使用protobuf序列化数据,类似 185 | 186 | ### 代码从项目工程复制出来的,有运行问题请提issue 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | --------------------------------------------------------------------------------