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.

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