C 嵌入式系统的串行通信数据包组织

C 嵌入式系统的串行通信数据包组织,c,serialization,embedded,uart,C,Serialization,Embedded,Uart,我有一个嵌入式项目,我正在实现一个库来处理两个微处理器之间的串行通信。我心目中有一种结构,可以为可能随着时间推移而添加的数据包提供一种可伸缩的方法 需要有携带可变长度信息的不同数据包。接收数据包的处理器对每种类型的数据包都有不同的解释 每次输入一个字节时都要执行读取。当一个完整的数据包到达时,调用consumer函数来尽快处理它 我想解释一下我的方法,并就它的缺点以及如何改进得到一些反馈 目前的做法: 创建一个显示数据成员和长度的结构 创建一个包含所有类型数据包和uint_8缓冲区的联合

我有一个嵌入式项目,我正在实现一个库来处理两个微处理器之间的串行通信。我心目中有一种结构,可以为可能随着时间推移而添加的数据包提供一种可伸缩的方法

需要有携带可变长度信息的不同数据包。接收数据包的处理器对每种类型的数据包都有不同的解释

每次输入一个字节时都要执行读取。当一个完整的数据包到达时,调用consumer函数来尽快处理它

我想解释一下我的方法,并就它的缺点以及如何改进得到一些反馈

目前的做法:

  • 创建一个显示数据成员和长度的结构
  • 创建一个包含所有类型数据包和uint_8缓冲区的联合
  • 创建一个结构,其中包含读取的字节、当前正在读取的数据包类型(联合的标记)、转义状态
  • 创建一个枚举,显示不同类型数据包的值(还包含转义字符的值)
职能的执行: -每当读取字节时,检查它是否是新操作,如果是,则更改union标记。 -否则,如果转义字符值设置转义标志。 -否则将数据推送到缓冲区,增量字节读取。 还为当前操作调用checkfinished函数(switch语句)。 如果完成,处理数据包并重置控制结构。 如果没有,什么也不会发生

void DispRead1B(void)
{
    static uint8_t ReadByte;

    ReadByte = (uint8_t)UARTCharGet(DISP_BASE);

    if(DisplayPacket.EscapeNext)
    {
        DisplayPacketPushByte(ReadByte);
        DisplayPacket.EscapeNext = false;
    }
    else
    {
        if(ReadByte == RECEIVE_ESCAPE)
        {
            DisplayPacket.EscapeNext = true;
        }
        else if((ReadByte < RECEIVE_ESCAPE) && (ReadByte > RECEIVE_NO_OPERATION))
        {
            DisplayPacketChangeOperation(ReadByte);
        }
        else
        {
            DisplayPacketPushByte(ReadByte);
        }
    }
}

void DisplayPacketChangeOperation(uint8_t Operation)
{
    DisplayPacket.CurrentOperation = Operation;
    DisplayPacketResetBytesRead();
    DisplayPacket.EscapeNext = false;
    DisplayPacketCheckOperationFinished();
}

void DisplayPacketPushByte(uint8_t Value)
{
    DisplayPacket.SerialBuffer[DisplayPacket.BytesRead] = Value;
    DisplayPacketIncrementBytesRead();
    DisplayPacketCheckOperationFinished();
}

void DisplayPacketIncrementBytesRead(void)
{
    DisplayPacket.BytesRead += 1;
    if(DisplayPacket.CurrentOperation == RECEIVE_NO_OPERATION)
    {
        DisplayPacket.BytesRead = 0;
    }
}

bool DisplayPacketCheckOperationFinished(void)
{
  bool PacketFinished = false;
  switch (DisplayPacket.CurrentOperation)
  {
      case ACK:
          PacketFinished = DisplayPacketCheckAckFinished(); break;
      case VERSION_REQUEST:
          PacketFinished = DisplayPacketCheckVersionRequestFinished(); break;
      case PASSWORD:
          PacketFinished = DisplayPacketCheckPasswordFinished(); break;
      default:
          return false;
  }
  if(PacketFinished)
  {
      DisplayPacketChangeOperation(RECEIVE_NO_OPERATION);
  }
  return PacketFinished;
}

