SmartOS/TinyNet/TinyClient.cpp

280 lines
5.9 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 "TinyClient.h"
#include "SerialPort.h"
#include "TinyMessage.h"
#include "TokenMessage.h"
bool OnClientReceived(Message& msg, void* param);
void DiscoverTask(void* param);
void PingTask(void* param);
static uint _taskDiscover = 0;
static uint _taskPing = 0;
TinyClient::TinyClient(Controller* control)
{
assert_ptr(control);
_control = control;
Server = 0;
DeviceType = 0;
Password = 0;
LastActive = 0;
_control->Received = OnClientReceived;
_control->Param = this;
Received = NULL;
Param = NULL;
OnDiscover = NULL;
OnPing = NULL;
Switchs = NULL;
Regs = NULL;
}
void TinyClient::Send(Message& msg)
{
_control->Send(msg);
}
void TinyClient::Reply(Message& msg)
{
_control->Reply(msg);
}
bool OnClientReceived(Message& msg, void* param)
{
TinyClient* client = (TinyClient*)param;
assert_ptr(client);
// 消息转发
if(client->Received) return client->Received(msg, client->Param);
return true;
}
// 常用系统级消息
void TinyClient::SetDefault()
{
#if DEBUG
_control->AddTransport(SerialPort::GetMessagePort());
#endif
// 注册消息。每个消息代码对应一个功能函数
_control->Register(1, Discover, this);
_control->Register(2, Ping, this);
_control->Register(3, SysID, this);
_control->Register(4, SysTime, this);
_control->Register(5, SysMode, this);
// 发现服务端的任务
debug_printf("开始寻找服务端 ");
_taskDiscover = Sys.AddTask(DiscoverTask, this, 0, 2000000);
}
// 最后发送Discover消息的ID防止被别人欺骗直接向我发送Discover响应
static byte _lastDiscoverID;
void DiscoverTask(void* param)
{
assert_ptr(param);
TinyClient* client = (TinyClient*)param;
client->Discover();
}
// 发送发现消息,告诉大家我在这
// 格式2字节设备类型 + 20字节系统ID
void TinyClient::Discover()
{
Message* p_msg = _control->Create();
TinyMessage& msg = *(TinyMessage*)p_msg;
msg.Code = 1;
// 发送的广播消息设备类型和系统ID
Stream ms(msg.Data, ArrayLength(msg.Data));
ms.Length = 0;
ms.Write(DeviceType);
ms.Write(Sys.ID, 0, 20);
msg.Length = ms.Length;
_control->Send(msg);
_lastDiscoverID = msg.Sequence;
delete p_msg;
}
// Discover响应
// 格式1字节地址 + 8字节密码
bool TinyClient::Discover(Message& msg, void* param)
{
TinyMessage& tmsg = (TinyMessage&)msg;
// 客户端只处理Discover响应
if(!tmsg.Reply || tmsg.Error) return true;
// 校验不对
if(_lastDiscoverID != tmsg.Sequence) return true;
assert_ptr(param);
TinyClient* client = (TinyClient*)param;
TinyController* ctrl = (TinyController*)client->_control;
// 解析数据
Stream ms(msg.Data, msg.Length);
if(ms.Remain())
ctrl->Address = ms.Read<byte>();
if(ms.Remain() >= 8)
client->Password = ms.Read<ulong>();
// 记住服务端地址
client->Server = tmsg.Src;
// 取消Discover任务
debug_printf("停止寻找服务端 ");
Sys.RemoveTask(_taskDiscover);
_taskDiscover = 0;
// 启动Ping任务
debug_printf("开始Ping服务端 ");
_taskPing = Sys.AddTask(PingTask, client, 0, 5000000);
if(client->OnDiscover) return client->OnDiscover(msg, param);
return true;
}
void PingTask(void* param)
{
assert_ptr(param);
TinyClient* client = (TinyClient*)param;
client->Ping();
}
// Ping指令用于保持与对方的活动状态
void TinyClient::Ping()
{
if(LastActive > 0 && LastActive + 30000000 < Time.Current())
{
// 30秒无法联系服务端可能已经掉线重启Discover任务关闭Ping任务
debug_printf("30秒无法联系服务端可能已经掉线重启Discover任务关闭Ping任务\r\n");
debug_printf("停止Ping服务端 ");
Sys.RemoveTask(_taskPing);
debug_printf("开始寻找服务端 ");
_taskDiscover = Sys.AddTask(DiscoverTask, this, 0, 2000000);
Server = 0;
Password = 0;
return;
}
Message* msg = _control->Create();
msg->Code = 2;
_control->Send(*msg);
delete msg;
if(LastActive == 0) LastActive = Time.Current();
}
bool TinyClient::Ping(Message& msg, void* param)
{
assert_ptr(param);
TinyClient* client = (TinyClient*)param;
TinyMessage& tmsg = (TinyMessage&)msg;
// 忽略响应消息
if(tmsg.Reply)
{
if(tmsg.Src == client->Server) client->LastActive = Time.Current();
return true;
}
debug_printf("Message_Ping Length=%d\r\n", msg.Length);
if(client->OnPing) return client->OnPing(msg, param);
return true;
}
// 系统时间获取与设置
bool TinyClient::SysTime(Message& msg, void* param)
{
TinyMessage& tmsg = (TinyMessage&)msg;
// 忽略响应消息
if(tmsg.Reply) return true;
debug_printf("Message_SysTime Length=%d\r\n", msg.Length);
// 负载数据决定是读时间还是写时间
if(msg.Length >= 8)
{
// 写时间
ulong us = *(ulong*)msg.Data;
Time.SetTime(us);
}
// 读时间
ulong us2 = Time.Current();
msg.Length = 8;
*(ulong*)msg.Data = us2;
return true;
}
bool TinyClient::SysID(Message& msg, void* param)
{
TinyMessage& tmsg = (TinyMessage&)msg;
// 忽略响应消息
if(tmsg.Reply) return true;
debug_printf("Message_SysID Length=%d\r\n", msg.Length);
if(msg.Length == 0)
{
// 12字节ID4字节CPUID4字节设备ID
msg.SetData(Sys.ID, 5 << 2);
}
else
{
// 干脆直接输出Sys前面11个uint
msg.SetData((byte*)&Sys, 11 << 2);
}
return true;
}
bool TinyClient::SysMode(Message& msg, void* param)
{
TinyMessage& tmsg = (TinyMessage&)msg;
// 忽略响应消息
if(tmsg.Reply) return true;
byte mode = 0;
if(msg.Length > 0) mode = msg.Data[0];
debug_printf("Message_SysMode Length=%d Mode=%d\r\n", msg.Length, mode);
switch(mode)
{
case 1: // 系统软重启
Sys.Reset();
break;
}
msg.Length = 1;
msg.Data[0] = 0;
return true;
}