SmartOS/TokenNet/Gateway.cpp

557 lines
11 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "Gateway.h"
#include "Config.h"
#include "Security\MD5.h"
#include "Security\Crc.h"
// 循环间隔
#define LOOP_Interval 10000
bool TokenToTiny(const TokenMessage& msg, TinyMessage& msg2);
void TinyToToken(const TinyMessage& msg, TokenMessage& msg2);
Gateway* Gateway::Current = NULL;
// 本地网和远程网一起实例化网关服务
Gateway::Gateway()
{
Server = NULL;
Client = NULL;
Led = NULL;
Running = false;
}
Gateway::~Gateway()
{
Stop();
delete Server;
Server = NULL;
delete Client;
Client = NULL;
}
// 启动网关。挂载本地和远程的消息事件
void Gateway::Start()
{
if(Running) return;
TS("Gateway::Start");
assert_param2(Server, "微网服务端未设置");
assert_param2(Client, "令牌客户端未设置");
Server->Received = [](void* s, Message& msg, void* p){ return ((Gateway*)p)->OnLocal((TinyMessage&)msg); };
Server->Param = this;
Client->Received = [](void* s, Message& msg, void* p){ return ((Gateway*)p)->OnRemote((TokenMessage&)msg); };
Client->Param = this;
debug_printf("\r\nGateway::Start \r\n");
Server->Start();
// 添加网关这一条设备信息
if(Server->Devices.Length() == 0)
{
auto dv = new Device();
dv->Address = Server->Cfg->Address;
dv->Kind = Sys.Code;
dv->LastTime = Sys.Seconds();
//dv->SetHardID(Array(Sys.ID, 16));
//dv->SetName(Array(Sys.Name, 0));
dv->HardID = Sys.ID;
dv->Name = Sys.Name;
Server->Devices.Push(dv);
Server->SaveDevices();
}
Client->Open();
_task = Sys.AddTask(Loop, this, 10000, LOOP_Interval, "设备任务");
Running = true;
}
// 停止网关。取消本地和远程的消息挂载
void Gateway::Stop()
{
if(!Running) return;
Sys.RemoveTask(_task);
Server->Received = NULL;
Server->Param = NULL;
Client->Received = NULL;
Client->Param = NULL;
Running = false;
}
// 数据接收中心
bool Gateway::OnLocal(const TinyMessage& msg)
{
TS("Gateway::OnLocal");
auto dv = Server->Current;
if(dv)
{
switch(msg.Code)
{
case 0x01:
DeviceRequest(DeviceAtions::Register, dv);
DeviceRequest(DeviceAtions::Online, dv);
break;
case 0x02:
DeviceRequest(DeviceAtions::Delete, dv);
break;
}
}
// 应用级消息转发
if(msg.Code >= 0x10 && msg.Dest == Server->Cfg->Address)
{
TokenMessage tmsg;
TinyToToken(msg, tmsg);
Client->Send(tmsg);
}
return true;
}
bool Gateway::OnRemote(const TokenMessage& msg)
{
TS("Gateway::OnRemote");
switch(msg.Code)
{
case 0x02:
// 登录以后自动发送设备列表和设备信息
if(msg.Reply && Client->Token != 0)
{
// 遍历发送所有设备信息
SendDevices(DeviceAtions::List, NULL);
}
break;
case 0x20:
return OnMode(msg);
case 0x21:
return DeviceProcess(msg);
}
// 应用级消息转发
if(msg.Code >= 0x10 && !msg.Error && msg.Length <= Server->Control->Port->MaxSize - TinyMessage::MinSize)
{
//debug_printf("Gateway::Remote ");
//msg.Show();
TinyMessage tmsg;
if(!TokenToTiny(msg, tmsg)) return true;
bool rs = Server->Dispatch(tmsg);
if(!rs) return false;
TokenMessage msg2;
TinyToToken(tmsg, msg2);
//msg2.Show();
return Client->Reply(msg2);
}
return true;
}
// 设备列表 0x21
bool Gateway::SendDevices(DeviceAtions act, const Device* dv)
{
TS("Gateway::SendDevices");
if(Client->Status < 2) return false;
TokenMessage msg;
msg.Code = 0x21;
int count = 0;
int len = Server->Devices.Length();
for(int i = 0;i < len;i++)
{
if(Server->Devices[i] == NULL) continue;
count++;
}
if(dv) count = 1;
byte buf[1500]; // 1024 字节只能承载 23条数据udp最大能承载1514字节
MemoryStream ms(buf, ArrayLength(buf));
//MemoryStream ms(1536);
ms.Write((byte)act);
ms.Write((byte)count);
if(len > 0)
{
if(dv)
dv->WriteMessage(ms);
else
{
for(int i=0; i<len; i++)
{
auto dv1 = Server->Devices[i];
if(dv1 == NULL ) continue;
dv1->WriteMessage(ms);
}
}
}
msg.Length = ms.Position();
msg.Data = ms.GetBuffer();
#if DEBUG
switch(act)
{
case DeviceAtions::List:
debug_printf("发送设备列表 共%d个\r\n", count);
break;
case DeviceAtions::Online:
debug_printf("节点上线 ID=0x%02X \t", dv->Address);
break;
case DeviceAtions::Offline:
debug_printf("节点下线 ID=0x%02X \t", dv->Address);
break;
default: break;
}
#endif
if(act == DeviceAtions::List)
return Client->Reply(msg);
else
return Client->Send(msg);
}
void Gateway::SendDevicesIDs()
{
TokenMessage msg;
msg.Code = 0x21;
auto act = DeviceAtions::ListIDs;
MemoryStream ms;
ms.Write((byte)act);
byte len = Server->Devices.Length();
//先确认真正的设备有多少个
for(int i = 0; i < len; i++)
{
auto dv =Server->Devices[i];
if(!dv) continue;
ms.Write(dv->Address);
}
msg.Length = ms.Position();
msg.Data = ms.GetBuffer();
Client->Send(msg);
}
// 学习模式 0x20
void Gateway::SetMode(uint time)
{
TS("Gateway::SetMode");
Server->Study = time > 0;
// 定时退出学习模式
_Study = time;
// 设定小灯快闪时间,单位毫秒
if(Led) Led->Write(time ? time * 1000 : 100);
if(time)
debug_printf("进入 学习模式 %d 秒\r\n", time);
else
debug_printf("退出 学习模式\r\n");
TokenMessage msg;
msg.Code = 0x20;
msg.Length = 1;
msg.Data[0] = time;
Client->Reply(msg);
}
// 获取学习模式 返回sStudy
uint Gateway::GetMode()
{
return _Study;
}
// 清空
void Gateway::Clear()
{
TS("Gateway::Clear()");
TokenMessage msg;
msg.Code = 0x35;
msg.Length = 1;
msg.Data[0] = 0;
Client->Reply(msg);
}
bool Gateway::OnMode(const Message& msg)
{
msg.Show();
TS("Gateway::OnMode");
int time = 30;
if(msg.Length > 0) time = msg.Data[0];
SetMode(time);
return true;
}
// 节点消息处理 0x21
void Gateway::DeviceRequest(DeviceAtions act, const Device* dv)
{
TS("Gateway::DeviceRequest");
if(Client->Status < 2) return;
byte id = dv->Address;
switch(act)
{
case DeviceAtions::List:
SendDevices(act, dv);
return;
case DeviceAtions::Update:
SendDevices(act, dv);
return;
case DeviceAtions::Register:
debug_printf("节点注册入网 ID=0x%02X\r\n", id);
SendDevices(act, dv);
return;
case DeviceAtions::Online:
debug_printf("节点上线 ID=0x%02X\r\n", id);
break;
case DeviceAtions::Offline:
debug_printf("节点离线 ID=0x%02X\r\n", id);
break;
case DeviceAtions::Delete:
{
debug_printf("节点删除~~ ID=0x%02X\r\n", id);
auto dv = Server->FindDevice(id);
if(dv == NULL) return;
Server->DeleteDevice(id);
break;
}
default:
debug_printf("无法识别的节点操作 Act=%d ID=0x%02X\r\n", (byte)act, id);
break;
}
TokenMessage rs;
rs.Code = 0x21;
rs.Length = 2;
rs.Data[0] = (byte)act;
rs.Data[1] = id;
Client->Send(rs);
}
bool Gateway::DeviceProcess(const Message& msg)
{
// 仅处理来自云端的请求
if(msg.Reply) return false;
TS("Gateway::DeviceProcess");
auto act = (DeviceAtions)msg.Data[0];
byte id = msg.Data[1];
TokenMessage rs;
rs.Code = 0x21;
rs.Length = 2;
rs.Data[0] = (byte)act;
rs.Data[1] = id;
switch(act)
{
case DeviceAtions::List:
{
SendDevices(act, NULL);
return true;
}
case DeviceAtions::Update:
{
// 云端要更新网关设备信息
auto dv = Server->FindDevice(id);
if(!dv)
{
rs.Error = true;
}
else
{
auto ms = msg.ToStream();
ms.Seek(2);
dv->ReadMessage(ms);
Server->SaveDevices();
}
Client->Reply(rs);
}
break;
case DeviceAtions::Register:
break;
case DeviceAtions::Online:
break;
case DeviceAtions::Offline:
break;
case DeviceAtions::Delete:
debug_printf("节~~1点删除 ID=0x%02X\r\n", id);
{
auto dv = Server->FindDevice(id);
if(dv == NULL)
{
rs.Error = true;
Client->Reply(rs);
return false;
}
ushort crc = Crc::Hash16(dv->HardID);
Server->Disjoin(id);
Sys.Sleep(300);
Server->Disjoin(id);
Sys.Sleep(300);
Server->Disjoin(id);
// 云端要删除本地设备信息
bool flag = Server->DeleteDevice(id);
rs.Error = !flag;
Client->Reply(rs);
}
break;
default:
debug_printf("无法识别的节点操作 Act=%d ID=0x%02X\r\n", (byte)act, id);
break;
}
return true;
}
bool TokenToTiny(const TokenMessage& msg, TinyMessage& tny)
{
if(msg.Length == 0) return false;
TS("TokenToTiny");
tny.Code = msg.Code;
// 处理Reply标记
tny.Reply = msg.Reply;
tny.Error = msg.Error;
// 第一个字节是节点设备地址
tny.Dest = msg.Data[0];
if(msg.Length > 1) memcpy(tny.Data, &msg.Data[1], msg.Length - 1);
tny.Length = msg.Length - 1;
return true;
}
void TinyToToken(const TinyMessage& msg, TokenMessage& msg2)
{
TS("TinyToToken");
// 处理Reply标记
msg2.Code = msg.Code;
msg2.Reply = msg.Reply;
msg2.Error = msg.Error;
// 第一个字节是节点设备地址
msg2.Data[0] = ((TinyMessage&)msg).Src;
if(msg.Length > 0) memcpy(&msg2.Data[1], msg.Data, msg.Length);
msg2.Length = 1 + msg.Length;
}
Gateway* Gateway::CreateGateway(TokenClient* client, TinyServer* server)
{
debug_printf("\r\nGateway::CreateGateway \r\n");
Gateway* gw = Current;
if(gw)
{
if( (client == NULL || gw->Client == client) &&
(server == NULL || gw->Server == server)) return gw;
delete gw;
}
gw = new Gateway();
gw->Client = client;
gw->Server = server;
Current = gw;
return gw;
}
// 设备上线下线报备
void Gateway::Loop(void* param)
{
TS("Gateway::Loop");
auto gw = (Gateway*)param;
// 检测自动退出学习模式
if(gw->_Study)
{
gw->_Study -= LOOP_Interval / 1000;
if(gw->_Study <= 0)
{
gw->_Study = 0;
gw->SetMode(0);
}
}
// 未登录不执行任何逻辑
if(gw->Client->Token == 0) return;
gw->SendDevicesIDs();
auto now = Sys.Seconds();
byte len = gw->Server->Devices.Length();
for(int i = 0; i < len; i++)
{
auto dv = gw->Server->Devices[i];
if(!dv) continue;
ushort time = dv->OfflineTime ? dv->OfflineTime :60;
// 特殊处理网关自身
if(dv->Address == gw->Server->Cfg->Address) dv->LastTime = now;
if(dv->LastTime + time < now)
{ // 下线
if(dv->Logined)
{
//debug_printf("设备最后活跃时间:%d,系统当前时间:%d,离线阈值:%d\r\n",dv->LastTime,now,time);
gw->DeviceRequest(DeviceAtions::Offline, dv);
dv->Logined = false;
}
}
else
{ // 上线
if(!dv->Logined)
{
gw->DeviceRequest(DeviceAtions::Online, dv);
dv->Logined = true;
}
}
}
}