Esp8266驱动独立目录,每个类一对源码文件
This commit is contained in:
parent
a745365404
commit
323c04a457
|
@ -4,6 +4,10 @@
|
||||||
#include "Message\DataStore.h"
|
#include "Message\DataStore.h"
|
||||||
|
|
||||||
#include "Esp8266.h"
|
#include "Esp8266.h"
|
||||||
|
#include "EspTcp.h"
|
||||||
|
#include "EspUdp.h"
|
||||||
|
#include "WaitExpect.h"
|
||||||
|
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
|
|
||||||
#define NET_DEBUG DEBUG
|
#define NET_DEBUG DEBUG
|
||||||
|
@ -14,23 +18,6 @@
|
||||||
#define net_printf(format, ...)
|
#define net_printf(format, ...)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// 等待
|
|
||||||
class WaitExpect
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
const String* Command = nullptr;
|
|
||||||
String* Result = nullptr;
|
|
||||||
cstring Key1 = nullptr;
|
|
||||||
cstring Key2 = nullptr;
|
|
||||||
|
|
||||||
bool Capture = true; // 是否捕获所有
|
|
||||||
//bool OK = false;
|
|
||||||
|
|
||||||
bool Wait(int msTimeout);
|
|
||||||
uint Parse(const Buffer& bs);
|
|
||||||
uint FindKey(const String& str);
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
注意事项
|
注意事项
|
||||||
1、设置模式AT+CWMODE需要重启后生效AT+RST
|
1、设置模式AT+CWMODE需要重启后生效AT+RST
|
||||||
|
@ -39,61 +26,6 @@ public:
|
||||||
4、单连接模式,多连接模式 收发数据有参数个数区别
|
4、单连接模式,多连接模式 收发数据有参数个数区别
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/******************************** 内部Tcp/Udp ********************************/
|
|
||||||
class EspSocket : public Object, public ITransport, public ISocket
|
|
||||||
{
|
|
||||||
protected:
|
|
||||||
Esp8266& _Host;
|
|
||||||
byte _Index;
|
|
||||||
int _Error;
|
|
||||||
|
|
||||||
public:
|
|
||||||
EspSocket(Esp8266& host, ProtocolType protocol, byte idx);
|
|
||||||
virtual ~EspSocket();
|
|
||||||
|
|
||||||
// 打开Socket
|
|
||||||
virtual bool OnOpen();
|
|
||||||
virtual void OnClose();
|
|
||||||
|
|
||||||
//// 应用配置,修改远程地址和端口
|
|
||||||
//virtual bool Change(const String& remote, ushort port);
|
|
||||||
|
|
||||||
virtual bool OnWrite(const Buffer& bs);
|
|
||||||
virtual uint OnRead(Buffer& bs);
|
|
||||||
|
|
||||||
// 发送数据
|
|
||||||
virtual bool Send(const Buffer& bs);
|
|
||||||
// 接收数据
|
|
||||||
virtual uint Receive(Buffer& bs);
|
|
||||||
|
|
||||||
// 收到数据
|
|
||||||
virtual void OnProcess(const Buffer& bs, const IPEndPoint& remote);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
bool SendData(const String& cmd, const Buffer& bs);
|
|
||||||
};
|
|
||||||
|
|
||||||
class EspTcp : public EspSocket
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
EspTcp(Esp8266& host, byte idx);
|
|
||||||
|
|
||||||
virtual String& ToStr(String& str) const { return str + "Tcp_" + Local.Port; }
|
|
||||||
};
|
|
||||||
|
|
||||||
class EspUdp : public EspSocket
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
EspUdp(Esp8266& host, byte idx);
|
|
||||||
|
|
||||||
virtual bool SendTo(const Buffer& bs, const IPEndPoint& remote);
|
|
||||||
|
|
||||||
virtual String& ToStr(String& str) const { return str + "Udp_" + Local.Port; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
virtual bool OnWriteEx(const Buffer& bs, const void* opt);
|
|
||||||
};
|
|
||||||
|
|
||||||
/******************************** Esp8266 ********************************/
|
/******************************** Esp8266 ********************************/
|
||||||
|
|
||||||
Esp8266::Esp8266(ITransport* port, Pin power, Pin rst)
|
Esp8266::Esp8266(ITransport* port, Pin power, Pin rst)
|
||||||
|
@ -294,10 +226,6 @@ bool Esp8266::EnableDNS() { return true; }
|
||||||
// 启用DHCP
|
// 启用DHCP
|
||||||
bool Esp8266::EnableDHCP() { Mode = SocketMode::STA_AP; return true;/* return SetDHCP(SocketMode::Both, true); */}
|
bool Esp8266::EnableDHCP() { Mode = SocketMode::STA_AP; return true;/* return SetDHCP(SocketMode::Both, true); */}
|
||||||
|
|
||||||
#if NET_DEBUG
|
|
||||||
static bool EnableLog = true;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// 发送指令,在超时时间内等待返回期望字符串,然后返回内容
|
// 发送指令,在超时时间内等待返回期望字符串,然后返回内容
|
||||||
String Esp8266::Send(const String& cmd, cstring expect, cstring expect2, uint msTimeout)
|
String Esp8266::Send(const String& cmd, cstring expect, cstring expect2, uint msTimeout)
|
||||||
{
|
{
|
||||||
|
@ -337,6 +265,10 @@ String Esp8266::Send(const String& cmd, cstring expect, cstring expect2, uint ms
|
||||||
|
|
||||||
_Expect = &we;
|
_Expect = &we;
|
||||||
|
|
||||||
|
#if NET_DEBUG
|
||||||
|
bool EnableLog = true;
|
||||||
|
#endif
|
||||||
|
|
||||||
if(cmd)
|
if(cmd)
|
||||||
{
|
{
|
||||||
// 设定小灯快闪时间,单位毫秒
|
// 设定小灯快闪时间,单位毫秒
|
||||||
|
@ -346,7 +278,8 @@ String Esp8266::Send(const String& cmd, cstring expect, cstring expect2, uint ms
|
||||||
|
|
||||||
#if NET_DEBUG
|
#if NET_DEBUG
|
||||||
// 只有AT指令显示日志
|
// 只有AT指令显示日志
|
||||||
if(EnableLog && cmd.StartsWith("AT"))
|
if(!cmd.StartsWith("AT") || expect && expect[0] == '<') EnableLog = false;
|
||||||
|
if(EnableLog)
|
||||||
{
|
{
|
||||||
we.Command = &cmd;
|
we.Command = &cmd;
|
||||||
net_printf("%d=> ", tid);
|
net_printf("%d=> ", tid);
|
||||||
|
@ -946,283 +879,3 @@ bool Esp8266::SetIPD(bool enable)
|
||||||
String cmd = "AT+CIPDINFO=";
|
String cmd = "AT+CIPDINFO=";
|
||||||
return SendCmd(cmd + (enable ? '1' : '0'));
|
return SendCmd(cmd + (enable ? '1' : '0'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************************** Socket ********************************/
|
|
||||||
|
|
||||||
EspSocket::EspSocket(Esp8266& host, ProtocolType protocol, byte idx)
|
|
||||||
: _Host(host)
|
|
||||||
{
|
|
||||||
_Index = idx;
|
|
||||||
_Error = 0;
|
|
||||||
|
|
||||||
Host = &host;
|
|
||||||
Protocol = protocol;
|
|
||||||
}
|
|
||||||
|
|
||||||
EspSocket::~EspSocket()
|
|
||||||
{
|
|
||||||
Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool EspSocket::OnOpen()
|
|
||||||
{
|
|
||||||
// 确保宿主打开
|
|
||||||
if(!_Host.Open()) return false;
|
|
||||||
|
|
||||||
// 如果没有指定本地端口,则使用累加端口
|
|
||||||
if(!Local.Port)
|
|
||||||
{
|
|
||||||
// 累加端口
|
|
||||||
static ushort g_port = 1024;
|
|
||||||
if(g_port < 1024) g_port = 1024;
|
|
||||||
Local.Port = g_port++;
|
|
||||||
}
|
|
||||||
Local.Address = _Host.IP;
|
|
||||||
|
|
||||||
_Host.SetMux(true);
|
|
||||||
|
|
||||||
#if DEBUG
|
|
||||||
debug_printf("%s::Open ", Protocol == ProtocolType::Tcp ? "Tcp" : "Udp");
|
|
||||||
Local.Show(false);
|
|
||||||
debug_printf(" => ");
|
|
||||||
Server.Show(false);
|
|
||||||
debug_printf(" ");
|
|
||||||
Remote.Show(true);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
String cmd = "AT+CIPSTART=";
|
|
||||||
cmd = cmd + _Index + ",";
|
|
||||||
|
|
||||||
if(Protocol == ProtocolType::Udp)
|
|
||||||
cmd += "\"UDP\"";
|
|
||||||
else if(Protocol == ProtocolType::Tcp)
|
|
||||||
cmd += "\"TCP\"";
|
|
||||||
|
|
||||||
auto rm = Server;
|
|
||||||
if(!rm) rm = Remote.Address.ToString();
|
|
||||||
|
|
||||||
// 设置端口目的(远程)IP地址和端口号
|
|
||||||
cmd = cmd + ",\"" + rm + "\"," + Remote.Port;
|
|
||||||
// 设置自己的端口号
|
|
||||||
if(Local.Port) cmd = cmd + ',' + Local.Port;
|
|
||||||
// UDP传输属性。0,收到数据不改变远端目标;1,收到数据改变一次远端目标;2,收到数据改变远端目标
|
|
||||||
|
|
||||||
/*if(Remote.Address == IPAddress::Broadcast())
|
|
||||||
cmd += ",2";
|
|
||||||
else*/
|
|
||||||
cmd += ",0";
|
|
||||||
|
|
||||||
// 打开Socket。有OK/ERROR/ALREADY CONNECTED三种
|
|
||||||
auto rt = _Host.Send(cmd + "\r\n", "OK", "ERROR", 1600);
|
|
||||||
if(!rt.Contains("OK") && ! rt.Contains("ALREADY CONNECTED"))
|
|
||||||
{
|
|
||||||
debug_printf("协议 %d, %d 打开失败 \r\n", Protocol, Remote.Port);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 清空一次缓冲区
|
|
||||||
/*cmd = "AT+CIPBUFRESET=";
|
|
||||||
_Host.SendCmd(cmd + _Index);*/
|
|
||||||
_Error = 0;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void EspSocket::OnClose()
|
|
||||||
{
|
|
||||||
String cmd = "AT+CIPCLOSE=";
|
|
||||||
cmd += _Index;
|
|
||||||
cmd += "\r\n";
|
|
||||||
|
|
||||||
_Host.SendCmd(cmd, 1600);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 接收数据
|
|
||||||
uint EspSocket::Receive(Buffer& bs)
|
|
||||||
{
|
|
||||||
if(!Open()) return 0;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 发送数据
|
|
||||||
bool EspSocket::Send(const Buffer& bs)
|
|
||||||
{
|
|
||||||
if(!Open()) return false;
|
|
||||||
|
|
||||||
String cmd = "AT+CIPSEND=";
|
|
||||||
cmd = cmd + _Index + ',' + bs.Length() + "\r\n";
|
|
||||||
|
|
||||||
return SendData(cmd, bs);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool EspSocket::SendData(const String& cmd, const Buffer& bs)
|
|
||||||
{
|
|
||||||
#if NET_DEBUG
|
|
||||||
EnableLog = false;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// 重发3次AT指令,避免busy
|
|
||||||
int i = 0;
|
|
||||||
for(i=0; i<3; i++)
|
|
||||||
{
|
|
||||||
//auto rt = _Host.Send(cmd, ">", "OK", 1600);
|
|
||||||
// 不能等待OK,而应该等待>,因为发送期间可能给别的指令碰撞
|
|
||||||
auto rt = _Host.Send(cmd, ">", "ERROR", 1600);
|
|
||||||
if(rt.Contains(">")) break;
|
|
||||||
}
|
|
||||||
if(i<3 && _Host.Send(bs.AsString(), "SEND OK", "ERROR", 1600).Contains("SEND OK"))
|
|
||||||
{
|
|
||||||
#if NET_DEBUG
|
|
||||||
EnableLog = true;
|
|
||||||
#endif
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
#if NET_DEBUG
|
|
||||||
EnableLog = true;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// 发送失败,关闭链接,下一次重新打开
|
|
||||||
if(++_Error >= 10)
|
|
||||||
{
|
|
||||||
_Error = 0;
|
|
||||||
|
|
||||||
Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool EspSocket::OnWrite(const Buffer& bs) { return Send(bs); }
|
|
||||||
uint EspSocket::OnRead(Buffer& bs) { return Receive(bs); }
|
|
||||||
|
|
||||||
// 收到数据
|
|
||||||
void EspSocket::OnProcess(const Buffer& bs, const IPEndPoint& remote)
|
|
||||||
{
|
|
||||||
OnReceive((Buffer&)bs, (void*)&remote);
|
|
||||||
}
|
|
||||||
|
|
||||||
/******************************** Tcp ********************************/
|
|
||||||
|
|
||||||
EspTcp::EspTcp(Esp8266& host, byte idx)
|
|
||||||
: EspSocket(host, ProtocolType::Tcp, idx)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/******************************** Udp ********************************/
|
|
||||||
|
|
||||||
EspUdp::EspUdp(Esp8266& host, byte idx)
|
|
||||||
: EspSocket(host, ProtocolType::Udp, idx)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
bool EspUdp::SendTo(const Buffer& bs, const IPEndPoint& remote)
|
|
||||||
{
|
|
||||||
//!!! ESP8266有BUG,收到数据后,远程地址还是乱了,所以这里的远程地址跟实际可能不一致
|
|
||||||
if(remote == Remote) return Send(bs);
|
|
||||||
|
|
||||||
if(!Open()) return false;
|
|
||||||
|
|
||||||
String cmd = "AT+CIPSEND=";
|
|
||||||
cmd = cmd + _Index + ',' + bs.Length();
|
|
||||||
|
|
||||||
// 加上远程IP和端口
|
|
||||||
cmd = cmd + ",\"" + remote.Address + "\"";
|
|
||||||
cmd = cmd + ',' + remote.Port;
|
|
||||||
cmd += "\r\n";
|
|
||||||
|
|
||||||
return SendData(cmd, bs);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool EspUdp::OnWriteEx(const Buffer& bs, const void* opt)
|
|
||||||
{
|
|
||||||
auto ep = (IPEndPoint*)opt;
|
|
||||||
if(!ep) return OnWrite(bs);
|
|
||||||
|
|
||||||
return SendTo(bs, *ep);
|
|
||||||
}
|
|
||||||
|
|
||||||
/******************************** WaitExpect ********************************/
|
|
||||||
|
|
||||||
bool WaitExpect::Wait(int msTimeout)
|
|
||||||
{
|
|
||||||
// 提前等待一会,再开始轮询,专门为了加快命中快速响应的指令
|
|
||||||
Sys.Sleep(40);
|
|
||||||
if(!Result) return true;
|
|
||||||
|
|
||||||
// 等待收到数据
|
|
||||||
TimeWheel tw(0, msTimeout - 40);
|
|
||||||
// 默认检查间隔200ms,如果超时时间大于1000ms,则以四分之一为检查间隔
|
|
||||||
// ESP8266串口任务平均时间为150ms左右,为了避免接收指令任务里面发送指令时等不到OK,需要加大检查间隔
|
|
||||||
tw.Sleep = 200;
|
|
||||||
if(msTimeout > 1000) tw.Sleep = msTimeout >> 2;
|
|
||||||
if(tw.Sleep > 1000) tw.Sleep = 1000;
|
|
||||||
|
|
||||||
while(Result)
|
|
||||||
{
|
|
||||||
if(tw.Expired()) return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint WaitExpect::Parse(const Buffer& bs)
|
|
||||||
{
|
|
||||||
if(bs.Length() == 0 || !Result) return 0;
|
|
||||||
|
|
||||||
TS("WaitExpect::Parse");
|
|
||||||
|
|
||||||
// 适配任意关键字后,也就是收到了成功或失败,通知业务层已结束
|
|
||||||
auto s = (const String)bs.AsString();
|
|
||||||
int p = FindKey(s);
|
|
||||||
auto& rs= *Result;
|
|
||||||
|
|
||||||
// 捕获所有
|
|
||||||
if(Capture)
|
|
||||||
{
|
|
||||||
if(p > 0)
|
|
||||||
rs += bs.Sub(0, p).AsString();
|
|
||||||
else
|
|
||||||
rs += s;
|
|
||||||
}
|
|
||||||
else if(p > 0)
|
|
||||||
rs = bs.Sub(0, p).AsString();
|
|
||||||
|
|
||||||
// 匹配关键字,任务完成
|
|
||||||
if(p > 0) Result = nullptr;
|
|
||||||
|
|
||||||
// 如果后面是换行,则跳过
|
|
||||||
if(p < s.Length() && s[p] == ' ') p++;
|
|
||||||
if(p < s.Length() && s[p] == '\r') p++;
|
|
||||||
if(p < s.Length() && s[p] == '\n') p++;
|
|
||||||
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint WaitExpect::FindKey(const String& str)
|
|
||||||
{
|
|
||||||
// 适配第一关键字
|
|
||||||
int p = Key1 ? str.IndexOf(Key1) : -1;
|
|
||||||
if(p >= 0)
|
|
||||||
{
|
|
||||||
//net_printf("适配第一关键字 %s \r\n", Key1);
|
|
||||||
return p + String(Key1).Length();
|
|
||||||
}
|
|
||||||
// 适配第二关键字
|
|
||||||
p = Key2 ? str.IndexOf(Key2) : -1;
|
|
||||||
if(p >= 0)
|
|
||||||
{
|
|
||||||
net_printf("适配第二关键字 %s \r\n", Key2);
|
|
||||||
return p + String(Key2).Length();
|
|
||||||
}
|
|
||||||
// 适配busy
|
|
||||||
p = str.IndexOf("busy ");
|
|
||||||
if(p >= 0)
|
|
||||||
{
|
|
||||||
net_printf("适配 busy \r\n");
|
|
||||||
return p + 4 + 1 + 4;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
|
@ -1,7 +1,6 @@
|
||||||
#ifndef __Esp8266_H__
|
#ifndef __Esp8266_H__
|
||||||
#define __Esp8266_H__
|
#define __Esp8266_H__
|
||||||
|
|
||||||
#include "Sys.h"
|
|
||||||
#include "Port.h"
|
#include "Port.h"
|
||||||
#include "Net\ITransport.h"
|
#include "Net\ITransport.h"
|
||||||
#include "Net\Socket.h"
|
#include "Net\Socket.h"
|
||||||
|
@ -13,11 +12,8 @@ class Esp8266 : public PackPort, public ISocketHost
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
bool AutoConn; // 是否自动连接WiFi,默认false
|
bool AutoConn; // 是否自动连接WiFi,默认false
|
||||||
//String SSID;
|
|
||||||
//String Pass;
|
|
||||||
|
|
||||||
IDataPort* Led; // 指示灯
|
IDataPort* Led; // 指示灯
|
||||||
//Action NetReady; // 网络准备就绪
|
|
||||||
|
|
||||||
Esp8266(ITransport* port, Pin power = P0, Pin rst = P0);
|
Esp8266(ITransport* port, Pin power = P0, Pin rst = P0);
|
||||||
virtual ~Esp8266();
|
virtual ~Esp8266();
|
|
@ -0,0 +1,154 @@
|
||||||
|
#include "EspSocket.h"
|
||||||
|
|
||||||
|
#define NET_DEBUG DEBUG
|
||||||
|
//#define NET_DEBUG 0
|
||||||
|
#if NET_DEBUG
|
||||||
|
#define net_printf debug_printf
|
||||||
|
#else
|
||||||
|
#define net_printf(format, ...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/******************************** Socket ********************************/
|
||||||
|
|
||||||
|
EspSocket::EspSocket(Esp8266& host, ProtocolType protocol, byte idx)
|
||||||
|
: _Host(host)
|
||||||
|
{
|
||||||
|
_Index = idx;
|
||||||
|
_Error = 0;
|
||||||
|
|
||||||
|
Host = &host;
|
||||||
|
Protocol = protocol;
|
||||||
|
}
|
||||||
|
|
||||||
|
EspSocket::~EspSocket()
|
||||||
|
{
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EspSocket::OnOpen()
|
||||||
|
{
|
||||||
|
// 确保宿主打开
|
||||||
|
if(!_Host.Open()) return false;
|
||||||
|
|
||||||
|
// 如果没有指定本地端口,则使用累加端口
|
||||||
|
if(!Local.Port)
|
||||||
|
{
|
||||||
|
// 累加端口
|
||||||
|
static ushort g_port = 1024;
|
||||||
|
if(g_port < 1024) g_port = 1024;
|
||||||
|
Local.Port = g_port++;
|
||||||
|
}
|
||||||
|
Local.Address = _Host.IP;
|
||||||
|
|
||||||
|
_Host.SetMux(true);
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
debug_printf("%s::Open ", Protocol == ProtocolType::Tcp ? "Tcp" : "Udp");
|
||||||
|
Local.Show(false);
|
||||||
|
debug_printf(" => ");
|
||||||
|
Server.Show(false);
|
||||||
|
debug_printf(" ");
|
||||||
|
Remote.Show(true);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
String cmd = "AT+CIPSTART=";
|
||||||
|
cmd = cmd + _Index + ",";
|
||||||
|
|
||||||
|
if(Protocol == ProtocolType::Udp)
|
||||||
|
cmd += "\"UDP\"";
|
||||||
|
else if(Protocol == ProtocolType::Tcp)
|
||||||
|
cmd += "\"TCP\"";
|
||||||
|
|
||||||
|
auto rm = Server;
|
||||||
|
if(!rm) rm = Remote.Address.ToString();
|
||||||
|
|
||||||
|
// 设置端口目的(远程)IP地址和端口号
|
||||||
|
cmd = cmd + ",\"" + rm + "\"," + Remote.Port;
|
||||||
|
// 设置自己的端口号
|
||||||
|
if(Local.Port) cmd = cmd + ',' + Local.Port;
|
||||||
|
// UDP传输属性。0,收到数据不改变远端目标;1,收到数据改变一次远端目标;2,收到数据改变远端目标
|
||||||
|
|
||||||
|
/*if(Remote.Address == IPAddress::Broadcast())
|
||||||
|
cmd += ",2";
|
||||||
|
else*/
|
||||||
|
cmd += ",0";
|
||||||
|
|
||||||
|
// 打开Socket。有OK/ERROR/ALREADY CONNECTED三种
|
||||||
|
auto rt = _Host.Send(cmd + "\r\n", "OK", "ERROR", 1600);
|
||||||
|
if(!rt.Contains("OK") && ! rt.Contains("ALREADY CONNECTED"))
|
||||||
|
{
|
||||||
|
debug_printf("协议 %d, %d 打开失败 \r\n", Protocol, Remote.Port);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 清空一次缓冲区
|
||||||
|
/*cmd = "AT+CIPBUFRESET=";
|
||||||
|
_Host.SendCmd(cmd + _Index);*/
|
||||||
|
_Error = 0;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EspSocket::OnClose()
|
||||||
|
{
|
||||||
|
String cmd = "AT+CIPCLOSE=";
|
||||||
|
cmd += _Index;
|
||||||
|
cmd += "\r\n";
|
||||||
|
|
||||||
|
_Host.SendCmd(cmd, 1600);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 接收数据
|
||||||
|
uint EspSocket::Receive(Buffer& bs)
|
||||||
|
{
|
||||||
|
if(!Open()) return 0;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 发送数据
|
||||||
|
bool EspSocket::Send(const Buffer& bs)
|
||||||
|
{
|
||||||
|
if(!Open()) return false;
|
||||||
|
|
||||||
|
String cmd = "AT+CIPSEND=";
|
||||||
|
cmd = cmd + _Index + ',' + bs.Length() + "\r\n";
|
||||||
|
|
||||||
|
return SendData(cmd, bs);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EspSocket::SendData(const String& cmd, const Buffer& bs)
|
||||||
|
{
|
||||||
|
// 重发3次AT指令,避免busy
|
||||||
|
int i = 0;
|
||||||
|
for(i=0; i<3; i++)
|
||||||
|
{
|
||||||
|
//auto rt = _Host.Send(cmd, ">", "OK", 1600);
|
||||||
|
// 不能等待OK,而应该等待>,因为发送期间可能给别的指令碰撞
|
||||||
|
auto rt = _Host.Send(cmd, ">", "ERROR", 1600);
|
||||||
|
if(rt.Contains(">")) break;
|
||||||
|
}
|
||||||
|
if(i<3 && _Host.Send(bs.AsString(), "SEND OK", "ERROR", 1600).Contains("SEND OK"))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 发送失败,关闭链接,下一次重新打开
|
||||||
|
if(++_Error >= 10)
|
||||||
|
{
|
||||||
|
_Error = 0;
|
||||||
|
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EspSocket::OnWrite(const Buffer& bs) { return Send(bs); }
|
||||||
|
uint EspSocket::OnRead(Buffer& bs) { return Receive(bs); }
|
||||||
|
|
||||||
|
// 收到数据
|
||||||
|
void EspSocket::OnProcess(const Buffer& bs, const IPEndPoint& remote)
|
||||||
|
{
|
||||||
|
OnReceive((Buffer&)bs, (void*)&remote);
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
#ifndef __EspSocket_H__
|
||||||
|
#define __EspSocket_H__
|
||||||
|
|
||||||
|
#include "Esp8266.h"
|
||||||
|
|
||||||
|
class EspSocket : public Object, public ITransport, public ISocket
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
Esp8266& _Host;
|
||||||
|
byte _Index;
|
||||||
|
int _Error;
|
||||||
|
|
||||||
|
public:
|
||||||
|
EspSocket(Esp8266& host, ProtocolType protocol, byte idx);
|
||||||
|
virtual ~EspSocket();
|
||||||
|
|
||||||
|
// 打开Socket
|
||||||
|
virtual bool OnOpen();
|
||||||
|
virtual void OnClose();
|
||||||
|
|
||||||
|
//// 应用配置,修改远程地址和端口
|
||||||
|
//virtual bool Change(const String& remote, ushort port);
|
||||||
|
|
||||||
|
virtual bool OnWrite(const Buffer& bs);
|
||||||
|
virtual uint OnRead(Buffer& bs);
|
||||||
|
|
||||||
|
// 发送数据
|
||||||
|
virtual bool Send(const Buffer& bs);
|
||||||
|
// 接收数据
|
||||||
|
virtual uint Receive(Buffer& bs);
|
||||||
|
|
||||||
|
// 收到数据
|
||||||
|
virtual void OnProcess(const Buffer& bs, const IPEndPoint& remote);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool SendData(const String& cmd, const Buffer& bs);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,9 @@
|
||||||
|
#include "EspTcp.h"
|
||||||
|
|
||||||
|
/******************************** Tcp ********************************/
|
||||||
|
|
||||||
|
EspTcp::EspTcp(Esp8266& host, byte idx)
|
||||||
|
: EspSocket(host, ProtocolType::Tcp, idx)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
#ifndef __EspTcp_H__
|
||||||
|
#define __EspTcp_H__
|
||||||
|
|
||||||
|
#include "EspSocket.h"
|
||||||
|
|
||||||
|
class EspTcp : public EspSocket
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
EspTcp(Esp8266& host, byte idx);
|
||||||
|
|
||||||
|
virtual String& ToStr(String& str) const { return str + "Tcp_" + Local.Port; }
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,35 @@
|
||||||
|
#include "EspUdp.h"
|
||||||
|
|
||||||
|
/******************************** Udp ********************************/
|
||||||
|
|
||||||
|
EspUdp::EspUdp(Esp8266& host, byte idx)
|
||||||
|
: EspSocket(host, ProtocolType::Udp, idx)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EspUdp::SendTo(const Buffer& bs, const IPEndPoint& remote)
|
||||||
|
{
|
||||||
|
//!!! ESP8266有BUG,收到数据后,远程地址还是乱了,所以这里的远程地址跟实际可能不一致
|
||||||
|
if(remote == Remote) return Send(bs);
|
||||||
|
|
||||||
|
if(!Open()) return false;
|
||||||
|
|
||||||
|
String cmd = "AT+CIPSEND=";
|
||||||
|
cmd = cmd + _Index + ',' + bs.Length();
|
||||||
|
|
||||||
|
// 加上远程IP和端口
|
||||||
|
cmd = cmd + ",\"" + remote.Address + "\"";
|
||||||
|
cmd = cmd + ',' + remote.Port;
|
||||||
|
cmd += "\r\n";
|
||||||
|
|
||||||
|
return SendData(cmd, bs);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EspUdp::OnWriteEx(const Buffer& bs, const void* opt)
|
||||||
|
{
|
||||||
|
auto ep = (IPEndPoint*)opt;
|
||||||
|
if(!ep) return OnWrite(bs);
|
||||||
|
|
||||||
|
return SendTo(bs, *ep);
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
#ifndef __EspUdp_H__
|
||||||
|
#define __EspUdp_H__
|
||||||
|
|
||||||
|
#include "EspSocket.h"
|
||||||
|
|
||||||
|
class EspUdp : public EspSocket
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
EspUdp(Esp8266& host, byte idx);
|
||||||
|
|
||||||
|
virtual bool SendTo(const Buffer& bs, const IPEndPoint& remote);
|
||||||
|
|
||||||
|
virtual String& ToStr(String& str) const { return str + "Udp_" + Local.Port; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
virtual bool OnWriteEx(const Buffer& bs, const void* opt);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,95 @@
|
||||||
|
#include "Time.h"
|
||||||
|
#include "Sys.h"
|
||||||
|
|
||||||
|
#include "WaitExpect.h"
|
||||||
|
|
||||||
|
#define NET_DEBUG DEBUG
|
||||||
|
//#define NET_DEBUG 0
|
||||||
|
#if NET_DEBUG
|
||||||
|
#define net_printf debug_printf
|
||||||
|
#else
|
||||||
|
#define net_printf(format, ...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/******************************** WaitExpect ********************************/
|
||||||
|
|
||||||
|
bool WaitExpect::Wait(int msTimeout)
|
||||||
|
{
|
||||||
|
// 提前等待一会,再开始轮询,专门为了加快命中快速响应的指令
|
||||||
|
Sys.Sleep(40);
|
||||||
|
if(!Result) return true;
|
||||||
|
|
||||||
|
// 等待收到数据
|
||||||
|
TimeWheel tw(0, msTimeout - 40);
|
||||||
|
// 默认检查间隔200ms,如果超时时间大于1000ms,则以四分之一为检查间隔
|
||||||
|
// ESP8266串口任务平均时间为150ms左右,为了避免接收指令任务里面发送指令时等不到OK,需要加大检查间隔
|
||||||
|
tw.Sleep = 200;
|
||||||
|
if(msTimeout > 1000) tw.Sleep = msTimeout >> 2;
|
||||||
|
if(tw.Sleep > 1000) tw.Sleep = 1000;
|
||||||
|
|
||||||
|
while(Result)
|
||||||
|
{
|
||||||
|
if(tw.Expired()) return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint WaitExpect::Parse(const Buffer& bs)
|
||||||
|
{
|
||||||
|
if(bs.Length() == 0 || !Result) return 0;
|
||||||
|
|
||||||
|
TS("WaitExpect::Parse");
|
||||||
|
|
||||||
|
// 适配任意关键字后,也就是收到了成功或失败,通知业务层已结束
|
||||||
|
auto s = (const String)bs.AsString();
|
||||||
|
int p = FindKey(s);
|
||||||
|
auto& rs= *Result;
|
||||||
|
|
||||||
|
// 捕获所有
|
||||||
|
if(Capture)
|
||||||
|
{
|
||||||
|
if(p > 0)
|
||||||
|
rs += bs.Sub(0, p).AsString();
|
||||||
|
else
|
||||||
|
rs += s;
|
||||||
|
}
|
||||||
|
else if(p > 0)
|
||||||
|
rs = bs.Sub(0, p).AsString();
|
||||||
|
|
||||||
|
// 匹配关键字,任务完成
|
||||||
|
if(p > 0) Result = nullptr;
|
||||||
|
|
||||||
|
// 如果后面是换行,则跳过
|
||||||
|
if(p < s.Length() && s[p] == ' ') p++;
|
||||||
|
if(p < s.Length() && s[p] == '\r') p++;
|
||||||
|
if(p < s.Length() && s[p] == '\n') p++;
|
||||||
|
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint WaitExpect::FindKey(const String& str)
|
||||||
|
{
|
||||||
|
// 适配第一关键字
|
||||||
|
int p = Key1 ? str.IndexOf(Key1) : -1;
|
||||||
|
if(p >= 0)
|
||||||
|
{
|
||||||
|
//net_printf("适配第一关键字 %s \r\n", Key1);
|
||||||
|
return p + String(Key1).Length();
|
||||||
|
}
|
||||||
|
// 适配第二关键字
|
||||||
|
p = Key2 ? str.IndexOf(Key2) : -1;
|
||||||
|
if(p >= 0)
|
||||||
|
{
|
||||||
|
net_printf("适配第二关键字 %s \r\n", Key2);
|
||||||
|
return p + String(Key2).Length();
|
||||||
|
}
|
||||||
|
// 适配busy
|
||||||
|
p = str.IndexOf("busy ");
|
||||||
|
if(p >= 0)
|
||||||
|
{
|
||||||
|
net_printf("适配 busy \r\n");
|
||||||
|
return p + 4 + 1 + 4;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
#ifndef __WaitExpect_H__
|
||||||
|
#define __WaitExpect_H__
|
||||||
|
|
||||||
|
// 等待
|
||||||
|
class WaitExpect
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
const String* Command = nullptr;
|
||||||
|
String* Result = nullptr;
|
||||||
|
cstring Key1 = nullptr;
|
||||||
|
cstring Key2 = nullptr;
|
||||||
|
|
||||||
|
bool Capture = true; // 是否捕获所有
|
||||||
|
|
||||||
|
bool Wait(int msTimeout);
|
||||||
|
uint Parse(const Buffer& bs);
|
||||||
|
uint FindKey(const String& str);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in New Issue