控制器提供发送的内层方法,静态消息,不需要修改。而普通的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"
//#define MSG_DEBUG DEBUG
#define MSG_DEBUG 0
#define MSG_DEBUG DEBUG
//#define MSG_DEBUG 0
#if MSG_DEBUG
#define msg_printf debug_printf
#else
@ -158,7 +158,19 @@ bool Controller::OnReceive(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;
@ -170,10 +182,3 @@ bool Controller::Send(Message& msg)
Array bs(ms.GetBuffer(), ms.Position());
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;
void* Param;
protected:
bool SendInternal(const Message& msg);
};
#endif

View File

@ -13,10 +13,10 @@
void SendTask(void* param);
void StatTask(void* param);
static bool Encrypt(Message& msg,Array& pass);
/*================================ 微网消息 ================================*/
typedef struct{
byte Retry:2; // 标识位。也可以用来做二级命令
byte Retry:2; // 重发次数。
byte TTL:2; // 路由TTL。最多3次转发
byte NoAck:1; // 是否不需要确认包
byte Ack:1; // 确认包
@ -132,7 +132,7 @@ bool TinyMessage::Valid() const
debug_printf("Message::Valid Crc Error %04X != Checksum: %04X \r\n", Crc, Checksum);
#if MSG_DEBUG
debug_printf("校验错误指令 ");
debug_printf("指令校验错误 ");
Show();
#endif
@ -190,10 +190,10 @@ TinyMessage TinyMessage::CreateReply() const
return msg;
}
/*================================ 微网控制器 ================================*/
// 构造控制器
TinyController::TinyController() : Controller()
{
_Sequence = 0;
_taskID = 0;
Interval = 2;
Timeout = 200;
@ -290,6 +290,19 @@ void ShowMessage(TinyMessage& msg, bool send, ITransport* port)
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)
{
/*byte* buf = ms.Current();
@ -470,15 +483,7 @@ void TinyController::AckResponse(const TinyMessage& msg)
msg_printf(" 失败!\r\n");*/
}
uint TinyController::Post(byte dest, byte code, const Array& arr)
{
TinyMessage msg(code);
msg.Dest = dest;
msg.SetData(arr);
return Send(msg);
}
static byte _Sequence = 0;
// 发送消息,传输口参数为空时向所有传输口发送消息
bool TinyController::Send(Message& msg)
{
@ -492,139 +497,24 @@ bool TinyController::Send(Message& msg)
ByteArray key;
CallblackKey(tmsg.Dest, key, Param);
Encrypt(tmsg,key);
if(key.Length() > 0) Encrypt(tmsg, key);
#if MSG_DEBUG
ShowMessage(tmsg, true, Port);
//#endif
//return Controller::Send(msg, port);
#endif
return Post(tmsg, -1);
}
//加密。组网不加密,退网不加密
static bool Encrypt(Message& msg, Array& pass)
bool TinyController::Reply(Message& 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;
}
auto& tmsg = (TinyMessage&)msg;
void SendTask(void* param)
{
assert_ptr(param);
TinyController* control = (TinyController*)param;
control->Loop();
}
// 回复信息,源地址变成目的地址
if(tmsg.Dest == Address && tmsg.Src != Address) tmsg.Dest = tmsg.Src;
msg.Reply = 1;
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 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;
return Send(msg);
}
// 广播消息,不等待响应和确认
@ -643,18 +533,121 @@ bool TinyController::Broadcast(TinyMessage& msg)
ShowMessage(msg, true, Port);
#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;
msg.Reply = 1;
// 如果没有传输口处于打开状态,则发送失败
if(!Port->Open()) return false;
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)
@ -693,19 +686,24 @@ void TinyController::ShowStat() const
#endif
}
void MessageNode::SetMessage(const TinyMessage& msg)
/*================================ 信息节点 ================================*/
void MessageNode::Set(const TinyMessage& msg, int msTimeout)
{
Seq = msg.Seq;
Period = 0;
Times = 0;
LastSend = 0;
StartTime = Sys.Ms();
Expired = StartTime + msTimeout;
Next = 0;
// 注意此时指针位于0而内容长度为缓冲区长度
Stream ms(Data, ArrayLength(Data));
msg.Write(ms);
Length = ms.Position();
}
/*================================ 环形队列 ================================*/
RingQueue::RingQueue()
{
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
{
public:
@ -21,7 +17,7 @@ public:
byte Dest; // 目的地址
byte Src; // 源地址
byte _Code; // 功能代码
byte Retry:2; // 标识位。也可以用来做二级命令
byte Retry:2; // 重发次数。
byte TTL:2; // 路由TTL。最多3次转发
byte NoAck:1; // 是否不需要确认包
byte Ack:1; // 确认包
@ -55,14 +51,13 @@ public:
// 验证消息校验码是否有效
virtual bool Valid() const;
// 创建当前消息对应的响应消息。设置源地址目的地址、功能代码、序列号、标识位
TinyMessage CreateReply() const;
// 显示消息内容
virtual void Show() const;
};
class RingQueue;
// 环形队列。记录收到消息的序列号,防止短时间内重复处理消息
class RingQueue
{
@ -102,24 +97,22 @@ public:
byte Using; // 是否在使用
byte Seq; // 序列号
byte Data[64];
uint Length;
uint Period; // 延迟间隔ms。每次逐步递增
ushort Length;
ushort Times; // 发送次数
ulong StartTime; // 开始时间ms
ulong Next; // 下一次重发时间ms
ulong Expired; // 过期时间ms
uint Times; // 发送次数
ulong LastSend; // 最后一次发送时间ms
void SetMessage(const TinyMessage& msg);
void Set(const TinyMessage& msg, int msTimeout);
};
// 消息控制器。负责发送消息、接收消息、分发消息
class TinyController : public Controller
{
private:
MessageNode _Queue[4]; // 消息队列。最多允许16个消息同时等待响应
MessageNode _Queue[4]; // 消息队列。最多允许4个消息同时等待响应
uint _Sequence; // 控制器的消息序号
RingQueue _Ring; // 环形队列
uint _taskID; // 发送队列任务
@ -145,18 +138,16 @@ public:
virtual void Open();
// 发送消息,传输口参数为空时向所有传输口发送消息
// 发送消息
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);
// 广播消息,不等待响应和确认
bool Broadcast(TinyMessage& msg);
// 放入发送队列,超时之前,如果对方没有响应,会重复发送
bool Post(const TinyMessage& msg, int msTimeout = -1);
// 循环处理待发送的消息队列
void Loop();