微网协议去掉尾部的TTL和Retry,由标识位来承载
Zigbee有粘包情况,但是因为TTL/Retry的存在,导致后半截指令解析错误
This commit is contained in:
parent
21f824ddad
commit
eed7f61d93
|
@ -84,10 +84,22 @@ uint Controller::Dispatch(ITransport* port, ByteArray& bs, void* param, void* pa
|
|||
Stream ms(buf, len);
|
||||
while(ms.Remain() >= control->MinSize)
|
||||
{
|
||||
#if MSG_DEBUG
|
||||
uint p = ms.Position();
|
||||
buf = ms.Current();
|
||||
len = ms.Remain();
|
||||
#endif
|
||||
// 如果不是有效数据包,则直接退出,避免产生死循环。当然,也可以逐字节移动测试,不过那样性能太差
|
||||
if(!control->Dispatch(ms, NULL))
|
||||
{
|
||||
#if MSG_DEBUG
|
||||
// 兼容性处理,如果0x00 0x01 0x02开头,则重新来一次
|
||||
if(buf[0] == 0x00 || buf[0] == 0x01 || buf[0] == 0x02 || buf[0] == 0x03)
|
||||
{
|
||||
ms.SetPosition(p + 1);
|
||||
continue;
|
||||
}
|
||||
|
||||
msg_printf("TinyNet::DispatchError[%d] ", len);
|
||||
// 输出整条信息
|
||||
Sys.ShowHex(buf, len, '-');
|
||||
|
|
|
@ -348,7 +348,7 @@ void SerialPort::OnRxHandler()
|
|||
_task->NextTime = Time.Current() + 1;
|
||||
_task->Enable = true;
|
||||
// 如果系统调度器处于Sleep,让它立马退出
|
||||
//Task::Scheduler()->Sleeping = false;
|
||||
Task::Scheduler()->Sleeping = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -24,10 +24,6 @@ TinyMessage::TinyMessage(byte code) : Message(code)
|
|||
memset(&Dest, 0, MinSize);
|
||||
|
||||
Crc = 0;
|
||||
TTL = 0;
|
||||
#if MSG_DEBUG
|
||||
Retry = 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
// 分析数据,转为消息。负载数据部分将指向数据区,外部不要提前释放内存
|
||||
|
@ -36,7 +32,7 @@ bool TinyMessage::Read(Stream& ms)
|
|||
// 消息至少4个头部字节、2字节长度和2字节校验,没有负载数据的情况下
|
||||
if(ms.Remain() < MinSize) return false;
|
||||
|
||||
const byte* p = ms.Current();
|
||||
byte* p = ms.Current();
|
||||
ms.Read(&Dest, 0, HeaderSize);
|
||||
|
||||
// 占位符拷贝到实际数据
|
||||
|
@ -60,25 +56,15 @@ bool TinyMessage::Read(Stream& ms)
|
|||
// 读取真正的校验码
|
||||
Checksum = ms.Read<ushort>();
|
||||
|
||||
// 计算Crc之前,需要清零TTL和Retry
|
||||
byte fs = p[3];
|
||||
TinyMessage* msg = (TinyMessage*)p;
|
||||
msg->TTL = 0;
|
||||
msg->Retry = 0;
|
||||
// 连续的,可以直接计算Crc16
|
||||
Crc = Crc::Hash16(p, HeaderSize + Length);
|
||||
|
||||
// 后面可能有TTL
|
||||
if(UseTTL)
|
||||
{
|
||||
// 必须严格检查,否则可能成为溢出漏洞
|
||||
if(ms.Remain() > 0)
|
||||
TTL = ms.Read<byte>();
|
||||
else
|
||||
TTL = 0;
|
||||
}
|
||||
#if MSG_DEBUG
|
||||
// 调试诊断模式下该字段表示第几次重发
|
||||
if(ms.Remain() > 0)
|
||||
Retry = ms.Read<byte>();
|
||||
else
|
||||
Retry = 0;
|
||||
#endif
|
||||
// 还原数据
|
||||
p[3] = fs;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -102,15 +88,19 @@ void TinyMessage::Write(Stream& ms) const
|
|||
ms.Write((byte*)&Dest, 0, HeaderSize);
|
||||
if(Length > 0) ms.Write(Data, 0, Length);
|
||||
|
||||
// 计算Crc之前,需要清零TTL和Retry
|
||||
byte fs = buf[3];
|
||||
TinyMessage* msg = (TinyMessage*)buf;
|
||||
msg->TTL = 0;
|
||||
msg->Retry = 0;
|
||||
|
||||
p->Checksum = p->Crc = Crc::Hash16(buf, HeaderSize + Length);
|
||||
|
||||
// 还原数据
|
||||
buf[3] = fs;
|
||||
|
||||
// 写入真正的校验码
|
||||
ms.Write(Checksum);
|
||||
|
||||
// 后面可能有TTL
|
||||
if(UseTTL && ms.Position() < 24) ms.Write(TTL);
|
||||
#if MSG_DEBUG
|
||||
if(ms.Position() < 24) ms.Write(Retry);
|
||||
#endif
|
||||
}
|
||||
|
||||
void TinyMessage::ComputeCrc()
|
||||
|
@ -141,10 +131,6 @@ bool TinyMessage::Valid() const
|
|||
uint TinyMessage::Size() const
|
||||
{
|
||||
uint len = MinSize + Length;
|
||||
if(UseTTL) len++;
|
||||
#if MSG_DEBUG
|
||||
len++;
|
||||
#endif
|
||||
return len;
|
||||
}
|
||||
|
||||
|
@ -304,11 +290,8 @@ bool TinyController::Valid(const Message& msg)
|
|||
{
|
||||
// 快速响应确认消息,避免对方无休止的重发
|
||||
if(!tmsg.NoAck) AckResponse(tmsg);
|
||||
#if MSG_DEBUG
|
||||
|
||||
msg_printf("重复消息 Reply=%d Ack=%d Src=0x%02x Seq=%d Retry=%d\r\n", tmsg.Reply, tmsg.Ack, tmsg.Src, tmsg.Sequence, tmsg.Retry);
|
||||
#else
|
||||
msg_printf("重复消息 Reply=%d Ack=%d Src=0x%02x Seq=%d\r\n", tmsg.Reply, tmsg.Ack, tmsg.Src, tmsg.Sequence);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
_Ring.Push(seq);
|
||||
|
@ -371,11 +354,7 @@ void TinyController::AckRequest(const TinyMessage& msg)
|
|||
else
|
||||
msg_printf("收到Reply确认 ");
|
||||
|
||||
#if MSG_DEBUG
|
||||
msg_printf("Src=%d Seq=%d Cost=%dus Retry=%d\r\n", msg.Src, msg.Sequence, cost, msg.Retry);
|
||||
#else
|
||||
msg_printf("Src=%d Seq=%d Cost=%dus\r\n", msg.Src, msg.Sequence, cost);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -402,10 +381,7 @@ void TinyController::AckResponse(const TinyMessage& msg)
|
|||
#endif
|
||||
|
||||
bool rs = Controller::Send(msg2);
|
||||
msg_printf("发送Ack确认包 Dest=0x%02x Seq=%d ", msg.Src, msg.Sequence);
|
||||
#if MSG_DEBUG
|
||||
msg_printf("Retry=%d ", msg.Retry);
|
||||
#endif
|
||||
msg_printf("发送Ack确认包 Dest=0x%02x Seq=%d Retry=%d ", msg.Src, msg.Sequence, msg.Retry);
|
||||
if(rs)
|
||||
msg_printf(" 成功!\r\n");
|
||||
else
|
||||
|
@ -483,8 +459,9 @@ void TinyController::Loop()
|
|||
//debug_printf("重发消息 Dest=0x%02X Seq=%d Times=%d\r\n", node.Data[0], node.Sequence, node.Times);
|
||||
// 第6个字节表示长度
|
||||
TinyMessage* msg = (TinyMessage*)node.Data;
|
||||
msg->Retry++;
|
||||
// 最后一个附加字节记录第几次重发
|
||||
if(node.Length > TinyMessage::MinSize + msg->Length) node.Data[node.Length - 1] = node.Times;
|
||||
//if(node.Length > TinyMessage::MinSize + msg->Length) node.Data[node.Length - 1] = node.Times;
|
||||
//ByteArray bs(node.Data, node.Length);
|
||||
//bs.Show(true);
|
||||
#endif
|
||||
|
|
|
@ -23,8 +23,8 @@ public:
|
|||
byte Dest; // 目的地址
|
||||
byte Src; // 源地址
|
||||
byte _Code; // 功能代码
|
||||
byte Flags:3; // 标识位。也可以用来做二级命令
|
||||
byte UseTTL:1; // 使用TTL。具体TTL值位于数据包最后
|
||||
byte Retry:2; // 标识位。也可以用来做二级命令
|
||||
byte TTL:2; // 路由TTL。最多3次转发
|
||||
byte NoAck:1; // 是否不需要确认包
|
||||
byte Ack:1; // 确认包
|
||||
byte _Error:1; // 是否错误
|
||||
|
@ -34,12 +34,6 @@ public:
|
|||
byte _Data[32]; // 数据部分
|
||||
ushort Checksum;// 16位检验和
|
||||
|
||||
// 可选的附加数据紧跟在头数据后面,可能直接读取内存区域
|
||||
byte TTL; // 路由生命周期。为方便路由,不参与Crc校验
|
||||
#if DEBUG
|
||||
byte Retry; // 调试诊断模式下该字段表示第几次重发
|
||||
#endif
|
||||
|
||||
// 负载数据及校验部分,并非内存布局。
|
||||
ushort Crc; // 整个消息的Crc16校验,计算前Checksum清零
|
||||
|
||||
|
@ -95,7 +89,6 @@ public:
|
|||
uint Ack; // 总成功。有多少消息收到确认,每条消息仅计算一次确认
|
||||
uint Bytes; // 总字节数。成功发送消息的字节数
|
||||
uint Cost; // 总开销ms。成功发送消息到收到确认所花费的时间
|
||||
//uint Retry; // 总重试次数
|
||||
int Receive;// 收到消息数
|
||||
|
||||
TinyStat()
|
||||
|
|
Loading…
Reference in New Issue