bool DisplayPacketCheckAckFinished(void)
{
    if(DisplayPacket.BytesRead == ACK_PACKET_BYTES)
    {
        if(CheckSysFlagNotSet(KeepAliveAckReceived))
        {
          UpdateSysFlag(KeepAliveAckReceived,true);
          StartAliveTimer();
        }
        else
        {
          UpdateSysFlag(ConnectionError,false);
          ReloadAliveTimer();
        }
        return true;
    }
    return false;
}

bool DisplayPacketCheckVersionRequestFinished(void)
{

    if(DisplayPacket.BytesRead == VER_REQ_PACKET_BYTES)
    {
      UpdateSysFlag(FirmwareVerRequested,true);
      return true;
    }
    return false;
}

bool DisplayPacketCheckPasswordFinished(void)
{
    if(DisplayPacket.BytesRead == PASSWORD_PACKET_BYTES)
    {
        PasswordPacket = DisplayPacket.PasswordPacket;
        UpdateSysFlag(PasswordReceived,true);
        return true;
    }
    return false;
}
void DispRead1B(void)
{
静态uint8_t ReadByte;
ReadByte=(uint8_t)UARTCharGet(DISP_BASE);
if(displaypack.EscapeNext)
{
显示packetpushbyte(ReadByte);
displaypack.EscapeNext=false;
}
其他的
{
if(ReadByte==接收\u转义)
{
displaypack.EscapeNext=true;
}
否则如果((ReadByteRECEIVE\u NO\u操作))
{
显示PacketChangeOperation(读取字节);
}
其他的
{
显示packetpushbyte(ReadByte);
}
}
}
无效显示packetchange操作(uint8\t操作)
{
DisplayPacket.CurrentOperation=操作;
DisplayPacketResetBytesRead();
displaypack.EscapeNext=false;
DisplayPacketCheckOperationFinished();
}
无效显示packetpushbyte(uint8_t值)
{
displaypack.SerialBuffer[displaypack.BytesRead]=值;
DisplayPacketIncrementBytesRead();
DisplayPacketCheckOperationFinished();
}
void display packetincrementbytesread(void)
{
displaypack.BytesRead+=1;
if(DisplayPacket.CurrentOperation==接收\u否\u操作)
{
displaypack.BytesRead=0;
}
}
bool DisplayPacketCheckOperationFinished(无效)
{
bool PacketFinished=false;
交换机(DisplayPacket.CurrentOperation)
{
案例确认:
PacketFinished=显示PacketCheckAckFinished();中断;
案例版本请求:
PacketFinished=DisplayPacketCheckVersionRequestFinished();中断;
案例密码:
PacketFinished=DisplayPacketCheckPasswordFinished();中断;
违约:
返回false;
}
如果(包装完成)
{
显示PacketChangeOperation(接收\u否\u操作);
}
返回包装完成;
}
bool DisplayPacketCheckAckFinished(无效)
{
if(displaypack.BytesRead==ACK\u PACKET\u字节)
{
if(CheckSysFlagNotSet(KeepAliveAckReceived))
{
UpdateSysFlag(KeepAliveAckReceived,true);
StartAliveTimer();
}
其他的
{
UpdateSysFlag(ConnectionError,false);
重新加载AliveTimer();
}
返回true;
}
返回false;
}
bool DisplayPacketCheckVersionRequestFinished(无效)
{
if(displaypack.BytesRead==VER\u REQ\u PACKET\u字节)
{
UpdateSysFlag(firmWareRequested,true);
返回true;
}
返回false;
}
bool DisplayPacketCheckPasswordFinished(无效)
{
if(displaypack.BytesRead==密码\数据包\字节)
{
PasswordPacket=DisplayPacket.PasswordPacket;
UpdateSysFlag(PasswordReceived,true);
返回true;
}
返回false;
}
使用这种方法,不需要序列化,因为联合会处理它。此外,如果需要数据的备份副本,复制数据包的语法也很简单。即:PacketType=CommUnion.PacketType

添加新数据包时。创建一个结构并将其添加到union中,添加新的enum字段,并向check FINATED switch语句添加一个案例,该语句调用此数据包的函数

这需要库的源代码在我不喜欢的多行上进行更改

有没有一种方法可以以一种更简单的方式实现类似的功能,即在编译的comm结构保持不变的情况下,需要进行外部更改

