diff --git a/Board/LinkBoard.cpp b/Board/LinkBoard.cpp new file mode 100644 index 00000000..890f51ab --- /dev/null +++ b/Board/LinkBoard.cpp @@ -0,0 +1,154 @@ +#include "LinkBoard.h" + +#include "Drivers\W5500.h" +#include "Drivers\Esp8266\Esp8266.h" + +LinkBoard::LinkBoard() +{ + Client = nullptr; + + Data = nullptr; + Size = 0; +} + +void* LinkBoard::InitData(void* data, int size) +{ + // 启动信息 + auto hot = &HotConfig::Current(); + hot->Times++; + + data = hot->Next(); + if (hot->Times == 1) + { + Buffer ds(data, size); + ds.Clear(); + ds[0] = size; + } + + Data = data; + Size = size; + +#if DEBUG + debug_printf("数据区[%d]:", hot->Times); + Buffer(Data, Size).Show(true); +#endif + + return data; +} + +// 写入数据区并上报 +void LinkBoard::Write(uint offset, byte data) +{ + auto client = Client; + if (!client) return; + + client->Store.Write(offset, data); + client->ReportAsync(offset, 1); +} + +/******************************** Link ********************************/ + +void LinkBoard::InitClient() +{ + if (Client) return; + + // 初始化配置区 + InitConfig(); + + // 初始化令牌网 + auto tk = LinkConfig::Create("tcp://192.168.0.3:2233"); + + // 创建客户端 + auto tc = LinkClient::CreateFast(Buffer(Data, Size)); + tc->Cfg = tk; + tc->MaxNotActive = 8 * 60 * 1000; + + Client = tc; +} + +void LinkBoard::Register(uint offset, IDataPort& dp) +{ + if (!Client) return; + + auto& ds = Client->Store; + ds.Register(offset, dp); +} + +void LinkBoard::Register(uint offset, uint size, Handler hook) +{ + if (!Client) return; + + auto& ds = Client->Store; + ds.Register(offset, size, hook); +} + +void LinkBoard::OnLongPress(InputPort* port, bool down) +{ + if (down) return; + + debug_printf("Press P%c%d Time=%d ms\r\n", _PIN_NAME(port->_Pin), port->PressTime); + + auto client = Client; + if (!client) return; + + ushort time = port->PressTime; + if (time >= 5000 && time < 10000) + { + client->Reset("按键重置"); + } + else if (time >= 3000) + { + client->Reboot("按键重启"); + Sys.Reboot(1000); + } +} + +NetworkInterface* LinkBoard::Create5500() +{ + debug_printf("\r\nW5500::Create \r\n"); + + auto net = new W5500(Net.Spi, Net.Irq, Net.Reset); + if (!net->Open()) + { + delete net; + return nullptr; + } + + net->SetLed(*Leds[0]); + net->EnableDNS(); + net->EnableDHCP(); + + return net; +} + +NetworkInterface* LinkBoard::Create8266() +{ + debug_printf("\r\nEsp8266::Create \r\n"); + + auto esp = new Esp8266(); + esp->Init(Esp.Com, Esp.Baudrate); + esp->Set(Esp.Power, Esp.Reset, Esp.LowPower); + + // 初次需要指定模式 否则为 Wire + bool join = esp->SSID && *esp->SSID; + if (!join) + { + *esp->SSID = "WSWL"; + *esp->Pass = "12345678"; + + esp->Mode = NetworkType::STA_AP; + esp->WorkMode = NetworkType::STA_AP; + } + + if (!esp->Open()) + { + delete esp; + return nullptr; + } + + esp->SetLed(*Leds[1]); + //Client->Register("SetWiFi", &Esp8266::SetWiFi, esp); + //Client->Register("GetWiFi", &Esp8266::GetWiFi, esp); + + return esp; +} diff --git a/Board/LinkBoard.h b/Board/LinkBoard.h new file mode 100644 index 00000000..f07248ce --- /dev/null +++ b/Board/LinkBoard.h @@ -0,0 +1,48 @@ +#ifndef _LinkBoard_H_ +#define _LinkBoard_H_ + +#include "Net\Socket.h" + +#include "Device\Spi.h" +#include "Device\SerialPort.h" + +#include "BaseBoard.h" + +#include "Link\LinkClient.h" + +// 物联协议板级包基类 +class LinkBoard : public BaseBoard +{ +public: + LinkClient* Client; // 物联客户端 + + LinkBoard(); + + // 设置数据区 + void* InitData(void* data, int size); + // 写入数据区并上报 + void Write(uint offset, byte data); + + typedef bool(*Handler)(uint offset, uint size, bool write); + void Register(uint offset, uint size, Handler hook); + void Register(uint offset, IDataPort& dp); + + void OnLongPress(InputPort* port, bool down); + void Restore(); + + void InitClient(); + + SpiConfig Net; + SerialConfig Esp; + + // 打开以太网W5500 + NetworkInterface* Create5500(); + // 打开Esp8266,作为主控或者纯AP + NetworkInterface* Create8266(); + +private: + void* Data; + int Size; +}; + +#endif diff --git a/Link/LinkClient.cpp b/Link/LinkClient.cpp index dccebc14..101bd0b3 100644 --- a/Link/LinkClient.cpp +++ b/Link/LinkClient.cpp @@ -28,6 +28,10 @@ LinkClient::LinkClient() Delay = 0; MaxNotActive = 0; + _task = 0; + ReportStart = 0; + ReportLength = 0; + assert(!Current, "只能有一个物联客户端实例"); Current = this; } @@ -123,6 +127,8 @@ void LinkClient::LoopTask() Ping(); break; } + + CheckReport(); } uint LinkClient::Dispatch(ITransport* port, Buffer& bs, void* param, void* param2) @@ -397,6 +403,31 @@ void LinkClient::OnPing(LinkMessage& msg) if (serverTime > 1000) ((TTime&)Time).SetTime(serverTime); } +void LinkClient::Reset(const String& reason) +{ + Json js; + js.Add("time", DateTime::Now().TotalSeconds()); + js.Add("reason", reason); + + Invoke("Reset", js); + + debug_printf("设备500ms后重置\r\n"); + + Sys.Sleep(500); + + Config::Current->RemoveAll(); + Sys.Reboot(); +} + +void LinkClient::Reboot(const String& reason) +{ + Json js; + js.Add("time", DateTime::Now().TotalSeconds()); + js.Add("reason", reason); + + Invoke("Reboot", js); +} + void LinkClient::OnRead(LinkMessage& msg) { TS("LinkClient::OnRead"); @@ -441,3 +472,72 @@ void LinkClient::OnWrite(LinkMessage& msg) Reply(js["action"].AsString(), msg.Seq, 0, rs); } + +void LinkClient::Write(int start, const Buffer& bs) +{ + Json js; + js.Add("start", start); + js.Add("data", bs.ToHex()); + + Invoke("Write", js); +} + +void LinkClient::Write(int start, byte dat) +{ + Write(start, Buffer(&dat, 1)); +} + +void LinkClient::ReportAsync(int start, uint length) +{ + if (start<0 || start + (int)length > Store.Data.Length()) + { + debug_printf("布置异步上报数据失败\r\n"); + debug_printf("start=%d len:%d data.len:%d\r\n", start, length, Store.Data.Length()); + return; + } + + ReportStart = start; + ReportLength = length; + + // 延迟上报,期间有其它上报任务到来将会覆盖 + Sys.SetTask(_task, true, 20); +} + +bool LinkClient::CheckReport() +{ + TS("LinkClient::CheckReport"); + + auto offset = ReportStart; + int len = ReportLength; + + if (offset < 0) return false; + + // 检查索引,否则数组越界 + auto& bs = Store.Data; + if (bs.Length() >= offset + len) Write(offset, Buffer(&bs[offset], len)); + + ReportStart = -1; + + return true; +} + +// 快速建立客户端,注册默认Api +LinkClient* LinkClient::CreateFast(const Buffer& store) +{ + auto tc = new LinkClient(); + + /*// 重启 + tc->Register("Gateway/Restart", &LinkClient::InvokeRestart, tc); + // 重置 + tc->Register("Gateway/Reset", &LinkClient::InvokeReset, tc); + // 设置远程地址 + tc->Register("Gateway/SetRemote", &LinkClient::InvokeSetRemote, tc); + // 获取远程配置信息 + tc->Register("Gateway/GetRemote", &LinkClient::InvokeGetRemote, tc); + // 获取所有Invoke命令 + tc->Register("Api/All", &LinkClient::InvokeGetAllApi, tc);*/ + + if (store.Length()) tc->Store.Data.Set(store.GetBuffer(), store.Length()); + + return tc; +} diff --git a/Link/LinkClient.h b/Link/LinkClient.h index 9f715bc9..e098d3f8 100644 --- a/Link/LinkClient.h +++ b/Link/LinkClient.h @@ -3,6 +3,9 @@ #include "Kernel\Sys.h" +#include "Net\ITransport.h" +#include "Net\Socket.h" + #include "Message\DataStore.h" #include "Message\Json.h" @@ -38,6 +41,16 @@ public: bool Invoke(const String& action, const Json& args); bool Reply(const String& action, int seq, int code, const Json& result); + void Read(int start, int size); + void Write(int start, const Buffer& bs); + void Write(int start, byte dat); + + // 异步上传并等待响应,返回实际上传字节数 + int WriteAsync(int start, const Buffer& bs, int msTimeout); + + // 必须满足 start > 0 才可以。 + void ReportAsync(int start, uint length = 1); + // 收到功能消息时触发 //MessageHandler Received; void* Param; @@ -48,6 +61,13 @@ public: // 心跳,用于保持与对方的活动状态 void Ping(); + // 重置并上报 + void Reset(const String& reason); + void Reboot(const String& reason); + + // 快速建立客户端,注册默认Api + static LinkClient* CreateFast(const Buffer& store); + static LinkClient* Current; private: @@ -62,9 +82,12 @@ private: private: uint _task; + int ReportStart; // 下次上报偏移,-1不动 + byte ReportLength; // 下次上报数据长度 void LoopTask(); void CheckNet(); + bool CheckReport(); static uint Dispatch(ITransport* port, Buffer& bs, void* param, void* param2); }; diff --git a/vs/SmartOS.vcxproj b/vs/SmartOS.vcxproj index b6d97819..3705011b 100644 --- a/vs/SmartOS.vcxproj +++ b/vs/SmartOS.vcxproj @@ -38,6 +38,7 @@ + diff --git a/vs/SmartOS.vcxproj.filters b/vs/SmartOS.vcxproj.filters index 1aceecad..aa855150 100644 --- a/vs/SmartOS.vcxproj.filters +++ b/vs/SmartOS.vcxproj.filters @@ -593,5 +593,8 @@ Link + + Board + \ No newline at end of file