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.

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