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.

520 lines
15 KiB

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
8 years ago
7 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
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
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 SRC_TINYGSMCLIENTESP8266_H_
  9. #define SRC_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 const char GSM_CME_ERROR[] TINY_GSM_PROGMEM = GSM_NL "+CME ERROR:";
  18. static unsigned TINY_GSM_TCP_KEEP_ALIVE = 120;
  19. // <stat> status of ESP8266 station interface
  20. // 2 : ESP8266 station connected to an AP and has obtained IP
  21. // 3 : ESP8266 station created a TCP or UDP transmission
  22. // 4 : the TCP or UDP transmission of ESP8266 station disconnected
  23. // 5 : ESP8266 station did NOT connect to an AP
  24. enum RegStatus {
  25. REG_OK_IP = 2,
  26. REG_OK_TCP = 3,
  27. REG_OK_NO_TCP = 4,
  28. REG_DENIED = 5,
  29. REG_UNKNOWN = 6,
  30. };
  31. class TinyGsmESP8266
  32. : public TinyGsmModem<TinyGsmESP8266, NO_MODEM_BUFFER, TINY_GSM_MUX_COUNT> {
  33. friend class TinyGsmModem<TinyGsmESP8266, NO_MODEM_BUFFER, TINY_GSM_MUX_COUNT>;
  34. /*
  35. * Inner Client
  36. */
  37. public:
  38. class GsmClientESP8266 : public GsmClient {
  39. friend class TinyGsmESP8266;
  40. public:
  41. GsmClientESP8266() {}
  42. explicit GsmClientESP8266(TinyGsmESP8266& modem, uint8_t mux = 1) {
  43. init(&modem, mux);
  44. }
  45. bool init(TinyGsmESP8266* modem, uint8_t mux = 1) {
  46. this->at = modem;
  47. this->mux = mux;
  48. sock_connected = false;
  49. at->sockets[mux] = this;
  50. return true;
  51. }
  52. public:
  53. int connect(const char* host, uint16_t port, int timeout_s) {
  54. stop();
  55. TINY_GSM_YIELD();
  56. rx.clear();
  57. sock_connected = at->modemConnect(host, port, mux, false, timeout_s);
  58. return sock_connected;
  59. }
  60. int connect(IPAddress ip, uint16_t port, int timeout_s) {
  61. return connect(TinyGsmStringFromIp(ip).c_str(), port, timeout_s);
  62. }
  63. int connect(const char* host, uint16_t port) override {
  64. return connect(host, port, 75);
  65. }
  66. int connect(IPAddress ip, uint16_t port) override {
  67. return connect(ip, port, 75);
  68. }
  69. void stop(uint32_t maxWaitMs) {
  70. TINY_GSM_YIELD();
  71. at->sendAT(GF("+CIPCLOSE="), mux);
  72. sock_connected = false;
  73. at->waitResponse(maxWaitMs);
  74. rx.clear();
  75. }
  76. void stop() override {
  77. stop(5000L);
  78. }
  79. /*
  80. * Extended API
  81. */
  82. String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
  83. };
  84. /*
  85. * Inner Secure Client
  86. */
  87. public:
  88. class GsmClientSecureESP8266 : public GsmClientESP8266 {
  89. public:
  90. GsmClientSecureESP8266() {}
  91. explicit GsmClientSecureESP8266(TinyGsmESP8266& modem, uint8_t mux = 1)
  92. : GsmClientESP8266(modem, mux) {}
  93. public:
  94. int connect(const char* host, uint16_t port, int timeout_s) {
  95. stop();
  96. TINY_GSM_YIELD();
  97. rx.clear();
  98. sock_connected = at->modemConnect(host, port, mux, true, timeout_s);
  99. return sock_connected;
  100. }
  101. };
  102. /*
  103. * Constructor
  104. */
  105. public:
  106. explicit TinyGsmESP8266(Stream& stream) : stream(stream) {
  107. memset(sockets, 0, sizeof(sockets));
  108. }
  109. /*
  110. * Basic functions
  111. */
  112. protected:
  113. bool initImpl(const char* pin = NULL) {
  114. DBG(GF("### TinyGSM Version:"), TINYGSM_VERSION);
  115. if (!testAT()) { return false; }
  116. if (pin && strlen(pin) > 0) {
  117. DBG("ESP8266 modules do not use an unlock pin!");
  118. }
  119. sendAT(GF("E0")); // Echo Off
  120. if (waitResponse() != 1) { return false; }
  121. sendAT(GF("+CIPMUX=1")); // Enable Multiple Connections
  122. if (waitResponse() != 1) { return false; }
  123. sendAT(GF("+CWMODE_CUR=1")); // Put into "station" mode
  124. if (waitResponse() != 1) { return false; }
  125. DBG(GF("### Modem:"), getModemName());
  126. return true;
  127. }
  128. String getModemNameImpl() {
  129. return "ESP8266";
  130. }
  131. void setBaudImpl(uint32_t baud) {
  132. sendAT(GF("+UART_CUR="), baud, "8,1,0,0");
  133. }
  134. bool factoryDefaultImpl() {
  135. sendAT(GF("+RESTORE"));
  136. return waitResponse() == 1;
  137. }
  138. String getModemInfoImpl() {
  139. sendAT(GF("+GMR"));
  140. String res;
  141. if (waitResponse(1000L, res) != 1) { return ""; }
  142. res.replace(GSM_NL "OK" GSM_NL, "");
  143. res.replace(GSM_NL, " ");
  144. res.trim();
  145. return res;
  146. }
  147. bool thisHasSSL() {
  148. return true;
  149. }
  150. bool thisHasWifi() {
  151. return true;
  152. }
  153. bool thisHasGPRS() {
  154. return false;
  155. }
  156. /*
  157. * Power functions
  158. */
  159. protected:
  160. bool restartImpl() {
  161. if (!testAT()) { return false; }
  162. sendAT(GF("+RST"));
  163. if (waitResponse(10000L) != 1) { return false; }
  164. if (waitResponse(10000L, GF(GSM_NL "ready" GSM_NL)) != 1) { return false; }
  165. delay(500);
  166. return init();
  167. }
  168. bool powerOffImpl() {
  169. sendAT(GF("+GSLP=0")); // Power down indefinitely - until manually reset!
  170. return waitResponse() == 1;
  171. }
  172. bool radioOffImpl() TINY_GSM_ATTR_NOT_IMPLEMENTED;
  173. bool sleepEnableImpl(bool enable = true) TINY_GSM_ATTR_NOT_AVAILABLE;
  174. /*
  175. * SIM card functions
  176. */
  177. protected:
  178. // SIM card functions don't apply
  179. /*
  180. * Generic network functions
  181. */
  182. public:
  183. RegStatus getRegistrationStatus() {
  184. sendAT(GF("+CIPSTATUS"));
  185. if (waitResponse(3000, GF("STATUS:")) != 1) return REG_UNKNOWN;
  186. int status = waitResponse(GFP(GSM_ERROR), GF("2"), GF("3"), GF("4"),
  187. GF("5"));
  188. waitResponse(); // Returns an OK after the status
  189. return (RegStatus)status;
  190. }
  191. protected:
  192. int16_t getSignalQualityImpl() {
  193. sendAT(GF("+CWJAP_CUR?"));
  194. int res1 = waitResponse(GF("No AP"), GF("+CWJAP_CUR:"));
  195. if (res1 != 2) {
  196. waitResponse();
  197. return 0;
  198. }
  199. streamSkipUntil(','); // Skip SSID
  200. streamSkipUntil(','); // Skip BSSID/MAC address
  201. streamSkipUntil(','); // Skip Chanel number
  202. int res2 = stream.parseInt(); // Read RSSI
  203. waitResponse(); // Returns an OK after the value
  204. return res2;
  205. }
  206. bool isNetworkConnectedImpl() {
  207. RegStatus s = getRegistrationStatus();
  208. if (s == REG_OK_IP || s == REG_OK_TCP) {
  209. // with these, we're definitely connected
  210. return true;
  211. } else if (s == REG_OK_NO_TCP) {
  212. // with this, we may or may not be connected
  213. if (getLocalIP() == "") {
  214. return false;
  215. } else {
  216. return true;
  217. }
  218. } else {
  219. return false;
  220. }
  221. }
  222. /*
  223. * WiFi functions
  224. */
  225. protected:
  226. bool networkConnectImpl(const char* ssid, const char* pwd) {
  227. sendAT(GF("+CWJAP_CUR=\""), ssid, GF("\",\""), pwd, GF("\""));
  228. if (waitResponse(30000L, GFP(GSM_OK), GF(GSM_NL "FAIL" GSM_NL)) != 1) {
  229. return false;
  230. }
  231. return true;
  232. }
  233. bool networkDisconnectImpl() {
  234. sendAT(GF("+CWQAP"));
  235. bool retVal = waitResponse(10000L) == 1;
  236. waitResponse(GF("WIFI DISCONNECT"));
  237. return retVal;
  238. }
  239. /*
  240. * IP Address functions
  241. */
  242. protected:
  243. String getLocalIPImpl() {
  244. sendAT(GF("+CIPSTA_CUR?"));
  245. int res1 = waitResponse(GF("ERROR"), GF("+CWJAP_CUR:"));
  246. if (res1 != 2) { return ""; }
  247. String res2 = stream.readStringUntil('"');
  248. waitResponse();
  249. return res2;
  250. }
  251. /*
  252. * Phone Call functions
  253. */
  254. protected:
  255. bool callAnswerImpl() TINY_GSM_ATTR_NOT_AVAILABLE;
  256. bool callNumberImpl(const String& number) TINY_GSM_ATTR_NOT_AVAILABLE;
  257. bool callHangupImpl() TINY_GSM_ATTR_NOT_AVAILABLE;
  258. bool dtmfSendImpl(char cmd,
  259. int duration_ms = 100) TINY_GSM_ATTR_NOT_AVAILABLE;
  260. /*
  261. * Messaging functions
  262. */
  263. protected:
  264. String sendUSSDImpl(const String& code) TINY_GSM_ATTR_NOT_AVAILABLE;
  265. bool sendSMSImpl(const String& number,
  266. const String& text) TINY_GSM_ATTR_NOT_AVAILABLE;
  267. bool sendSMS_UTF16Impl(const char* const number, const void* text,
  268. size_t len) TINY_GSM_ATTR_NOT_AVAILABLE;
  269. /*
  270. * Location functions
  271. */
  272. protected:
  273. String getGsmLocationImpl() TINY_GSM_ATTR_NOT_AVAILABLE;
  274. /*
  275. * GPS location functions
  276. */
  277. public:
  278. // No functions of this type supported
  279. /*
  280. * Time functions
  281. */
  282. protected:
  283. String
  284. getGSMDateTimeImpl(TinyGSMDateTimeFormat format) TINY_GSM_ATTR_NOT_AVAILABLE;
  285. /*
  286. * Battery & temperature functions
  287. */
  288. protected:
  289. uint16_t getBattVoltageImpl() TINY_GSM_ATTR_NOT_AVAILABLE;
  290. int8_t getBattPercentImpl() TINY_GSM_ATTR_NOT_AVAILABLE;
  291. uint8_t getBattChargeStateImpl() TINY_GSM_ATTR_NOT_AVAILABLE;
  292. bool getBattStatsImpl(uint8_t& chargeState, int8_t& percent,
  293. uint16_t& milliVolts) TINY_GSM_ATTR_NOT_AVAILABLE;
  294. float getTemperatureImpl() TINY_GSM_ATTR_NOT_AVAILABLE;
  295. /*
  296. * Client related functions
  297. */
  298. protected:
  299. bool modemConnect(const char* host, uint16_t port, uint8_t mux,
  300. bool ssl = false, int timeout_s = 75) {
  301. uint32_t timeout_ms = ((uint32_t)timeout_s) * 1000;
  302. if (ssl) {
  303. sendAT(GF("+CIPSSLSIZE=4096"));
  304. waitResponse();
  305. }
  306. sendAT(GF("+CIPSTART="), mux, ',', ssl ? GF("\"SSL") : GF("\"TCP"),
  307. GF("\",\""), host, GF("\","), port, GF(","),
  308. TINY_GSM_TCP_KEEP_ALIVE);
  309. // TODO(?): Check mux
  310. int rsp = waitResponse(timeout_ms, GFP(GSM_OK), GFP(GSM_ERROR),
  311. GF("ALREADY CONNECT"));
  312. // if (rsp == 3) waitResponse();
  313. // May return "ERROR" after the "ALREADY CONNECT"
  314. return (1 == rsp);
  315. }
  316. int16_t modemSend(const void* buff, size_t len, uint8_t mux) {
  317. sendAT(GF("+CIPSEND="), mux, ',', (uint16_t)len);
  318. if (waitResponse(GF(">")) != 1) { return 0; }
  319. stream.write(reinterpret_cast<const uint8_t*>(buff), len);
  320. stream.flush();
  321. if (waitResponse(10000L, GF(GSM_NL "SEND OK" GSM_NL)) != 1) { return 0; }
  322. return len;
  323. }
  324. size_t modemRead(size_t, uint8_t) {
  325. return 0;
  326. }
  327. size_t modemGetAvailable(uint8_t) {
  328. return 0;
  329. }
  330. bool modemGetConnected(uint8_t mux) {
  331. sendAT(GF("+CIPSTATUS"));
  332. if (waitResponse(3000, GF("STATUS:")) != 1) { return false; }
  333. int status = waitResponse(GFP(GSM_ERROR), GF("2"), GF("3"), GF("4"),
  334. GF("5"));
  335. if (status != 3) {
  336. // if the status is anything but 3, there are no connections open
  337. waitResponse(); // Returns an OK after the status
  338. for (int muxNo = 0; muxNo < TINY_GSM_MUX_COUNT; muxNo++) {
  339. sockets[muxNo]->sock_connected = false;
  340. }
  341. return false;
  342. }
  343. bool verified_connections[TINY_GSM_MUX_COUNT] = {0, 0, 0, 0, 0};
  344. for (int muxNo = 0; muxNo < TINY_GSM_MUX_COUNT; muxNo++) {
  345. uint8_t has_status = waitResponse(GF("+CIPSTATUS:"), GFP(GSM_OK),
  346. GFP(GSM_ERROR));
  347. if (has_status == 1) {
  348. int returned_mux = stream.readStringUntil(',').toInt();
  349. streamSkipUntil(','); // Skip mux
  350. streamSkipUntil(','); // Skip type
  351. streamSkipUntil(','); // Skip remote IP
  352. streamSkipUntil(','); // Skip remote port
  353. streamSkipUntil(','); // Skip local port
  354. streamSkipUntil('\n'); // Skip client/server type
  355. verified_connections[returned_mux] = 1;
  356. }
  357. if (has_status == 2) break; // once we get to the ok, stop
  358. }
  359. for (int muxNo = 0; muxNo < TINY_GSM_MUX_COUNT; muxNo++) {
  360. sockets[muxNo]->sock_connected = verified_connections[muxNo];
  361. }
  362. return verified_connections[mux];
  363. }
  364. /*
  365. * Utilities
  366. */
  367. public:
  368. // TODO(vshymanskyy): Optimize this!
  369. uint8_t waitResponse(uint32_t timeout_ms, String& data,
  370. GsmConstStr r1 = GFP(GSM_OK),
  371. GsmConstStr r2 = GFP(GSM_ERROR),
  372. GsmConstStr r3 = GFP(GSM_CME_ERROR),
  373. GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) {
  374. /*String r1s(r1); r1s.trim();
  375. String r2s(r2); r2s.trim();
  376. String r3s(r3); r3s.trim();
  377. String r4s(r4); r4s.trim();
  378. String r5s(r5); r5s.trim();
  379. DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/
  380. data.reserve(64);
  381. uint8_t index = 0;
  382. uint32_t startMillis = millis();
  383. do {
  384. TINY_GSM_YIELD();
  385. while (stream.available() > 0) {
  386. TINY_GSM_YIELD();
  387. int a = stream.read();
  388. if (a <= 0) continue; // Skip 0x00 bytes, just in case
  389. data += static_cast<char>(a);
  390. if (r1 && data.endsWith(r1)) {
  391. index = 1;
  392. goto finish;
  393. } else if (r2 && data.endsWith(r2)) {
  394. index = 2;
  395. goto finish;
  396. } else if (r3 && data.endsWith(r3)) {
  397. index = 3;
  398. goto finish;
  399. } else if (r4 && data.endsWith(r4)) {
  400. index = 4;
  401. goto finish;
  402. } else if (r5 && data.endsWith(r5)) {
  403. index = 5;
  404. goto finish;
  405. } else if (data.endsWith(GF("+IPD,"))) {
  406. int mux = stream.readStringUntil(',').toInt();
  407. int len = stream.readStringUntil(':').toInt();
  408. int len_orig = len;
  409. if (len > sockets[mux]->rx.free()) {
  410. DBG("### Buffer overflow: ", len, "received vs",
  411. sockets[mux]->rx.free(), "available");
  412. } else {
  413. DBG("### Got Data: ", len, "on", mux);
  414. }
  415. while (len--) { moveCharFromStreamToFifo(mux); }
  416. // TODO(SRGDamia1): deal with buffer overflow/missed characters
  417. if (len_orig > sockets[mux]->available()) {
  418. DBG("### Fewer characters received than expected: ",
  419. sockets[mux]->available(), " vs ", len_orig);
  420. }
  421. data = "";
  422. } else if (data.endsWith(GF("CLOSED"))) {
  423. int muxStart =
  424. TinyGsmMax(0, data.lastIndexOf(GSM_NL, data.length() - 8));
  425. int coma = data.indexOf(',', muxStart);
  426. int mux = data.substring(muxStart, coma).toInt();
  427. if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
  428. sockets[mux]->sock_connected = false;
  429. }
  430. data = "";
  431. DBG("### Closed: ", mux);
  432. }
  433. }
  434. } while (millis() - startMillis < timeout_ms);
  435. finish:
  436. if (!index) {
  437. data.trim();
  438. if (data.length()) { DBG("### Unhandled:", data); }
  439. data = "";
  440. }
  441. // data.replace(GSM_NL, "/");
  442. // DBG('<', index, '>', data);
  443. return index;
  444. }
  445. uint8_t waitResponse(uint32_t timeout_ms, GsmConstStr r1 = GFP(GSM_OK),
  446. GsmConstStr r2 = GFP(GSM_ERROR),
  447. GsmConstStr r3 = GFP(GSM_CME_ERROR),
  448. GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) {
  449. String data;
  450. return waitResponse(timeout_ms, data, r1, r2, r3, r4, r5);
  451. }
  452. uint8_t waitResponse(GsmConstStr r1 = GFP(GSM_OK),
  453. GsmConstStr r2 = GFP(GSM_ERROR),
  454. GsmConstStr r3 = GFP(GSM_CME_ERROR),
  455. GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) {
  456. return waitResponse(1000, r1, r2, r3, r4, r5);
  457. }
  458. protected:
  459. Stream& stream;
  460. GsmClientESP8266* sockets[TINY_GSM_MUX_COUNT];
  461. const char* gsmNL = GSM_NL;
  462. };
  463. #endif // SRC_TINYGSMCLIENTESP8266_H_