本帖最后由 mftang2016 于 2017-4-16 09:51 编辑
本文介绍一种通信协议的实现原理和方法,其可支持单点、多点通信。可用于串口、usb、网口、485等多种通信介质。下面介绍其实现方法和原理:
固件实现:
1. 数据解析文件
[mw_shl_code=c,true]/*******************************************************************************
** File name: ZCS_Parser.c
** Created by: Mingfei Tang
** Created date: 2016/2/18
** Version: V1.00
** Descriptions: for zcs protocol parsered
** Details:
**------------------------------------------------------------------------------
** Modified by:
** Modified date:
** Version:
** Descriptions:
**
*******************************************************************************/
#include "includes.h"
void ZCS_ParserReset(ZCS* pst_zcs )
{
pst_zcs->StateStep = _ZCS_HEAD_H;
pst_zcs->DataLen = 0;
pst_zcs->HostPckLength = 0;
pst_zcs->PackeParseLen.LenIndex = 0;
pst_zcs->ParseLength = 512;
memset( pst_zcs->DataBuf, 0, sizeof(pst_zcs->DataBuf));
memset( pst_zcs->RecvDataBuf, 0, sizeof(pst_zcs->RecvDataBuf));
memset( pst_zcs->HostSendBuf, 0, sizeof(pst_zcs->HostSendBuf));
pst_zcs->PackeParseLen.PF_UID = 6;
}
/* Header H -0 */
static void ZCS_Check_HEADH( ZCS* pst_zcs )
{
INT8U u8_input = pst_zcs->InByte;
if( u8_input == HEAD )
{
pst_zcs->Head = u8_input;
pst_zcs->Head <<= 8;
pst_zcs->Head &= 0xFF00;
pst_zcs->StateStep = _ZCS_HEAD_L;
}
else
{
ZCS_ParserReset( pst_zcs );
}
}
/* Header L -1 */
static void ZCS_Check_HEADL( ZCS* pst_zcs )
{
INT8U u8_input = pst_zcs->InByte;
if( u8_input == HEAD )
{
pst_zcs->Head += u8_input;
pst_zcs->StateStep = _ZCS_FNUM_H;
}
else
{
ZCS_ParserReset( pst_zcs );
}
}
/* FNUM H -2 */
static void ZCS_Check_FNUMH( ZCS* pst_zcs )
{
INT8U u8_input = pst_zcs->InByte;
pst_zcs->FNUM = u8_input;
pst_zcs->FNUM <<= 8;
pst_zcs->FNUM &= 0xFF00;
pst_zcs->StateStep = _ZCS_FNUM_L;
}
/* FNUM L -3 */
static void ZCS_Check_FNUML( ZCS* pst_zcs )
{
INT8U u8_input = pst_zcs->InByte;
pst_zcs->FNUM += u8_input;
pst_zcs->StateStep = _ZCS_UID;
pst_zcs->PackeParseLen.LenIndex = 0;
}
/* UID -4 */
static void ZCS_Check_UID( ZCS* pst_zcs )
{
INT8U inByte = pst_zcs->InByte;
pst_zcs->UID[pst_zcs->PackeParseLen.LenIndex++] = inByte;
if( pst_zcs->PackeParseLen.LenIndex == pst_zcs->PackeParseLen.PF_UID)
{
pst_zcs->PackeParseLen.LenIndex = 0;
pst_zcs->StateStep = _ZCS_CMD_H;
}
}
/* CMD H -5 */
static void ZCS_Check_CMDH( ZCS* pst_zcs )
{
INT8U u8_input = pst_zcs->InByte;
pst_zcs->CMD = u8_input;
pst_zcs->CMD <<= 8;
pst_zcs->CMD &= 0xFF00;
pst_zcs->StateStep = _ZCS_CMD_L;
}
/* CMD L -6 */
static void ZCS_Check_CMDL( ZCS* pst_zcs )
{
INT8U u8_input = pst_zcs->InByte;
pst_zcs->CMD += u8_input;
pst_zcs->StateStep = _ZCS_DLEN_H;
}
/* data length H -7 */
static void ZCS_Check_datalengthH( ZCS* pst_zcs )
{
INT8U u8_input = pst_zcs->InByte;
pst_zcs->DataLen = u8_input;
pst_zcs->DataLen <<= 8;
pst_zcs->DataLen &= 0xFF00;
pst_zcs->StateStep = _ZCS_DLEN_L;
}
/* data length L -8 */
static void ZCS_Check_datalengthHL( ZCS* pst_zcs )
{
INT8U u8_input = pst_zcs->InByte;
pst_zcs->DataLen += u8_input;
pst_zcs->PackeParseLen.LenIndex = 0;
if( pst_zcs->DataLen >= pst_zcs->MaxParseLength)
{
ZCS_ParserReset( pst_zcs );
}
else if( !pst_zcs->DataLen ){
pst_zcs->StateStep = _ZCS_CRC16_H;
}
else{
pst_zcs->StateStep = _ZCS_DATA;
}
}
/* data packet -9 */
static void ZCS_Check_DataPck( ZCS* pst_zcs )
{
INT8U inByte = pst_zcs->InByte;
pst_zcs->DataBuf[pst_zcs->PackeParseLen.LenIndex++] = inByte;
if( pst_zcs->PackeParseLen.LenIndex == pst_zcs->DataLen)
{
pst_zcs->PackeParseLen.LenIndex = 0;
pst_zcs->StateStep = _ZCS_CRC16_H;
}
}
/* calculate CRC16 */
static void ZCS_Check_calculateCRC( ZCS* pst_zcs )
{
INT16U crc16Cal;
INT8U i;
pst_zcs->PackeParseLen.LenIndex = 0;
/* header */
pst_zcs->RecvDataBuf[pst_zcs->PackeParseLen.LenIndex++] = (pst_zcs->Head >>8) & 0xff;
pst_zcs->RecvDataBuf[pst_zcs->PackeParseLen.LenIndex++] = pst_zcs->Head & 0xff;
/* FNUM */
pst_zcs->RecvDataBuf[pst_zcs->PackeParseLen.LenIndex++] = (pst_zcs->FNUM >>8) & 0xff;
pst_zcs->RecvDataBuf[pst_zcs->PackeParseLen.LenIndex++] = pst_zcs->FNUM & 0xff;
/* UID */
for( i = 0; i < pst_zcs->PackeParseLen.PF_UID; i++ )
{
pst_zcs->RecvDataBuf[pst_zcs->PackeParseLen.LenIndex++] = pst_zcs->UID
;
}
/* CMD */
pst_zcs->RecvDataBuf[pst_zcs->PackeParseLen.LenIndex++] = (pst_zcs->CMD >>8) & 0xff;
pst_zcs->RecvDataBuf[pst_zcs->PackeParseLen.LenIndex++] = pst_zcs->CMD & 0xff;
/* data length */
pst_zcs->RecvDataBuf[pst_zcs->PackeParseLen.LenIndex++] = (pst_zcs->DataLen >>8) & 0xff;
pst_zcs->RecvDataBuf[pst_zcs->PackeParseLen.LenIndex++] = pst_zcs->DataLen & 0xff;
/* data */
for( i = 0; i < pst_zcs->DataLen; i++ )
{
pst_zcs->RecvDataBuf[pst_zcs->PackeParseLen.LenIndex++] = pst_zcs->DataBuf;
}
/* calculate CRC16 */
crc16Cal = UTL_ChkCrc16( pst_zcs->RecvDataBuf, pst_zcs->PackeParseLen.LenIndex);
if( crc16Cal == pst_zcs->CRC16 )
{
pst_zcs->RecvDataBuf[pst_zcs->PackeParseLen.LenIndex++] = (crc16Cal >>8) & 0xff;
pst_zcs->RecvDataBuf[pst_zcs->PackeParseLen.LenIndex++] = crc16Cal & 0xff;
pst_zcs->PacketFlags_bit.PF_ACTION = 1;
pst_zcs->PackeParseLen.LenIndex = 0;
}
else
{
ZCS_ParserReset( pst_zcs );
}
}
/* CRC16 H -10 */
static void ZCS_Check_CRC16H( ZCS* pst_zcs )
{
INT8U u8_input = pst_zcs->InByte;
pst_zcs->CRC16 = u8_input;
pst_zcs->CRC16 <<= 8;
pst_zcs->CRC16 &= 0xFF00;
pst_zcs->StateStep = _ZCS_CRC16_L;
}
/* CRC16 L -11 */
static void ZCS_Check_CRC16L( ZCS* pst_zcs )
{
INT8U u8_input = pst_zcs->InByte;
pst_zcs->CRC16 |= u8_input;
ZCS_Check_calculateCRC( pst_zcs );
}
/* must match with ZCS_STATE total number */
static void (* const ZCS_Check[])(ZCS*) = {
ZCS_Check_HEADH,
ZCS_Check_HEADL,
ZCS_Check_FNUMH,
ZCS_Check_FNUML,
ZCS_Check_UID,
ZCS_Check_CMDH,
ZCS_Check_CMDL,
ZCS_Check_datalengthH,
ZCS_Check_datalengthHL,
ZCS_Check_DataPck,
ZCS_Check_CRC16H,
ZCS_Check_CRC16L,
};
void ZCS_Parser( ZCS* pst_zcs, INT8U u8_input )
{
pst_zcs->InByte = u8_input;
ZCS_Check[pst_zcs->StateStep]( pst_zcs );
}
// 数据包模式解析
INT8U ZCS_CommHandlerAction( ZCS *pst_zcs, INT8U *pbuff)
{
INT16U cmd;
INT8U UID[6];
INT16U packetlenth;
memset( UID, 0xff, 6);
packetlenth = 0;
//Step - 1 header
if(pbuff[COLLECT_PROTOCOL_HEADER1_OFFSET]!=FRAME_HEADER0
|| pbuff[COLLECT_PROTOCOL_HEADER2_OFFSET]!=FRAME_HEADER1)
{
return FALSE;
}
else{
pst_zcs->Head = FRAME_HEADER0<<8|FRAME_HEADER1;
packetlenth += 2;
}
//Step - 2 FUMN
pst_zcs->FNUM = pbuff[COLLECT_PROTOCOL_FUMN_OFFSET]<<8|pbuff[COLLECT_PROTOCOL_FUMN_OFFSET+1];
packetlenth += 2;
//Step - 3 UID
memcpy( pst_zcs->UID, pbuff+COLLECT_PROTOCOL_UID_OFFSET, 6);
packetlenth += 6;
//step - 4 cmd
cmd = MAKE_WORD(pbuff[COLLECT_PROTOCOL_CMD_OFFSET],pbuff[COLLECT_PROTOCOL_CMD_OFFSET+1]);
pst_zcs->CMD = cmd&0xff;
pst_zcs->PacketFlags_bit.PF_ACTION = 1;
packetlenth += 2;
//step - 5 date length
pst_zcs->DataLen = pbuff[COLLECT_PROTOCOL_DATA_LENGTH_OFFSET]<<8|pbuff[COLLECT_PROTOCOL_DATA_LENGTH_OFFSET+1];
packetlenth += 2;
//step - 6 copy data
if( pst_zcs->DataLen )
{
memcpy( pst_zcs->DataBuf, pbuff+COLLECT_PROTOCOL_DATA_OFFSET, pst_zcs->DataLen);
packetlenth += pst_zcs->DataLen;
}
//step - 7 calculte crc
if(CheckCRC(pbuff,packetlenth+2) == RC_ERR)
{
return FALSE ;
}
//Action
if( pst_zcs->PacketFlags_bit.PF_ACTION )
{
ZCS_SlaveExecuter( pst_zcs );
pst_zcs->PacketFlags_bit.PF_ACTION = 0;
return TRUE;
}
return FALSE;
}
/* EOF*/[/mw_shl_code]
2. 执行协议文件
[mw_shl_code=c,true]/*******************************************************************************
** File name: ZCS_Excuter.c
** Created by: Mingfei Tang
** Created date: 2016/2/18
** Version: V1.00
** Descriptions: for zcs protocol parsered
** Details:
**------------------------------------------------------------------------------
** Modified by:
** Modified date:
** Version:
** Descriptions:
**
*******************************************************************************/
#include "includes.h"
static INT8U ZCS_Builder( ZCS *pst_zcs )
{
INT16U i;
INT16U cal_Crc;
i = 0;
/* packet head -1 */
pst_zcs->HostSendBuf[i++] = HEAD;
pst_zcs->HostSendBuf[i++] = HEAD;
/* FNUM */
pst_zcs->HostSendBuf[i++] = (pst_zcs->FNUM >>8) & 0xff;
pst_zcs->HostSendBuf[i++] = pst_zcs->FNUM & 0xff;
/* UID */
for(INT8U j = 0; j < pst_zcs->PackeParseLen.PF_UID; j++)
{
pst_zcs->HostSendBuf[i++] = pst_zcs->UID[j];
}
/* CMD */
pst_zcs->HostSendBuf[i++] = (pst_zcs->CMD >>8) & 0xff;
pst_zcs->HostSendBuf[i++] = pst_zcs->CMD & 0xff;
/* data length */
pst_zcs->HostSendBuf[i++] = (pst_zcs->DataLen >>8) & 0xff;
pst_zcs->HostSendBuf[i++] = pst_zcs->DataLen & 0xff;
/* data packet */
for(INT16U j = 0; j < pst_zcs->DataLen; j++)
{
pst_zcs->HostSendBuf[i++] = pst_zcs->DataBuf[j];
}
/* crc 16*/
cal_Crc = UTL_ChkCrc16( pst_zcs->HostSendBuf, i );
pst_zcs->HostSendBuf[i++] = (cal_Crc >> 8) & 0XFF;
pst_zcs->HostSendBuf[i++] = cal_Crc & 0XFF ;
pst_zcs->HostPckLength = i;
if( pst_zcs->pf_SendPut != NULL )
{
pst_zcs->pf_SendPut( pst_zcs->HostSendBuf, pst_zcs->HostPckLength);
return( 1 );
}
return 0;
}
/* return 1: support, 0: not support */
static INT8U ZCS_SearchCmd( ZCS *pst_zcs, PFNCT_ZCS* func )
{
INT16U i;
ZCS_CmdNode* tptr;
/* Search command set */
tptr = (ZCS_CmdNode *)pst_zcs->CmdTable;
for( i=0; i<pst_zcs->CmdTotal; i++ )
{
if( pst_zcs->CMD == (tptr+i)->command )
{
*func = (PFNCT_ZCS)(tptr+i)->pf_FuncPtr;
return( 1 );
}
}
return( 0 );
}
/* return 1: support, 0: not support */
INT8U ZCS_ActionExecuter( ZCS* zcs )
{
PFNCT_ZCS fptr = NULL;
if( ZCS_SearchCmd(zcs, &fptr ) == 0 )
{
goto exit;
}
if( fptr != NULL )
{
fptr( zcs );
}
return( 1 );
exit:
return( 0 );
}
/*******************************************************************************
Host action
********************************************************************************/
INT8U ZCS_HostSendPacket( ZCS *pst_zcs )
{
if( !ZCS_Builder( pst_zcs ) == 1 )
{
return 0;
}
return 1;
}
/*******************************************************************************
slave action
********************************************************************************/
INT8U ZCS_SlaveExecuter( ZCS *pst_zcs )
{
if(ZCS_ActionExecuter( pst_zcs ))
{
//Refrsh command
pst_zcs->CMD |= ZCS_SUCESS;
}
else
{
pst_zcs->CMD |= ZCS_ERROR;
}
/* Slave action */
if( !ZCS_Builder( pst_zcs ) == 1 )
{
return 0;
}
return 1;
}
/* EOF */[/mw_shl_code]
3. 头文件定义
[mw_shl_code=c,true]#ifndef __ZCS_H
#define __ZCS_H
#define ZCS_SUCESS 0X8000
#define ZCS_ERROR 0X4000
#define HEAD 0xfb
#define MAX_RETRY 3
typedef enum
{
ERR_OK = 0x0000,
ERR_OUT_OF_MEMORY=0x0001,
ERR_PARAM=0x0002,
ERR_SAMPLING=0x0003,
ERR_UNSUPORT_SAMPLE_RATE=0x0004,
ERR_END = 0x0005,
ERR_SENSOR_ALREADY_EXIST=0x0100,
ERR_SENSOR_NOT_EXIST=0x0101,
ERR_GPRSINFOR=0x0103,
ERR_LOG=0x0104,
ERR_SENSOR=0x0202,
ERR_SENSORNORSP = 0x7fffff41,
}Comm_error_code;
typedef enum {
HOST_RECV=1,
SLAVE_RECV,
HOST_SEND,
} ZCS_ROLE;
typedef enum {
_ZCS_HEAD_H = 0,
_ZCS_HEAD_L,
_ZCS_FNUM_H,
_ZCS_FNUM_L,
_ZCS_UID,
_ZCS_CMD_H,
_ZCS_CMD_L,
_ZCS_DLEN_H,
_ZCS_DLEN_L,
_ZCS_DATA,
_ZCS_CRC16_H,
_ZCS_CRC16_L,
} ZCS_STATE;
typedef struct {
INT8U PF_REPEAT :1;
INT8U PF_REPEATED :1;
INT8U :1;
INT8U :1;
INT8U PF_BROADCAST :1;
INT8U PF_ACTION :1;
INT8U PF_SPECIAL :1;
INT8U PF_INIT :1;
}ZCS_PacketFlag;
typedef struct {
INT8U :1;
INT8U :1;
INT8U :1;
INT8U :1;
INT8U CS_ERR_BUSY :1;
INT8U CS_ERR_DATA :1;
INT8U CS_ERR_CMD :1;
INT8U :1;
} ZCS_CommStatus;
typedef struct {
INT8U PF_HEAD;
INT8U PF_FNUM;
INT8U PF_UID;
INT8U PF_CMD;
INT8U PF_DLEN;
INT8U PF_DATAPACLEN;
INT8U PF_CRC16;
INT8U LenIndex;
}ZCS_PackeParseLEN;
typedef struct _ZCS {
/* ZCS internal use only */
ZCS_PackeParseLEN PackeParseLen;
ZCS_STATE StateStep;
INT8U Role;
INT8U InByte;
INT8U RtnCode;
INT8U VerPac;
INT16U SlaveAddr;
INT16U HostAddr;
/* data packet */
INT16U Head;
INT16U FNUM;
INT16U CRC16;
INT16U CMD;
INT16U DataLen;
INT8U *DataBuf;
INT8U *RecvDataBuf;
INT8U UID[6];
/* Host structure */
INT8U *HostSendBuf;
INT16U HostPckLength;
/* Use accessible */
union {
INT8U PacketFlags;
ZCS_PacketFlag PacketFlags_bit;
};
union {
INT8U CommStatus;
ZCS_CommStatus CommStatus_bit;
};
void (*pf_SendPut)(INT8U*, INT16U);
INT16U ParseLength;
INT16U MaxParseLength;
void* CmdTable;
INT16U CmdTotal;
} ZCS;
typedef void (*PFNCT_ZCS)(ZCS *);
typedef struct {
INT16U command;
PFNCT_ZCS pf_FuncPtr;
PFNCT_ZCS pf_PostFuncPtr;
} ZCS_CmdNode;
#endif /* __ZCS_H */[/mw_shl_code]
一周热门 更多>