You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

537 lines
13 KiB

8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
6 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
7 years ago
8 years ago
8 years ago
8 years ago
8 years ago
7 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
7 years ago
8 years ago
8 years ago
7 years ago
8 years ago
6 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
7 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
7 years ago
7 years ago
7 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
  1. /**
  2. * @file TinyGsmClientESP8266.h
  3. * @author Volodymyr Shymanskyy
  4. * @license LGPL-3.0
  5. * @copyright Copyright (c) 2016 Volodymyr Shymanskyy
  6. * @date Nov 2016
  7. */
  8. #ifndef TinyGsmClientESP8266_h
  9. #define TinyGsmClientESP8266_h
  10. //#pragma message("TinyGSM: TinyGsmClientESP8266")
  11. //#define TINY_GSM_DEBUG Serial
  12. #define TINY_GSM_MUX_COUNT 5
  13. #include <TinyGsmCommon.h>
  14. #define GSM_NL "\r\n"
  15. static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL;
  16. static const char GSM_ERROR[] TINY_GSM_PROGMEM = "ERROR" GSM_NL;
  17. static unsigned TINY_GSM_TCP_KEEP_ALIVE = 120;
  18. // <stat> status of ESP8266 station interface
  19. // 2 : ESP8266 station connected to an AP and has obtained IP
  20. // 3 : ESP8266 station created a TCP or UDP transmission
  21. // 4 : the TCP or UDP transmission of ESP8266 station disconnected
  22. // 5 : ESP8266 station did NOT connect to an AP
  23. enum RegStatus {
  24. REG_OK_IP = 2,
  25. REG_OK_TCP = 3,
  26. REG_UNREGISTERED = 4,
  27. REG_DENIED = 5,
  28. REG_UNKNOWN = 6,
  29. };
  30. class TinyGsmESP8266 : public TinyGsmModem
  31. {
  32. public:
  33. class GsmClient : public Client
  34. {
  35. friend class TinyGsmESP8266;
  36. typedef TinyGsmFifo<uint8_t, TINY_GSM_RX_BUFFER> RxFifo;
  37. public:
  38. GsmClient() {}
  39. GsmClient(TinyGsmESP8266& modem, uint8_t mux = 1) {
  40. init(&modem, mux);
  41. }
  42. bool init(TinyGsmESP8266* modem, uint8_t mux = 1) {
  43. this->at = modem;
  44. this->mux = mux;
  45. sock_connected = false;
  46. at->sockets[mux] = this;
  47. return true;
  48. }
  49. public:
  50. virtual int connect(const char *host, uint16_t port) {
  51. stop();
  52. TINY_GSM_YIELD();
  53. rx.clear();
  54. sock_connected = at->modemConnect(host, port, mux);
  55. return sock_connected;
  56. }
  57. virtual int connect(IPAddress ip, uint16_t port) {
  58. String host; host.reserve(16);
  59. host += ip[0];
  60. host += ".";
  61. host += ip[1];
  62. host += ".";
  63. host += ip[2];
  64. host += ".";
  65. host += ip[3];
  66. return connect(host.c_str(), port);
  67. }
  68. virtual void stop() {
  69. TINY_GSM_YIELD();
  70. at->sendAT(GF("+CIPCLOSE="), mux);
  71. sock_connected = false;
  72. at->waitResponse();
  73. rx.clear();
  74. }
  75. virtual size_t write(const uint8_t *buf, size_t size) {
  76. TINY_GSM_YIELD();
  77. //at->maintain();
  78. return at->modemSend(buf, size, mux);
  79. }
  80. virtual size_t write(uint8_t c) {
  81. return write(&c, 1);
  82. }
  83. virtual size_t write(const char *str) {
  84. if (str == NULL) return 0;
  85. return write((const uint8_t *)str, strlen(str));
  86. }
  87. virtual int available() {
  88. TINY_GSM_YIELD();
  89. if (!rx.size()) {
  90. at->maintain();
  91. }
  92. return rx.size();
  93. }
  94. virtual int read(uint8_t *buf, size_t size) {
  95. TINY_GSM_YIELD();
  96. size_t cnt = 0;
  97. uint32_t _startMillis = millis();
  98. while (cnt < size && millis() - _startMillis < _timeout) {
  99. size_t chunk = TinyGsmMin(size-cnt, rx.size());
  100. if (chunk > 0) {
  101. rx.get(buf, chunk);
  102. buf += chunk;
  103. cnt += chunk;
  104. continue;
  105. }
  106. // TODO: Read directly into user buffer?
  107. if (!rx.size() && sock_connected) {
  108. at->maintain();
  109. }
  110. }
  111. return cnt;
  112. }
  113. virtual int read() {
  114. uint8_t c;
  115. if (read(&c, 1) == 1) {
  116. return c;
  117. }
  118. return -1;
  119. }
  120. virtual int peek() { return -1; } //TODO
  121. virtual void flush() { at->stream.flush(); }
  122. virtual uint8_t connected() {
  123. if (available()) {
  124. return true;
  125. }
  126. return sock_connected;
  127. }
  128. virtual operator bool() { return connected(); }
  129. /*
  130. * Extended API
  131. */
  132. String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
  133. private:
  134. TinyGsmESP8266* at;
  135. uint8_t mux;
  136. bool sock_connected;
  137. RxFifo rx;
  138. };
  139. class GsmClientSecure : public GsmClient
  140. {
  141. public:
  142. GsmClientSecure() {}
  143. GsmClientSecure(TinyGsmESP8266& modem, uint8_t mux = 1)
  144. : GsmClient(modem, mux)
  145. {}
  146. public:
  147. virtual int connect(const char *host, uint16_t port) {
  148. stop();
  149. TINY_GSM_YIELD();
  150. rx.clear();
  151. sock_connected = at->modemConnect(host, port, mux, true);
  152. return sock_connected;
  153. }
  154. };
  155. public:
  156. TinyGsmESP8266(Stream& stream)
  157. : TinyGsmModem(stream), stream(stream)
  158. {
  159. memset(sockets, 0, sizeof(sockets));
  160. }
  161. /*
  162. * Basic functions
  163. */
  164. bool init(const char* pin = NULL) {
  165. if (!testAT()) {
  166. return false;
  167. }
  168. sendAT(GF("E0")); // Echo Off
  169. if (waitResponse() != 1) {
  170. return false;
  171. }
  172. sendAT(GF("+CIPMUX=1")); // Enable Multiple Connections
  173. if (waitResponse() != 1) {
  174. return false;
  175. }
  176. sendAT(GF("+CWMODE_CUR=1")); // Put into "station" mode
  177. if (waitResponse() != 1) {
  178. return false;
  179. }
  180. DBG(GF("### Modem:"), getModemName());
  181. return true;
  182. }
  183. String getModemName() {
  184. return "ESP8266";
  185. }
  186. void setBaud(unsigned long baud) {
  187. sendAT(GF("+IPR="), baud);
  188. }
  189. bool testAT(unsigned long timeout = 10000L) {
  190. for (unsigned long start = millis(); millis() - start < timeout; ) {
  191. sendAT(GF(""));
  192. if (waitResponse(200) == 1) return true;
  193. delay(100);
  194. }
  195. return false;
  196. }
  197. void maintain() {
  198. waitResponse(10, NULL, NULL);
  199. }
  200. bool factoryDefault() {
  201. sendAT(GF("+RESTORE"));
  202. return waitResponse() == 1;
  203. }
  204. String getModemInfo() {
  205. sendAT(GF("+GMR"));
  206. String res;
  207. if (waitResponse(1000L, res) != 1) {
  208. return "";
  209. }
  210. res.replace(GSM_NL "OK" GSM_NL, "");
  211. res.replace(GSM_NL, " ");
  212. res.trim();
  213. return res;
  214. }
  215. bool hasSSL() {
  216. return true;
  217. }
  218. bool hasWifi() {
  219. return true;
  220. }
  221. bool hasGPRS() {
  222. return false;
  223. }
  224. /*
  225. * Power functions
  226. */
  227. bool restart() {
  228. if (!testAT()) {
  229. return false;
  230. }
  231. sendAT(GF("+RST"));
  232. if (waitResponse(10000L) != 1) {
  233. return false;
  234. }
  235. if (waitResponse(10000L, GF(GSM_NL "ready" GSM_NL)) != 1) {
  236. return false;
  237. }
  238. delay(500);
  239. return init();
  240. }
  241. bool poweroff() {
  242. sendAT(GF("+GSLP=0")); // Power down indefinitely - until manually reset!
  243. return waitResponse() == 1;
  244. }
  245. bool radioOff() TINY_GSM_ATTR_NOT_IMPLEMENTED;
  246. bool sleepEnable(bool enable = true) TINY_GSM_ATTR_NOT_IMPLEMENTED;
  247. /*
  248. * SIM card functions
  249. */
  250. RegStatus getRegistrationStatus() {
  251. sendAT(GF("+CIPSTATUS"));
  252. if (waitResponse(3000, GF("STATUS:")) != 1) return REG_UNKNOWN;
  253. int status = waitResponse(GFP(GSM_ERROR), GF("2"), GF("3"), GF("4"), GF("5"));
  254. waitResponse(); // Returns an OK after the status
  255. return (RegStatus)status;
  256. }
  257. /*
  258. * Generic network functions
  259. */
  260. int16_t getSignalQuality() {
  261. sendAT(GF("+CWJAP_CUR?"));
  262. int res1 = waitResponse(GF("No AP"), GF("+CWJAP_CUR:"));
  263. if (res1 != 2) {
  264. waitResponse();
  265. return 0;
  266. }
  267. streamSkipUntil(','); // Skip SSID
  268. streamSkipUntil(','); // Skip BSSID/MAC address
  269. streamSkipUntil(','); // Skip Chanel number
  270. int res2 = stream.parseInt(); // Read RSSI
  271. waitResponse(); // Returns an OK after the value
  272. return res2;
  273. }
  274. bool isNetworkConnected() {
  275. RegStatus s = getRegistrationStatus();
  276. return (s == REG_OK_IP || s == REG_OK_TCP);
  277. }
  278. bool waitForNetwork(unsigned long timeout = 60000L) {
  279. for (unsigned long start = millis(); millis() - start < timeout; ) {
  280. sendAT(GF("+CIPSTATUS"));
  281. int res1 = waitResponse(3000, GF("busy p..."), GF("STATUS:"));
  282. if (res1 == 2) {
  283. int res2 = waitResponse(GFP(GSM_ERROR), GF("2"), GF("3"), GF("4"), GF("5"));
  284. if (res2 == 2 || res2 == 3) {
  285. waitResponse();
  286. return true;
  287. }
  288. }
  289. delay(250);
  290. }
  291. return false;
  292. }
  293. /*
  294. * WiFi functions
  295. */
  296. bool networkConnect(const char* ssid, const char* pwd) {
  297. sendAT(GF("+CWJAP_CUR=\""), ssid, GF("\",\""), pwd, GF("\""));
  298. if (waitResponse(30000L, GFP(GSM_OK), GF(GSM_NL "FAIL" GSM_NL)) != 1) {
  299. return false;
  300. }
  301. return true;
  302. }
  303. bool networkDisconnect() {
  304. sendAT(GF("+CWQAP"));
  305. bool retVal = waitResponse(10000L) == 1;
  306. waitResponse(GF("WIFI DISCONNECT"));
  307. return retVal;
  308. }
  309. /*
  310. * IP Address functions
  311. */
  312. String getLocalIP() {
  313. sendAT(GF("+CIPSTA_CUR??"));
  314. int res1 = waitResponse(GF("ERROR"), GF("+CWJAP_CUR:"));
  315. if (res1 != 2) {
  316. return "";
  317. }
  318. String res2 = stream.readStringUntil('"');
  319. waitResponse();
  320. return res2;
  321. }
  322. /*
  323. * Client related functions
  324. */
  325. protected:
  326. bool modemConnect(const char* host, uint16_t port, uint8_t mux, bool ssl = false) {
  327. if (ssl) {
  328. sendAT(GF("+CIPSSLSIZE=4096"));
  329. waitResponse();
  330. }
  331. sendAT(GF("+CIPSTART="), mux, ',', ssl ? GF("\"SSL") : GF("\"TCP"), GF("\",\""), host, GF("\","), port, GF(","), TINY_GSM_TCP_KEEP_ALIVE);
  332. // TODO: Check mux
  333. int rsp = waitResponse(75000L,
  334. GFP(GSM_OK),
  335. GFP(GSM_ERROR),
  336. GF("ALREADY CONNECT"));
  337. // if (rsp == 3) waitResponse(); // May return "ERROR" after the "ALREADY CONNECT"
  338. return (1 == rsp);
  339. }
  340. int16_t modemSend(const void* buff, size_t len, uint8_t mux) {
  341. sendAT(GF("+CIPSEND="), mux, ',', len);
  342. if (waitResponse(GF(">")) != 1) {
  343. return 0;
  344. }
  345. stream.write((uint8_t*)buff, len);
  346. stream.flush();
  347. if (waitResponse(10000L, GF(GSM_NL "SEND OK" GSM_NL)) != 1) {
  348. return 0;
  349. }
  350. return len;
  351. }
  352. bool modemGetConnected(uint8_t mux) {
  353. RegStatus s = getRegistrationStatus();
  354. return (s == REG_OK_IP || s == REG_OK_TCP);
  355. }
  356. public:
  357. /*
  358. Utilities
  359. */
  360. template<typename... Args>
  361. void sendAT(Args... cmd) {
  362. streamWrite("AT", cmd..., GSM_NL);
  363. stream.flush();
  364. TINY_GSM_YIELD();
  365. //DBG("### AT:", cmd...);
  366. }
  367. // TODO: Optimize this!
  368. uint8_t waitResponse(uint32_t timeout, String& data,
  369. GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
  370. GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
  371. {
  372. /*String r1s(r1); r1s.trim();
  373. String r2s(r2); r2s.trim();
  374. String r3s(r3); r3s.trim();
  375. String r4s(r4); r4s.trim();
  376. String r5s(r5); r5s.trim();
  377. DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/
  378. data.reserve(64);
  379. int index = 0;
  380. unsigned long startMillis = millis();
  381. do {
  382. TINY_GSM_YIELD();
  383. while (stream.available() > 0) {
  384. int a = stream.read();
  385. if (a <= 0) continue; // Skip 0x00 bytes, just in case
  386. data += (char)a;
  387. if (r1 && data.endsWith(r1)) {
  388. index = 1;
  389. goto finish;
  390. } else if (r2 && data.endsWith(r2)) {
  391. index = 2;
  392. goto finish;
  393. } else if (r3 && data.endsWith(r3)) {
  394. index = 3;
  395. goto finish;
  396. } else if (r4 && data.endsWith(r4)) {
  397. index = 4;
  398. goto finish;
  399. } else if (r5 && data.endsWith(r5)) {
  400. index = 5;
  401. goto finish;
  402. } else if (data.endsWith(GF(GSM_NL "+IPD,"))) {
  403. int mux = stream.readStringUntil(',').toInt();
  404. int len = stream.readStringUntil(':').toInt();
  405. int len_orig = len;
  406. if (len > sockets[mux]->rx.free()) {
  407. DBG("### Buffer overflow: ", len, "->", sockets[mux]->rx.free());
  408. } else {
  409. DBG("### Got: ", len, "->", sockets[mux]->rx.free());
  410. }
  411. while (len--) {
  412. while (!stream.available()) { TINY_GSM_YIELD(); }
  413. sockets[mux]->rx.put(stream.read());
  414. }
  415. if (len_orig > sockets[mux]->available()) { // TODO
  416. DBG("### Fewer characters received than expected: ", sockets[mux]->available(), " vs ", len_orig);
  417. }
  418. data = "";
  419. } else if (data.endsWith(GF("CLOSED"))) {
  420. int muxStart = max(0,data.lastIndexOf(GSM_NL, data.length()-8));
  421. int coma = data.indexOf(',', muxStart);
  422. int mux = data.substring(muxStart, coma).toInt();
  423. if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
  424. sockets[mux]->sock_connected = false;
  425. }
  426. data = "";
  427. DBG("### Closed: ", mux);
  428. }
  429. }
  430. } while (millis() - startMillis < timeout);
  431. finish:
  432. if (!index) {
  433. data.trim();
  434. if (data.length()) {
  435. DBG("### Unhandled:", data);
  436. }
  437. data = "";
  438. }
  439. //DBG('<', index, '>');
  440. return index;
  441. }
  442. uint8_t waitResponse(uint32_t timeout,
  443. GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
  444. GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
  445. {
  446. String data;
  447. return waitResponse(timeout, data, r1, r2, r3, r4, r5);
  448. }
  449. uint8_t waitResponse(GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
  450. GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
  451. {
  452. return waitResponse(1000, r1, r2, r3, r4, r5);
  453. }
  454. public:
  455. Stream& stream;
  456. protected:
  457. GsmClient* sockets[TINY_GSM_MUX_COUNT];
  458. };
  459. #endif