控制器提供发送的内层方法,静态消息,不需要修改。而普通的Send/Reply一般需要重新以实现专有功能

This commit is contained in:
nnhy 2015-12-11 03:50:29 +00:00
parent 81090eee64
commit a3e1cf9ccf
4 changed files with 185 additions and 188 deletions

View File

@ -1,7 +1,7 @@
#include "Controller.h" #include "Controller.h"
//#define MSG_DEBUG DEBUG #define MSG_DEBUG DEBUG
#define MSG_DEBUG 0 //#define MSG_DEBUG 0
#if MSG_DEBUG #if MSG_DEBUG
#define msg_printf debug_printf #define msg_printf debug_printf
#else #else
@ -158,7 +158,19 @@ bool Controller::OnReceive(Message& msg)
bool Controller::Send(Message& msg) bool Controller::Send(Message& msg)
{ {
TS("Controller::Send"); return SendInternal(msg);
}
bool Controller::Reply(Message& msg)
{
msg.Reply = 1;
return SendInternal(msg);
}
bool Controller::SendInternal(const Message& msg)
{
TS("Controller::SendInternal");
// 如果没有传输口处于打开状态,则发送失败 // 如果没有传输口处于打开状态,则发送失败
if(!Port->Open()) return false; if(!Port->Open()) return false;
@ -170,10 +182,3 @@ bool Controller::Send(Message& msg)
Array bs(ms.GetBuffer(), ms.Position()); Array bs(ms.GetBuffer(), ms.Position());
return Port->Write(bs, msg.State); return Port->Write(bs, msg.State);
} }
bool Controller::Reply(Message& msg)
{
msg.Reply = 1;
return Send(msg);
}

View File

@ -43,6 +43,9 @@ public:
// 收到消息时触发 // 收到消息时触发
MessageHandler Received; MessageHandler Received;
void* Param; void* Param;
protected:
bool SendInternal(const Message& msg);
}; };
#endif #endif

View File

