1. 程式人生 > >Arduino自定義通訊協議解析

Arduino自定義通訊協議解析

/*
自定義的庫函式:
  協議解析器 V1.0
解析的資料格式:
  協議首部-指令長度-控制指令-校驗和
"控制指令"格式:
  裝置型別-裝置號-埠號
*/
#include<stdlib.h>
#include<string.h>
//#pragma warning(disable:4996)
#define BUFFER_SIZE 128//假定接收資料的最大長度為128
class ProtocolParser
{
public:
  ProtocolParser(char *header);
  ~ProtocolParser();
  void Append(char *data);
  void AppendChar(char ch);//將從串列埠接收到的字元存到buffer

  size_t GetDeviceType();//獲取裝置型別
  size_t GetDeviceNumber();//獲取裝置號
  size_t GetPort();//獲取裝置所連線的埠號

private:
  bool m_bInCmd;//標誌位,標識一條控制指令是否接收完畢
  char *m_pHeader;//協議首部
  size_t m_nCmdLength;//指令長度
  char *m_pCtrlCmd;//控制指令
  size_t m_nCheckSum;//校驗和
  char buffer[BUFFER_SIZE];//接收的資料暫時存在buffer中
  size_t m_nRecvDataIndex;//記錄接收資料的索引

  char GetHeader(size_t index);//獲取協議首部指定索引的字元
  size_t GetCmdLength();//獲取控制指令長度
  size_t GetRecvDataLength();//獲取接收到的一條控制指令的長度
  size_t GetCheckSum();//獲取實際接收到的校驗和
};

//建構函式初始化,header為協議首部
ProtocolParser::ProtocolParser(char *header)
{
  m_bInCmd = false;
  //strcpy(m_pHeader, header);
  m_pHeader = header;
  m_nCmdLength = 0;
  m_nCheckSum = 0;
  m_nRecvDataIndex = 0;
  m_pCtrlCmd = NULL;

  buffer[0] = '\0';
}

ProtocolParser::~ProtocolParser()
{
}

char ProtocolParser::GetHeader(size_t index)
{
  int headerLength = strlen(m_pHeader);
  return m_pHeader[index];
}
//獲取“控制指令”欄位的長度,通過接收到的資料的第2、3位的值獲取
size_t ProtocolParser::GetCmdLength()
{
  int len = strlen(buffer);
  if (len >= 2)
  {
    m_nCmdLength=(buffer[0] - '0') * 16 + (buffer[1] - '0') * 1;
  }
  return m_nCmdLength;
}
//獲取實際接收到的校驗和
size_t ProtocolParser::GetCheckSum()
{
  //int len = strlen(buffer);
  m_nCheckSum = (buffer[GetCmdLength() * 2 + 2] - '0') * 16 + (buffer[GetCmdLength() * 2 + 3] - '0') * 1;
  return m_nCheckSum;
}
//從buffer中解析出裝置型別
size_t ProtocolParser::GetDeviceType()
{
  //int len = strlen(buffer);
  return (buffer[2] - '0') * 16 + (buffer[3] - '0') * 1;
}
//從buffer中解析出裝置號
size_t ProtocolParser::GetDeviceNumber()
{
  //int len = strlen(buffer);
  return (buffer[4] - '0') * 16 + (buffer[5] - '0') * 1;
}
//從buffer中解析出埠號
size_t ProtocolParser::GetPort()
{
  //int len = strlen(buffer);
  return (buffer[6] - '0') * 16 + (buffer[7] - '0') * 1;
}

//將從串列埠接收的字串存入buffer中
void ProtocolParser::AppendChar(char ch)
{
  size_t bufferLength = strlen(buffer);
  switch (m_nRecvDataIndex)
  {
  case 0:
  case 1://接收到的資料的索引值為0或者1,表示接收到的是首部
    m_bInCmd = true;
    buffer[0] = 0;
    m_nRecvDataIndex++;
    return;
    break;
  case 2:
  case 3://接收到的資料的索引值為2或者3,表示接收到的是"指令長度"部分
    buffer[m_nRecvDataIndex - 2] = ch;
    buffer[m_nRecvDataIndex - 1] = '\0';
    m_nRecvDataIndex++;
    return;
    break;
  default:
    break;
  }
  if (m_nRecvDataIndex==(GetCmdLength()*2+5))//達到了索引值
  {
    buffer[bufferLength] = ch;
    buffer[bufferLength + 1] = '\0';
    size_t chksum = 0;
    //計算根據接收的資料得到的校驗和
    for (size_t i = 0; i < GetCmdLength()*2;++i)
    {
      chksum ^= buffer[i + 2];
    }

    if (chksum==GetCheckSum())//判斷實際接收到的校驗和跟計算出來的校驗和是否相等
    {
      Serial.println("DeviceType:");
      Serial.println(GetDeviceType(),DEC);
      Serial.println("DeviceNumber:");
      Serial.println(GetDeviceNumber(),DEC);
      Serial.println("Port:");
      Serial.println(GetPort(),DEC);
      //GetDeviceNumber();
      //GetPort();
      //解析buffer的各個欄位的含義
      //cout << "DeviceType:" << GetDeviceType() << endl;
      //cout << "DeviceNumber:" << GetDeviceNumber() << endl;
      //cout << "Port:" << GetPort() << endl;
    }
    else//不相等說明出錯了
    {
      Serial.println("Error");
      //cout << "Error" << endl;
    }
    buffer[0] = '\0';
    m_bInCmd = false;
    m_nRecvDataIndex = 0;
    m_nCheckSum = 0;
  }
  else if (m_bInCmd)//指令未接收完畢
  {
    buffer[bufferLength] = ch;
    buffer[bufferLength + 1] = '\0';
    m_nRecvDataIndex++;
  }
}
void ProtocolParser::Append(char *data)
{
  for (size_t i = 0; i < strlen(data);++i)
  {
    AppendChar(data[i]);
  }
}
//int led=13;
char value;
ProtocolParser protocolParser(170);
void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  //Serial.println("Parser:");
  //pinMode(led,OUTPUT);
}
void loop() {
  // put your main code here, to run repeatedly:
  while(Serial.available()>0){
    value=Serial.read();
    //Serial.print(value);
    protocolParser.AppendChar(value);
    //Serial.println(protocolParser.getPort());
  }
}
編譯執行上傳到板子上以後,在串列埠除錯助手中除錯結果如下圖: