/** * @file Protocol_Lib.c * @brief 串口协议解析 * @details 串口协议解析 * @author myliu * @date 2022.05.09 * @version V1.0 * @copyright myiu */ #include <stdio.h> #include <string.h> #include "Protocol_CRC16.h" #include "gatts_table_creat_demo.h" static UARTOpen UARTOpen_Cbk; static UARTSend UARTSend_Cbk; static UARTRead UARTRead_Cbk; static ProcParse ProcParseCbk; static UARTClose UARTClose_Cbk; static ProtocolSetData ProtocolSetData_Cbk; static Protocol_uint8_t *mDataBufPtr = Protocol_NULL; static Protocol_uint16_t mDataBufLen = 0; static Protocol_uint32_t DataBufMaxLen = 0; BAT32A239_ACK_Structure BAT32A239_ACK; //#define DEBUG_PRO_DATA 0 /** * @brief 初始化函数 * @param[in] pMemSpace 分配给协议库的内存空间,用来缓存串口数据 * @param[in] MemLen 分配的内存空间大小 * @param[in] pFunc 回调函数,包括串口打开、发送、读取、关闭,也包括解析后数据回传 * @param[in] ProcParseCbk 此回调函数,返回数据从FrameNo开始到CRC16之前,和ProtocolSetData_Cbk二选一 * @param[in] ProtocolSetData_Cbk 此回调函数,返回数据区分命令字、电源状态等,和ProcParseCbk二选一,详见结构体Protocol_Data_t * * @warning 此函数KL30和Wakeup都要调用,否则未分配内存,功能不好使,也有可能造成野指针复位 * * @since 1.0.0 */ void Protocol_Init(Protocol_uint8_t *pMemSpace, Protocol_uint32_t MemLen, Protocol_Func_t *pFunc) { mDataBufPtr = pMemSpace; DataBufMaxLen = MemLen; UARTOpen_Cbk = pFunc->UARTOpen_Cbk; UARTSend_Cbk = pFunc->UARTSend_Cbk; UARTRead_Cbk = pFunc->UARTRead_Cbk; ProcParseCbk = pFunc->ProcParseCbk; UARTClose_Cbk = pFunc->UARTClose_Cbk; ProtocolSetData_Cbk = pFunc->ProtocolSetData_Cbk; if ( UARTOpen_Cbk != Protocol_NULL ) { UARTOpen_Cbk( ); } return; } extern Protocol_uint32_t UpdateBAT32A239Protocol_Parse(const Protocol_uint8_t *pData, Protocol_uint32_t len); extern uint32_t SwitchMode; /** * @brief 串口协议服务函数,包括读取数据,解析数据,如在外部读取数据,可不调用此函数 * * @warning 此函数可自定义周期调用,建议20ms周期调用,最大不可超过协议的最小发送周期 * * @since 1.0.0 */ void Protocol_Service(void) { int len; Protocol_uint32_t readNum = 0; if ( UARTRead_Cbk != Protocol_NULL ) { readNum = UARTRead_Cbk(mDataBufPtr + mDataBufLen, 256 - mDataBufLen); if ( readNum > 0 ) { mDataBufLen += readNum; // 解析协议 if(SwitchMode==0)//处理升级协议 { len = Protocol_Parse(mDataBufPtr, mDataBufLen); } else//处理应用协议 { len = UpdateBAT32A239Protocol_Parse(mDataBufPtr, mDataBufLen); } if ( (len > 0) && (len < mDataBufLen) ) { // 将未解析的数据移到头部 // Move unparsed data to the head memcpy(mDataBufPtr, mDataBufPtr + len, mDataBufLen - len); } mDataBufLen -= len; } } } /** * @brief 协议解析函数,如外部获取数据(例如中断),可直接调用此函数解析数据 * @param[in] pData 协议数据内容 * @param[in] len 需要处理的协议数据长度 * * @return 剩余已处理的数据长度 * * @since 1.0.0 */ Protocol_uint32_t Protocol_Parse(const Protocol_uint8_t *pData, Protocol_uint32_t len) { Protocol_uint32_t remainLen = len; // 剩余数据长度 Remaining data length Protocol_uint32_t dataLen; // 数据包长度 Packet length Protocol_uint32_t frameLen; // 帧长度 Frame length Protocol_uint32_t frameSum; Protocol_Data_t ProcData; int i = 0; int dataBuf [ 256 ]; /** * 以下部分需要根据协议格式进行相应的修改,解析出每一帧的数据 */ while ( remainLen >= DATA_PACKAGE_MIN_LEN ) { // 找到一帧数据的数据头 // Find the data header of a frame of data while ( (remainLen >= 2) && ((pData [ 0 ] != CMD_HEAD1) || (pData [ 1 ] != CMD_HEAD2)) ) { pData++; remainLen--; continue; } if ( remainLen < DATA_PACKAGE_MIN_LEN ) { #ifdef DEBUG_PRO_DATA d_printf("too short!!!!!!\n"); #endif break; } dataLen = pData [ 2 ]; frameLen = dataLen + DATA_PACKAGE_FIXED_LEN; if ( frameLen > remainLen ) { // 数据内容不全 #ifdef DEBUG_PRO_DATA d_printf("Incomplete data packet!!!!!!\n"); #endif break; } // 打印一帧数据,需要时在CommDef.h文件中打开DEBUG_PRO_DATA宏 #ifdef DEBUG_PRO_DATA for ( i = 0; i < frameLen; ++i ) { d_printf("%x ", pData [ i ]); } d_printf("\n"); #endif // 检测校验码 Checksum frameSum = (pData [ frameLen - 2 ] << 8) | (pData [ frameLen - 1 ]); if ( frameLen > 4 ) { if ( getCheckSum(pData + 2, frameLen - 4) == frameSum ) { // 解析一帧数据 if ( ProcParseCbk != Protocol_NULL ) { ProcParseCbk(pData + 3, dataLen - 2); } if ( ProtocolSetData_Cbk != Protocol_NULL ) { ProcData.FrameNo = pData [ 3 ]; ProcData.PowerSts = (pData [ 4 ] >> 6) & 0x03; ProcData.CmdID = pData [ 4 ] & 0x3F; if ( ProcData.CmdID == 0x10 ) { #ifdef DEBUG_PRO_DATA for ( i = 0; i < frameLen; ++i ) { d_printf("%x ", pData [ i ]); } d_printf("\n"); #endif } if ( ProcData.CmdID == 0x12 ) { #ifdef DEBUG_PRO_DATA for ( i = 0; i < frameLen; ++i ) { d_printf("%x ", pData [ i ]); } d_printf("\n"); #endif } ProcData.DataLen = dataLen - 4; memcpy(ProcData.Data, pData + 5, ProcData.DataLen); ProtocolSetData_Cbk(&ProcData); } } else { for ( i = 0; i < frameLen; ++i ) { dataBuf [ i ] = pData [ i ]; } i = 0; #ifdef DEBUG_PRO_DATA d_printf("CheckSum error: new = %x, old = %x!!!!!!\n", getCheckSum(pData + 2, frameLen - 4), frameSum); #endif } } pData += frameLen; remainLen -= frameLen; } return len - remainLen; } /** * 根据协议格式进行拼接 */ /** * @brief 串口协议数据拼接,如初始化发送函数,调用此函数后,数据已通过串口发送 * @param[in] cmdID 命令字 * @param[in] pData 协议数据内容(不包括协议头、长度、帧序号、命令字、校验和,从数据域算起) * @param[in] len 数据域长度 * * @return 已发送的数据长度 * * @since 1.0.0 */ Protocol_uint32_t Protocol_Send(const Protocol_uint16_t cmdID, const Protocol_uint8_t *pData, Protocol_uint8_t len) { int i = 0; Protocol_uint16_t checksum = 0; Protocol_uint8_t dataBuf [ 256 ]; Protocol_uint32_t frameLen; if ( len + DATA_PACKAGE_MIN_LEN > 256 ) { // printf("sendProtocol data is too len !!!\n"); return 0; } dataBuf [ 0 ] = CMD_HEAD1; dataBuf [ 1 ] = CMD_HEAD2; // 同步帧头 Sync frame header dataBuf [ 2 ] = len + 4; dataBuf [ 3 ] = 0; // 命令字节 Command byte dataBuf [ 4 ] = ( Protocol_uint8_t )cmdID; frameLen = 5; // 数据 Data for ( i = 0; i < len; ++i ) { dataBuf [ frameLen ] = pData [ i ]; frameLen++; } // 校验码 Checksum checksum = getCheckSum(dataBuf + 2, frameLen - 2); dataBuf [ frameLen ] = (checksum >> 8) & 0x00FF; frameLen++; dataBuf [ frameLen ] = checksum & 0x00FF; frameLen++; if ( UARTSend_Cbk != Protocol_NULL ) { return UARTSend_Cbk(dataBuf, frameLen); } else { return 0; } } Protocol_uint32_t CalcCrc32(Protocol_uint8_t buf[], int Len); /** * 根据协议格式进行拼接 */ /** * @brief 串口协议数据拼接,如初始化发送函数,调用此函数后,数据已通过串口发送 * @param[in] cmdID 命令字 * @param[in] pData 协议数据内容(不包括协议头、长度、帧序号、命令字、校验和,从数据域算起) * @param[in] len 数据域长度 * * @return 已发送的数据长度 * * @since 1.0.0 */ Protocol_uint32_t UpdateBAT32A239Protocol_Send(UpdateProtocolStructure SendPd) { int i = 0; Protocol_uint16_t checksum = 0; Protocol_uint8_t dataBuf [ 256 ]; Protocol_uint16_t checksumXor = 0; Protocol_uint32_t frameLen = 0; Protocol_uint32_t DAT_CRC; if ( SendPd.LEN > 256 ) { // printf("sendProtocol data is too len !!!\n"); return 0; } frameLen = SendPd.LEN + 7; dataBuf [ 0 ] = 0xAA; dataBuf [ 1 ] = 0x55; // 同步帧头 Sync frame header dataBuf [ 2 ] = SendPd.CMDH; //CMDH dataBuf [ 3 ] = SendPd.CMDL; // CMDL dataBuf [ 4 ] = frameLen; dataBuf [ 5 ] = frameLen >> 8; // 命令字节 Command byte if(SendPd.CMDH == CMD_FLASH_DWNLD) { if(SendPd.LEN > 4) { memcpy(&dataBuf[6],&SendPd.DAT[0],SendPd.LEN - 4); DAT_CRC=CalcCrc32(&SendPd.DAT[0], SendPd.LEN - 4 );//计算Address + Data的CRC 32 dataBuf[frameLen-5]=(Protocol_uint8_t)(DAT_CRC); dataBuf[frameLen-4]=(Protocol_uint8_t)(DAT_CRC>>8); dataBuf[frameLen-3]=(Protocol_uint8_t)(DAT_CRC>>16); dataBuf[frameLen-2]=(Protocol_uint8_t)(DAT_CRC>>24); } } if(SendPd.CMDH == CMD_FLASH_ERASE) { memcpy(&dataBuf[6],&SendPd.DAT[0],SendPd.LEN); } for(i = 0 ;i < (frameLen - 1); i++) { checksumXor^=dataBuf[i]; } dataBuf[frameLen - 1]=(Protocol_uint8_t)checksumXor; //printf("dataBuf[frameLen - 1] = %2x\n", dataBuf[frameLen - 1]); //printf("frameLen = %d\n", frameLen); if ( UARTSend_Cbk != Protocol_NULL ) { return UARTSend_Cbk(dataBuf, frameLen); } else { return 0; } }