@ -13,10 +13,10 @@
void SendTask(void* param); void SendTask(void* param);
void StatTask(void* param); void StatTask(void* param);
static bool Encrypt(Message& msg,Array& pass);
/*================================ 微网消息 ================================*/
typedef struct{ typedef struct{
byte Retry:2; // 标识位。也可以用来做二级命令 byte Retry:2; // 重发次数。
byte TTL:2; // 路由TTL。最多3次转发 byte TTL:2; // 路由TTL。最多3次转发
byte NoAck:1; // 是否不需要确认包 byte NoAck:1; // 是否不需要确认包
byte Ack:1; // 确认包 byte Ack:1; // 确认包
@ -54,11 +54,11 @@ bool TinyMessage::Read(Stream& ms)
Error = _Error; Error = _Error;
// 代码为0是非法的 // 代码为0是非法的
if(!Code) return false; if(!Code) return false;
// 没有源地址是很不负责任的 // 没有源地址是很不负责任的
if(!Src) return false; if(!Src) return false;
// 源地址和目的地址相同也是非法的 // 源地址和目的地址相同也是非法的
if(Dest == Src) return false; if(Dest == Src) return false;
// 校验剩余长度 // 校验剩余长度
ushort len = Length; ushort len = Length;
@ -132,7 +132,7 @@ bool TinyMessage::Valid() const
debug_printf("Message::Valid Crc Error %04X != Checksum: %04X \r\n", Crc, Checksum); debug_printf("Message::Valid Crc Error %04X != Checksum: %04X \r\n", Crc, Checksum);
#if MSG_DEBUG #if MSG_DEBUG
debug_printf("校验错误指令 "); debug_printf("指令校验错误 ");
Show(); Show();
#endif #endif
@ -155,7 +155,7 @@ void TinyMessage::Show() const
#if MSG_DEBUG #if MSG_DEBUG
assert_ptr(this); assert_ptr(this);
byte flag = *((byte*)&_Code+1); byte flag = *((byte*)&_Code + 1);
msg_printf("0x%02X => 0x%02X Code=0x%02X Flag=0x%02X Seq=0x%02X Retry=%d", Src, Dest, Code, flag, Seq, Retry); msg_printf("0x%02X => 0x%02X Code=0x%02X Flag=0x%02X Seq=0x%02X Retry=%d", Src, Dest, Code, flag, Seq, Retry);
if(flag) if(flag)
@ -190,10 +190,10 @@ TinyMessage TinyMessage::CreateReply() const
return msg; return msg;
} }
/*================================ 微网控制器 ================================*/
// 构造控制器 // 构造控制器
TinyController::TinyController() : Controller() TinyController::TinyController() : Controller()
{ {
_Sequence = 0;
_taskID = 0; _taskID = 0;
Interval = 2; Interval = 2;
Timeout = 200; Timeout = 200;
@ -290,6 +290,19 @@ void ShowMessage(TinyMessage& msg, bool send, ITransport* port)
msg.Show(); msg.Show();
} }
//加密。组网不加密,退网不加密
static bool Encrypt(Message& msg, Array& pass)
{
// 加解密。组网不加密,退网不加密
if(msg.Length > 0 && pass.Length() > 0 && !(msg.Code == 0x01 || msg.Code == 0x02||msg.Code==0x03))
{
Array bs(msg.Data, msg.Length);
RC4::Encrypt(bs, pass);
return true;
}
return false;
}
bool TinyController::Dispatch(Stream& ms, Message* pmsg, void* param) bool TinyController::Dispatch(Stream& ms, Message* pmsg, void* param)
{ {
/*byte* buf = ms.Current(); /*byte* buf = ms.Current();
@ -385,7 +398,7 @@ bool TinyController::Valid(const Message& msg)
if(tmsg.Dest == Address) if(tmsg.Dest == Address)
{ {
ByteArray key(0); ByteArray key(0);
CallblackKey(tmsg.Src, key, Param); CallblackKey(tmsg.Src, key, Param);
if(key.Length() > 0) Encrypt(tmsg, key); if(key.Length() > 0) Encrypt(tmsg, key);
} }
else else
@ -470,15 +483,7 @@ void TinyController::AckResponse(const TinyMessage& msg)
msg_printf(" 失败!\r\n");*/ msg_printf(" 失败!\r\n");*/
} }
uint TinyController::Post(byte dest, byte code, const Array& arr) static byte _Sequence = 0;
{
TinyMessage msg(code);
msg.Dest = dest;
msg.SetData(arr);
return Send(msg);
}
// 发送消息,传输口参数为空时向所有传输口发送消息 // 发送消息,传输口参数为空时向所有传输口发送消息
bool TinyController::Send(Message& msg) bool TinyController::Send(Message& msg)
{ {
@ -491,140 +496,25 @@ bool TinyController::Send(Message& msg)
if(!tmsg.Reply) tmsg.Seq = ++_Sequence; if(!tmsg.Reply) tmsg.Seq = ++_Sequence;
ByteArray key; ByteArray key;
CallblackKey(tmsg.Dest, key, Param); CallblackKey(tmsg.Dest, key, Param);
Encrypt(tmsg,key); if(key.Length() > 0) Encrypt(tmsg, key);
#if MSG_DEBUG
ShowMessage(tmsg, true, Port); ShowMessage(tmsg, true, Port);
//#endif #endif
//return Controller::Send(msg, port);
return Post(tmsg, -1); return Post(tmsg, -1);
} }
//加密。组网不加密,退网不加密 bool TinyController::Reply(Message& msg)
static bool Encrypt(Message& msg, Array& pass)
{ {
// 加解密。组网不加密,退网不加密 auto& tmsg = (TinyMessage&)msg;
if(msg.Length > 0 && pass.Length() > 0 && !(msg.Code == 0x01 || msg.Code == 0x02||msg.Code==0x03))
{
Array bs(msg.Data, msg.Length);
RC4::Encrypt(bs, pass);
return true;
}
return false;
}
void SendTask(void* param) // 回复信息,源地址变成目的地址
{ if(tmsg.Dest == Address && tmsg.Src != Address) tmsg.Dest = tmsg.Src;
assert_ptr(param); msg.Reply = 1;
TinyController* control = (TinyController*)param;
control->Loop();
}
void TinyController::Loop() return Send(msg);
{
TS("TinyController::Loop");
int count = 0;
for(int i=0; i<ArrayLength(_Queue); i++)
{
auto& node = _Queue[i];
if(!node.Using) continue;
// 检查时间。至少发送一次
if(node.Next > 0)
{
ulong now2 = Sys.Ms();
// 下一次发送时间还没到,跳过
if(node.Next > now2) continue;
// 已过期则删除
if(node.Expired < now2)
{
debug_printf("消息过期 Dest=0x%02X Seq=0x%02X Period=%d Times=%d\r\n", node.Data[0], node.Seq, node.Period, node.Times);
node.Using = 0;
continue;
}
}
count++;
node.Times++;
auto f = (TFlags*)&node.Data[3];
f->Retry++;
// 发送消息
Array bs(node.Data, node.Length);
Port->Write(bs);
// 增加发送次数统计
Total.Send++;
// 分组统计
if(Total.Send >= 100)
{
memcpy(&Last, &Total, sizeof(Total));
memset(&Total, 0, sizeof(Total));
}
ulong now = Sys.Ms();
node.LastSend = now;
// 随机延迟。随机数1~5。每次延迟递增
byte rnd = (uint)now % 3;
node.Period = (rnd + 1) * Interval;
//node.Period = Interval;
node.Next = now + node.Period;
//debug_printf("下一次 %dus\r\n", node.Period);
}
if(count == 0) Sys.SetTask(_taskID, false);
}
// 发送消息usTimeout微秒超时时间内如果对方没有响应会重复发送-1表示采用系统默认超时时间Timeout
bool TinyController::Post(TinyMessage& msg, int expire)
{
TS("TinyController::Post");
// 如果没有传输口处于打开状态,则发送失败
if(!Port->Open()) return false;
if(expire < 0) expire = Timeout;
// 需要响应
if(expire <= 0) msg.NoAck = true;
// 如果确定不需要响应则改用Post
if(msg.NoAck || msg.Ack) return Controller::Send(msg);
// 针对Zigbee等不需要Ack确认的通道
if(Timeout < 0) return Controller::Send(msg);
// 准备消息队列
MessageNode* node = NULL;
for(int i=0; i<ArrayLength(_Queue); i++)
{
if(!_Queue[i].Using)
{
node = &_Queue[i];
node->Seq = 0;
node->Using = 1;
break;
}
}
// 队列已满
if(!node) return false;
node->SetMessage(msg);
node->StartTime = Sys.Ms();
node->Next = 0;
node->Expired = Sys.Ms() + expire;
Total.Msg++;
Sys.SetTask(_taskID, true, 0);
return true;
} }
// 广播消息,不等待响应和确认 // 广播消息,不等待响应和确认
@ -643,18 +533,121 @@ bool TinyController::Broadcast(TinyMessage& msg)
ShowMessage(msg, true, Port); ShowMessage(msg, true, Port);
#endif #endif
return Post(msg, 0); if(!Port->Open()) return false;
return Controller::SendInternal(msg);
} }
bool TinyController::Reply(Message& msg) // 放入发送队列,超时之前,如果对方没有响应,会重复发送,-1表示采用系统默认超时时间Timeout
bool TinyController::Post(const TinyMessage& msg, int msTimeout)
{ {
auto& tmsg = (TinyMessage&)msg; TS("TinyController::Post");
// 回复信息,源地址变成目的地址 // 如果没有传输口处于打开状态,则发送失败
if(tmsg.Dest == Address && tmsg.Src != Address) tmsg.Dest = tmsg.Src; if(!Port->Open()) return false;
msg.Reply = 1;
return Send(msg); if(msTimeout < 0) msTimeout = Timeout;
// 如果确定不需要响应则改用Post
if(msTimeout <= 0 || msg.NoAck || msg.Ack) return Controller::SendInternal(msg);
// 针对Zigbee等不需要Ack确认的通道
if(Timeout < 0) return Controller::SendInternal(msg);
// 准备消息队列
MessageNode* node = NULL;
for(int i=0; i<ArrayLength(_Queue); i++)
{
if(!_Queue[i].Using)
{
node = &_Queue[i];
node->Using = 1;
node->Seq = 0;
break;
}
}
// 队列已满
if(!node)
{
debug_printf("TinyController::Post 发送队列已满! \r\n");
return false;
}
node->Set(msg, msTimeout);
Total.Msg++;
Sys.SetTask(_taskID, true, 0);
return true;
}
void SendTask(void* param)
{
assert_ptr(param);
auto control = (TinyController*)param;
control->Loop();
}
void TinyController::Loop()
{
TS("TinyController::Loop");
int count = 0;
for(int i=0; i<ArrayLength(_Queue); i++)
{
auto& node = _Queue[i];
if(!node.Using) continue;
// 检查时间。至少发送一次
if(node.Next > 0)
{
ulong now = Sys.Ms();
// 下一次发送时间还没到,跳过
if(node.Next > now) continue;
// 已过期则删除
if(node.Expired < now)
{
debug_printf("消息过期 Dest=0x%02X Seq=0x%02X Times=%d\r\n", node.Data[0], node.Seq, node.Times);
node.Using = 0;
continue;
}
}
count++;
node.Times++;
// 递增重试次数
auto f = (TFlags*)&node.Data[3];
f->Retry++;
// 发送消息
Port->Write(Array(node.Data, node.Length));
// 增加发送次数统计
Total.Send++;
// 分组统计
if(Total.Send >= 100)
{
memcpy(&Last, &Total, sizeof(Total));
memset(&Total, 0, sizeof(Total));
}
// 计算下一次重发时间
{
ulong now = Sys.Ms();
node.LastSend = now;
// 随机延迟。随机数1~5。每次延迟递增
byte rnd = (uint)now % 3;
node.Next = now + (rnd + 1) * Interval;
}
}
if(count == 0) Sys.SetTask(_taskID, false);
} }
void StatTask(void* param) void StatTask(void* param)
@ -693,19 +686,24 @@ void TinyController::ShowStat() const
#endif #endif
} }
void MessageNode::SetMessage(const TinyMessage& msg) /*================================ 信息节点 ================================*/
void MessageNode::Set(const TinyMessage& msg, int msTimeout)
{ {
Seq = msg.Seq; Seq = msg.Seq;
Period = 0;
Times = 0; Times = 0;
LastSend = 0; LastSend = 0;
StartTime = Sys.Ms();
Expired = StartTime + msTimeout;
Next = 0;
// 注意此时指针位于0而内容长度为缓冲区长度 // 注意此时指针位于0而内容长度为缓冲区长度
Stream ms(Data, ArrayLength(Data)); Stream ms(Data, ArrayLength(Data));
msg.Write(ms); msg.Write(ms);
Length = ms.Position(); Length = ms.Position();
} }
/*================================ 环形队列 ================================*/
RingQueue::RingQueue() RingQueue::RingQueue()
{ {
Index = 0; Index = 0;

View File

@ -10,10 +10,6 @@
// 消息 // 消息
// 头部按照内存布局,但是数据和校验部分不是 // 头部按照内存布局,但是数据和校验部分不是
// 请求 0038-0403-0000-BC4C从0x38发往0广播功能4标识3保留字段用于业务序号0长度0校验0x4CBC小字节序
// 响应 3856-048x-0000-xxxx
// 错误 3856-044x-0000
// 负载 0038-1000-0003-030303-A936从0x38广播功能4长度3负载03-03-03
class TinyMessage : public Message class TinyMessage : public Message
{ {
public: public:
@ -21,7 +17,7 @@ public:
byte Dest; // 目的地址 byte Dest; // 目的地址
byte Src; // 源地址 byte Src; // 源地址
byte _Code; // 功能代码 byte _Code; // 功能代码
byte Retry:2; // 标识位。也可以用来做二级命令 byte Retry:2; // 重发次数。
byte TTL:2; // 路由TTL。最多3次转发 byte TTL:2; // 路由TTL。最多3次转发
byte NoAck:1; // 是否不需要确认包 byte NoAck:1; // 是否不需要确认包
byte Ack:1; // 确认包 byte Ack:1; // 确认包
@ -55,27 +51,26 @@ public:
// 验证消息校验码是否有效 // 验证消息校验码是否有效
virtual bool Valid() const; virtual bool Valid() const;
// 创建当前消息对应的响应消息。设置源地址目的地址、功能代码、序列号、标识位
TinyMessage CreateReply() const; TinyMessage CreateReply() const;
// 显示消息内容 // 显示消息内容
virtual void Show() const; virtual void Show() const;
}; };
class RingQueue;
// 环形队列。记录收到消息的序列号,防止短时间内重复处理消息 // 环形队列。记录收到消息的序列号,防止短时间内重复处理消息
class RingQueue class RingQueue
{ {
public: public:
int Index; int Index;
ushort Arr[32]; ushort Arr[32];
ulong Expired; // 过期时间,微秒 ulong Expired; // 过期时间,微秒
RingQueue(); RingQueue();
void Push(ushort item); void Push(ushort item);
int Find(ushort item) const; int Find(ushort item) const;
bool Check(ushort item); bool Check(ushort item);
}; };
// 统计信息 // 统计信息
@ -102,24 +97,22 @@ public:
byte Using; // 是否在使用 byte Using; // 是否在使用
byte Seq; // 序列号 byte Seq; // 序列号
byte Data[64]; byte Data[64];
uint Length; ushort Length;
uint Period; // 延迟间隔ms。每次逐步递增 ushort Times; // 发送次数
ulong StartTime; // 开始时间ms ulong StartTime; // 开始时间ms
ulong Next; // 下一次重发时间ms ulong Next; // 下一次重发时间ms
ulong Expired; // 过期时间ms ulong Expired; // 过期时间ms
uint Times; // 发送次数
ulong LastSend; // 最后一次发送时间ms ulong LastSend; // 最后一次发送时间ms
void SetMessage(const TinyMessage& msg); void Set(const TinyMessage& msg, int msTimeout);
}; };
// 消息控制器。负责发送消息、接收消息、分发消息 // 消息控制器。负责发送消息、接收消息、分发消息
class TinyController : public Controller class TinyController : public Controller
{ {
private: private:
MessageNode _Queue[4]; // 消息队列。最多允许16个消息同时等待响应 MessageNode _Queue[4]; // 消息队列。最多允许4个消息同时等待响应
uint _Sequence; // 控制器的消息序号
RingQueue _Ring; // 环形队列 RingQueue _Ring; // 环形队列
uint _taskID; // 发送队列任务 uint _taskID; // 发送队列任务
@ -145,18 +138,16 @@ public:
virtual void Open(); virtual void Open();
// 发送消息,传输口参数为空时向所有传输口发送消息 // 发送消息
virtual bool Send(Message& msg); virtual bool Send(Message& msg);
// 发送消息,传输口参数为空时向所有传输口发送消息
uint Post(byte dest, byte code, const Array& arr);
// 把消息放入发送队列usTimeout微秒超时时间内如果对方没有响应会重复发送
bool Post(TinyMessage& msg, int usTimeout = -1);
// 回复对方的请求消息 // 回复对方的请求消息
virtual bool Reply(Message& msg); virtual bool Reply(Message& msg);
// 广播消息,不等待响应和确认 // 广播消息,不等待响应和确认
bool Broadcast(TinyMessage& msg); bool Broadcast(TinyMessage& msg);
// 放入发送队列,超时之前,如果对方没有响应,会重复发送
bool Post(const TinyMessage& msg, int msTimeout = -1);
// 循环处理待发送的消息队列 // 循环处理待发送的消息队列
void Loop(); void Loop();