SmartOS/TokenNet/Gateway.cpp

364 lines
7.7 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 20000
bool TokenToTiny(const TokenMessage& msg, TinyMessage& msg2);
void TinyToToken(const TinyMessage& msg, TokenMessage& msg2);
Gateway* Gateway::Current = nullptr;
// 本地网和远程网一起实例化网关服务
Gateway::Gateway()
{
Server = nullptr;
Client = nullptr;
Led = nullptr;
pDevMgmt = nullptr;
Running = false;
}
Gateway::~Gateway()
{
Stop();
delete Server;
Server = nullptr;
delete Client;
Client = nullptr;
}
// 启动网关。挂载本地和远程的消息事件
void Gateway::Start()
{
if (Running) return;
Running = true;
TS("Gateway::Start");
assert(Server, "微网服务端未设置");
assert(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();
pDevMgmt = DevicesManagement::CreateDevMgmt();
// 设备列表服务于Token 保存token的“联系方式”
pDevMgmt->SetTokenClient(Client);
if (pDevMgmt->Length() == 0)
{
// 如果全局设备列表为空则添加一条Addr=1的设备
auto dv = new Device();
dv->Address = 1;
dv->Kind = Sys.Code;
dv->LastTime = Sys.Seconds();
//dv->HardID = Sys.ID;
dv->HardID.Copy(0, Sys.ID, -1);
dv->Name = Sys.Name;
//pDevMgmt->PushDev(dv);
// 标记为永久在线设备
dv->Flag.BitFlag.OnlineAlws = 1;
pDevMgmt->DeviceRequest(DeviceAtions::Register, dv);
// ushort kinds[] = { 0x0201,0x0202,0x0203,0x0431 };
// byte ids[12];
// Buffer bufids(ids, sizeof(ids));
// bufids = Sys.ID;
// byte Addr = Sys.Ms();
//
// for (int i = 0; i < ArrayLength(kinds); i++)
// {
// // 如果全局设备列表为空则添加一条Addr=1的设备
// auto dv2 = new Device();
// dv2->Address = Addr + i;
// dv2->Kind = kinds[i];
// dv2->LastTime = Sys.Seconds();
//
// ids[11] += Sys.Ms();
// dv2->HardID = ids;
// dv2->Name = "测试设备";
//
// //pDevMgmt->PushDev(dv);
// // 标记为永久在线设备
// dv2->Flag.BitFlag.OnlineAlws = 0;
// pDevMgmt->DeviceRequest(DeviceAtions::Register, dv2);
// }
}
Client->Open();
_task = Sys.AddTask(Loop, this, 10000, LOOP_Interval, "设备任务");
Running = true;
Client->Register("Gateway/Study", &Gateway::InvokeStudy, this);
}
// 停止网关。取消本地和远程的消息挂载
void Gateway::Stop()
{
if (!Running) return;
Sys.RemoveTask(_task);
Server->Received = nullptr;
Server->Param = nullptr;
Client->Received = nullptr;
Client->Param = nullptr;
Running = false;
}
// 数据接收中心 TinyServer 上级
bool Gateway::OnLocal(const TinyMessage& msg)
{
TS("Gateway::OnLocal");
// 应用级消息转发
if (msg.Code >= 0x10 && msg.Dest == Server->Cfg->Address)
{
TokenMessage tmsg;
TinyToToken(msg, tmsg);
Client->Send(tmsg);
}
return true;
}
// 数据接收中心 TokenClient 上级
bool Gateway::OnRemote(const TokenMessage& msg)
{
TS("Gateway::OnRemote");
if (msg.Code == 0x20)
{
OnMode(msg);
}
if (msg.Code == 0x02)
{
if (msg.Code == 0x02 && msg.Reply && Client->Token != 0)
{
// 登录以后自动发送设备列表和设备信息
// 遍历发送所有设备信息
pDevMgmt->SendDevicesIDs();
return true;
}
}
// 应用级消息转发
bool applevel = (msg.Code >= 0x10 || msg.Code == 0x05 || msg.Code == 0x06);
if (applevel && !msg.Error && msg.Length <= Server->Control->Port->MaxSize - TinyMessage::MinSize)
{
TinyMessage tmsg;
if (!TokenToTiny(msg, tmsg)) return true;
if (tmsg.Dest == 0x00)tmsg.Dest = pDevMgmt->LocalId;
bool rs = Server->Dispatch(tmsg);
if (!rs) return false;
TokenMessage msg2;
TinyToToken(tmsg, msg2);
//msg2.Show();
return Client->Reply(msg2);
}
return true;
}
// 学习模式 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;
}
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) Buffer(tny.Data, msg.Length - 1) = &msg.Data[1];
//tny.Length = msg.Length - 1;
TokenDataMessage dm;
dm.ReadMessage(msg);
tny.Dest = dm.ID;
auto ms = tny.ToStream();
ms.WriteEncodeInt(dm.Start);
// 不管什么指令 有就写 没就不写
// dm.ReadMessage(msg); 读不到size的时候 size=data.Length 所以 这里不能用size进行判断
if (dm.HasSize)ms.WriteEncodeInt(dm.Size);
if (dm.Data.Length() != 0)ms.Write(dm.Data);
tny.Length = ms.Position();
return true;
}
void TinyToToken(const TinyMessage& msg, TokenMessage& msg2)
{
TS("TinyToToken");
// 处理Reply标记
msg2.Code = msg.Code;
if (msg2.Code == 0x15)msg2.Code = 0x05;
if (msg2.Code == 0x16)msg2.Code = 0x06;
msg2.Reply = msg.Reply;
msg2.Error = msg.Error;
auto ms = msg.ToStream();
TokenDataMessage dm;
//dm.ReadMessage(msg2); // 很显然 什么都读不到
//dm.ID = ms.ReadByte();
dm.ID = msg.Src;
dm.Start = ms.ReadEncodeInt();
// 存在三种情况 云读设备的回复 云写设备的回复 设备上报
// 云读设备的回复 设备上报 没有长度
// 云写设备的回复 不确定
auto isRead = (msg.Code == 0x05); // || msg.Code == 0x15);
if ((!isRead) && msg.Reply)
{
dm.Size = ms.ReadEncodeInt();
}
dm.Data = ByteArray(ms.GetBuffer() + ms.Position(), ms.Remain());
dm.WriteMessage(msg2);
}
Gateway* Gateway::CreateGateway(TokenClient* client, TinyServer* server)
{
debug_printf("\r\nGateway::CreateGateway \r\n");
Gateway* gw = Current;
if (gw)
{
if ((client == nullptr || gw->Client == client) &&
(server == nullptr || gw->Server == server)) return gw;
delete gw;
}
gw = new Gateway();
gw->Client = client;
gw->Server = server;
Current = gw;
return gw;
}
/******************************** invoke 调用********************************/
// 调用学习模式
bool Gateway::InvokeStudy(const Pair& args, Stream& result)
{
uint time;
args.Get("time", time);
SetMode(time);
result.Write((byte)true);
return true;
}
// 设备上线下线报备
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);
}
}
gw->pDevMgmt->MaintainState();
}