第二种方法(使用函数指针):

  • 摆脱工会。控制结构仍然保持不变,因为我们需要跟踪当前的数据包类型和字节读取、转义等
  • 摆脱enum方法以创建数据包值。创建函数,为不同的数据包注册检查完成的函数,并像enum方法一样为它们赋值。寄存器函数是用于检查函数的函数指针数组
  • 启动时,初始化所有数据包结构。(主程序或项目特定模块中的更改不在库中。)
  • 然后使用register函数注册所有数据包。这样,数据包的数量和转义字符的值可以在运行时计算(如果编译器是智能的,则在编译时计算)
  • 当您按下一个数据字节时,Check finished函数指针用于调用该函数。此函数序列化(或调用此函数)并在数据包完全接收时处理数据包
这种方法的好处是创建了数据包的实例(
#define DISPLAY_PACKET_BYTES    16
typedef struct
{
    union
    {
        uint8_t SerialBuffer[DISPLAY_PACKET_BYTES];
        password_packet_t PasswordPacket;
    };
    struct
    {
        uint8_t CurrentOperation;
        uint8_t BytesRead;
        bool EscapeNext;
    };
}disp_receive_packet_t;
enum
{
    RECEIVE_NO_OPERATION = 0xA0,
    ACK, 
    PASSWORD,
    VERSION_REQUEST,
    RECEIVE_ESCAPE,
}DISP_RECEIVE_OPERATIONS;
void DispRead1B(void)
{
    static uint8_t ReadByte;

    ReadByte = (uint8_t)UARTCharGet(DISP_BASE);

    if(DisplayPacket.EscapeNext)
    {
        DisplayPacketPushByte(ReadByte);
        DisplayPacket.EscapeNext = false;
    }
    else
    {
        if(ReadByte == RECEIVE_ESCAPE)
        {
            DisplayPacket.EscapeNext = true;
        }
        else if((ReadByte < RECEIVE_ESCAPE) && (ReadByte > RECEIVE_NO_OPERATION))
        {
            DisplayPacketChangeOperation(ReadByte);
        }
        else
        {
            DisplayPacketPushByte(ReadByte);
        }
    }
}

void DisplayPacketChangeOperation(uint8_t Operation)
{
    DisplayPacket.CurrentOperation = Operation;
    DisplayPacketResetBytesRead();
    DisplayPacket.EscapeNext = false;
    DisplayPacketCheckOperationFinished();
}

void DisplayPacketPushByte(uint8_t Value)
{
    DisplayPacket.SerialBuffer[DisplayPacket.BytesRead] = Value;
    DisplayPacketIncrementBytesRead();
    DisplayPacketCheckOperationFinished();
}

void DisplayPacketIncrementBytesRead(void)
{
    DisplayPacket.BytesRead += 1;
    if(DisplayPacket.CurrentOperation == RECEIVE_NO_OPERATION)
    {
        DisplayPacket.BytesRead = 0;
    }
}

bool DisplayPacketCheckOperationFinished(void)
{
  bool PacketFinished = false;
  switch (DisplayPacket.CurrentOperation)
  {
      case ACK:
          PacketFinished = DisplayPacketCheckAckFinished(); break;
      case VERSION_REQUEST:
          PacketFinished = DisplayPacketCheckVersionRequestFinished(); break;
      case PASSWORD:
          PacketFinished = DisplayPacketCheckPasswordFinished(); break;
      default:
          return false;
  }
  if(PacketFinished)
  {
      DisplayPacketChangeOperation(RECEIVE_NO_OPERATION);
  }
  return PacketFinished;
}

bool DisplayPacketCheckAckFinished(void)
{
    if(DisplayPacket.BytesRead == ACK_PACKET_BYTES)
    {
        if(CheckSysFlagNotSet(KeepAliveAckReceived))
        {
          UpdateSysFlag(KeepAliveAckReceived,true);
          StartAliveTimer();
        }
        else
        {
          UpdateSysFlag(ConnectionError,false);
          ReloadAliveTimer();
        }
        return true;
    }
    return false;
}

bool DisplayPacketCheckVersionRequestFinished(void)
{

    if(DisplayPacket.BytesRead == VER_REQ_PACKET_BYTES)
    {
      UpdateSysFlag(FirmwareVerRequested,true);
      return true;
    }
    return false;
}

bool DisplayPacketCheckPasswordFinished(void)
{
    if(DisplayPacket.BytesRead == PASSWORD_PACKET_BYTES)
    {
        PasswordPacket = DisplayPacket.PasswordPacket;
        UpdateSysFlag(PasswordReceived,true);
        return true;
    }
    return false;
}