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