SmartOS/TinyNet/TinyClient.cpp

404 lines
8.2 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 "Time.h"
#include "Task.h"
#include "Config.h"
#include "TinyClient.h"
#include "JoinMessage.h"
bool OnClientReceived(Message& msg, void* param);
void TinyClientTask(void* param);
/******************************** 初始化和开关 ********************************/
TinyClient::TinyClient(TinyController* control)
{
assert_ptr(control);
Control = control;
Server = 0;
Type = Sys.Code;
LastActive = 0;
Received = NULL;
Param = NULL;
_TaskID = 0;
}
void TinyClient::Open()
{
Control->Received = OnClientReceived;
Control->Param = this;
Control->Open();
TranID = (int)Time.Current();
_TaskID = Sys.AddTask(TinyClientTask, this, 0, 5000000, "客户端服务");
if(Config.Address > 0) Control->Address = Config.Address;
if(Config.Server > 0) Server = Config.Server;
}
void TinyClient::Close()
{
if(_TaskID) Sys.RemoveTask(_TaskID);
Control->Received = NULL;
Control->Param = NULL;
Control->Close();
}
/******************************** 收发中心 ********************************/
bool TinyClient::Send(TinyMessage& msg)
{
assert_param2(this, "令牌客户端未初始化");
assert_param2(Control, "令牌控制器未初始化");
// 未组网时,禁止发其它消息。组网消息通过广播发出,不经过这里
if(!Server) return false;
// 设置网关地址
if(!msg.Dest) msg.Dest = Server;
return Control->Send(msg);
}
bool TinyClient::Reply(TinyMessage& msg)
{
assert_param2(this, "令牌客户端未初始化");
assert_param2(Control, "令牌控制器未初始化");
// 未组网时,禁止发其它消息。组网消息通过广播发出,不经过这里
if(!Server) return false;
return Control->Reply(msg);
}
bool OnClientReceived(Message& msg, void* param)
{
TinyClient* client = (TinyClient*)param;
assert_ptr(client);
client->OnReceive((TinyMessage&)msg);
return true;
}
bool TinyClient::OnReceive(TinyMessage& msg)
{
if(msg.Src == Server) LastActive = Time.Current();
// 不处理来自网关以外的消息
//if(Server == 0 || Server != msg.Dest) return true;
if(Server != 0 && Server != msg.Dest) return true;
switch(msg.Code)
{
case 0x01:
OnJoin(msg);
break;
case 0x02:
OnDisjoin(msg);
break;
case 0x03:
OnPing(msg);
break;
case 0x05:
case 0x15:
OnRead(msg);
break;
case 0x06:
case 0x16:
OnWrite(msg);
break;
}
// 消息转发
if(Received) return Received(msg, Param);
return true;
}
/******************************** 数据区 ********************************/
/*
请求1起始 + 1大小
响应1起始 + N数据
错误1起始
*/
void TinyClient::OnRead(TinyMessage& msg)
{
if(msg.Reply) return;
if(msg.Length < 2) return;
// 起始地址为7位压缩编码整数
Stream ms = msg.ToStream();
uint offset = ms.ReadEncodeInt();
uint len = ms.ReadEncodeInt();
// 重新一个数据流,避免前面的不够
Stream ms2(4 + len);
ms2.WriteEncodeInt(offset);
ByteArray bs(ms2.Current(), len);
int rs = Store.Read(offset, bs);
if(rs < 0)
{
// 出错,使用原来的数据区即可,只需要返回一个起始位置
msg.Error = true;
msg.Length = ms2.Position();
}
else
{
msg.SetData(ms2.GetBuffer(), ms2.Length);
}
Reply(msg);
}
/*
请求1起始 + N数据
响应1起始 + 1大小
错误1起始
*/
void TinyClient::OnWrite(TinyMessage& msg)
{
if(msg.Reply) return;
if(msg.Length < 2) return;
// 起始地址为7位压缩编码整数
Stream ms = msg.ToStream();
uint offset = ms.ReadEncodeInt();
ByteArray bs(ms.Current(), ms.Remain());
int rs = Store.Write(offset, bs);
// 准备响应数据
ms.Length = ms.Position();
if(rs < 0)
msg.Error = true;
else
ms.WriteEncodeInt(rs);
msg.Length = ms.Length;
Reply(msg);
}
void TinyClient::Report(TinyMessage& msg)
{
// 没有服务端时不要上报
if(!Server) return;
Stream ms(msg.Data, ArrayLength(msg._Data));
ms.Write((byte)0x01); // 子功能码
ms.Write((byte)0x00); // 起始地址
ms.Write(Store.Data);
msg.Length = ms.Position();
}
/******************************** 常用系统级消息 ********************************/
void TinyClientTask(void* param)
{
assert_ptr(param);
TinyClient* client = (TinyClient*)param;
if(client->Server == 0)
client->Join();
else
client->Ping();
}
// 发送发现消息,告诉大家我在这
// 格式2设备类型 + N系统ID
void TinyClient::Join()
{
TinyMessage msg;
msg.Code = 1;
// 发送的广播消息设备类型和系统ID
JoinMessage dm;
dm.Kind = Type;
dm.HardID = Sys.ID;
dm.TranID = TranID;
dm.WriteMessage(msg);
dm.Show(true);
Control->Broadcast(msg);
}
// 组网
bool TinyClient::OnJoin(TinyMessage& msg)
{
// 客户端只处理Discover响应
if(!msg.Reply || msg.Error) return true;
// 解析数据
JoinMessage dm;
dm.ReadMessage(msg);
dm.Show(true);
// 校验不对
if(TranID != dm.TranID)
{
debug_printf("发现响应序列号 0x%08X 不等于内部序列号 0x%08X \r\n", dm.TranID, TranID);
//return true;
}
Control->Address = dm.Address;
Password = dm.Password;
// 记住服务端地址
Server = dm.Server;
Config.Channel = dm.Channel;
Config.Speed = dm.Speed == 0 ? 250 : (dm.Speed == 1 ? 1000 : 2000);;
debug_printf("组网成功!由网关 0x%02X 分配得到节点地址 0x%02X ,频道:%d传输速率%dkbps密码", Server, dm.Address, dm.Channel, Config.Speed);
Password.Show(true);
// 取消Join任务启动Ping任务
Task* task = Scheduler[_TaskID];
ushort time = Config.PingTime;
if(time < 5) time = 5;
task->Period = time * 1000000;
// 组网成功更新一次最后活跃时间
LastActive = Time.Current();
return true;
}
// 离网
bool TinyClient::OnDisjoin(TinyMessage& msg)
{
return true;
}
// 心跳
void TinyClient::Ping()
{
ushort off = Config.OfflineTime;
if(off < 10) off = 10;
if(LastActive > 0 && LastActive + off * 1000000 < Time.Current())
{
if(Server == 0) return;
debug_printf("%d 秒无法联系服务端可能已经掉线重启Join任务关闭Ping任务\r\n", off);
Task* task = Scheduler[_TaskID];
task->Period = 5000000;
Server = 0;
Password = 0;
return;
}
TinyMessage msg;
msg.Code = 2;
// 没事的时候心跳指令承载0x01子功能码作为数据上报
Report(msg);
Send(msg);
if(LastActive == 0) LastActive = Time.Current();
}
bool TinyClient::OnPing(TinyMessage& msg)
{
// 仅处理来自网关的消息
if(Server == 0 || Server != msg.Dest) return true;
// 忽略响应消息
if(msg.Reply)
{
if(msg.Src == Server) LastActive = Time.Current();
return true;
}
debug_printf("TinyClient::OnPing Length=%d\r\n", msg.Length);
return true;
}
/*
// 系统时间获取与设置
bool TinyClient::SysTime(Message& msg, void* param)
{
// 忽略响应消息
if(msg.Reply) return true;
debug_printf("Message_SysTime Length=%d\r\n", msg.Length);
// 负载数据决定是读时间还是写时间
ByteArray bs(msg.Data, msg.Length);
if(msg.Length >= 8)
{
// 写时间
ulong us = bs.ToUInt64();
Time.SetTime(us);
}
// 读时间
ulong us2 = Time.Current();
msg.Length = 8;
bs.Write(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;
}*/