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.

555 lines
12 KiB

7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
  1. /**
  2. * @file TinyWiFiClientESP8266.h
  3. * @author Volodymyr Shymanskyy
  4. * @license LGPL-3.0
  5. * @copyright Copyright (c) 2016 Volodymyr Shymanskyy
  6. * @date Nov 2016
  7. */
  8. #ifndef TinyGsmClientXBee_h
  9. #define TinyGsmClientXBee_h
  10. // #define TINY_GSM_DEBUG Serial
  11. #if !defined(TINY_GSM_RX_BUFFER)
  12. #define TINY_GSM_RX_BUFFER 256
  13. #endif
  14. #include <TinyGsmCommon.h>
  15. #define GSM_NL "\r"
  16. static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL;
  17. static const char GSM_ERROR[] TINY_GSM_PROGMEM = "ERROR" GSM_NL;
  18. enum SimStatus {
  19. SIM_ERROR = 0,
  20. SIM_READY = 1,
  21. SIM_LOCKED = 2,
  22. };
  23. enum RegStatus {
  24. REG_UNREGISTERED = 0,
  25. REG_SEARCHING = 2,
  26. REG_DENIED = 3,
  27. REG_OK_HOME = 1,
  28. REG_OK_ROAMING = 5,
  29. REG_UNKNOWN = 4,
  30. };
  31. class TinyGsm
  32. {
  33. public:
  34. TinyGsm(Stream& stream)
  35. : stream(stream)
  36. {}
  37. public:
  38. class GsmClient : public Client
  39. {
  40. friend class TinyGsm;
  41. public:
  42. GsmClient() {}
  43. GsmClient(TinyGsm& modem, uint8_t mux = 1) {
  44. init(&modem, mux);
  45. }
  46. bool init(TinyGsm* 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) {
  55. TINY_GSM_YIELD();
  56. at->commandMode();
  57. sock_connected = at->modemConnect(host, port, mux);
  58. at->writeChanges();
  59. at->exitCommand();
  60. return sock_connected;
  61. }
  62. virtual int connect(IPAddress ip, uint16_t port) {
  63. TINY_GSM_YIELD();
  64. at->commandMode();
  65. sock_connected = at->modemConnect(ip, port, mux);
  66. at->writeChanges();
  67. at->exitCommand();
  68. return sock_connected;
  69. }
  70. virtual void stop() { // Not supported
  71. sock_connected = false;
  72. }
  73. virtual size_t write(const uint8_t *buf, size_t size) {
  74. TINY_GSM_YIELD();
  75. //at->maintain();
  76. return at->modemSend(buf, size, mux);
  77. }
  78. virtual size_t write(uint8_t c) {
  79. return write(&c, 1);
  80. }
  81. virtual int available() {
  82. TINY_GSM_YIELD();
  83. return at->stream.available();
  84. }
  85. virtual int read(uint8_t *buf, size_t size) {
  86. return available();
  87. }
  88. virtual int read() {
  89. TINY_GSM_YIELD();
  90. return at->stream.read();
  91. }
  92. virtual int peek() { return at->stream.peek(); }
  93. virtual void flush() { at->stream.flush(); }
  94. virtual uint8_t connected() {
  95. if (available()) {
  96. return true;
  97. }
  98. return sock_connected;
  99. }
  100. virtual operator bool() { return connected(); }
  101. private:
  102. TinyGsm* at;
  103. uint8_t mux;
  104. bool sock_connected;
  105. };
  106. public:
  107. /*
  108. * Basic functions
  109. */
  110. bool begin() {
  111. return init();
  112. }
  113. bool init() {
  114. guardTime = 1100;
  115. commandMode();
  116. sendAT(GF("AP0")); // Put in transparent mode
  117. waitResponse();
  118. sendAT(GF("GTC8")); // shorten the guard time to 200ms
  119. waitResponse();
  120. writeChanges();
  121. exitCommand();
  122. guardTime = 225;
  123. return true;
  124. }
  125. bool autoBaud(unsigned long timeout = 10000L) { // not supported
  126. return false;
  127. }
  128. void maintain() {
  129. //while (stream.available()) {
  130. waitResponse(10, NULL, NULL);
  131. //}
  132. }
  133. bool factoryDefault() {
  134. commandMode();
  135. sendAT(GF("RE"));
  136. bool ret_val = waitResponse() == 1;
  137. writeChanges();
  138. exitCommand();
  139. return ret_val;
  140. }
  141. /*
  142. * Power functions
  143. */
  144. bool restart() {
  145. commandMode();
  146. sendAT(GF("FR"));
  147. if (waitResponse() != 1) {
  148. return false;
  149. }
  150. delay (2000); // Actually resets about 2 seconds later
  151. for (unsigned long start = millis(); millis() - start < 60000L; ) {
  152. if (commandMode()) {
  153. exitCommand();
  154. return true;
  155. }
  156. }
  157. exitCommand();
  158. return false;;
  159. }
  160. void setupPinSleep() {
  161. commandMode();
  162. sendAT(GF("SM"),1);
  163. waitResponse();
  164. sendAT(GF("SO"),200);
  165. waitResponse();
  166. writeChanges();
  167. exitCommand();
  168. }
  169. /*
  170. * SIM card & Networ Operator functions
  171. */
  172. bool simUnlock(const char *pin) { // Not supported
  173. return false;
  174. }
  175. String getSimCCID() {
  176. commandMode();
  177. sendAT(GF("S#"));
  178. String res = streamReadUntil('\r'); // Does not send an OK, just the result
  179. exitCommand();
  180. return res;
  181. }
  182. String getIMEI() {
  183. commandMode();
  184. sendAT(GF("IM"));
  185. String res = streamReadUntil('\r'); // Does not send an OK, just the result
  186. exitCommand();
  187. return res;
  188. }
  189. int getSignalQuality() {
  190. commandMode();
  191. sendAT(GF("DB"));
  192. char buf[4] = { 0, }; // Does not send an OK, just the result
  193. buf[0] = streamRead();
  194. buf[1] = streamRead();
  195. buf[2] = streamRead();
  196. buf[3] = streamRead();
  197. exitCommand();
  198. int intr = strtol(buf, 0, 16);
  199. return intr;
  200. }
  201. SimStatus getSimStatus(unsigned long timeout = 10000L) {
  202. return SIM_READY; // unsupported
  203. }
  204. RegStatus getRegistrationStatus() {
  205. commandMode();
  206. sendAT(GF("AI"));
  207. String res = streamReadUntil('\r'); // Does not send an OK, just the result
  208. exitCommand();
  209. if(res == GF("0x00"))
  210. return REG_OK_HOME;
  211. else if(res == GF("0x13") || res == GF("0x2A"))
  212. return REG_UNREGISTERED;
  213. else if(res == GF("0xFF") || res == GF("0x22") || res == GF("0x23") ||
  214. res == GF("0x40") || res == GF("0x41") || res == GF("0x42"))
  215. return REG_SEARCHING;
  216. else if(res == GF("0x24"))
  217. return REG_DENIED;
  218. else return REG_UNKNOWN;
  219. }
  220. String getOperator() {
  221. commandMode();
  222. sendAT(GF("MN"));
  223. String res = streamReadUntil('\r'); // Does not send an OK, just the result
  224. exitCommand();
  225. return res;
  226. }
  227. bool waitForNetwork(unsigned long timeout = 60000L) {
  228. for (unsigned long start = millis(); millis() - start < timeout; ) {
  229. commandMode();
  230. sendAT(GF("AI"));
  231. String res = streamReadUntil('\r'); // Does not send an OK, just the result
  232. exitCommand();
  233. if (res == GF("0")) {
  234. return true;
  235. }
  236. delay(1000);
  237. }
  238. return false;
  239. }
  240. /*
  241. * WiFi functions
  242. */
  243. bool networkConnect(const char* ssid, const char* pwd) {
  244. commandMode();
  245. sendAT(GF("AP"), 0); // Put in transparent mode
  246. waitResponse();
  247. sendAT(GF("IP"), 1); // Put in TCP mode
  248. waitResponse();
  249. sendAT(GF("EE"), 2); // Set security to WPA2
  250. waitResponse();
  251. sendAT(GF("ID"), ssid);
  252. if (waitResponse() != 1) {
  253. goto fail;
  254. }
  255. sendAT(GF("PK"), pwd);
  256. if (waitResponse() != 1) {
  257. goto fail;
  258. }
  259. writeChanges();
  260. exitCommand();
  261. return true;
  262. fail:
  263. exitCommand();
  264. return false;
  265. }
  266. bool networkDisconnect() {
  267. return false; // Doesn't support disconnecting
  268. }
  269. /*
  270. * GPRS functions
  271. */
  272. bool gprsConnect(const char* apn, const char* user = "", const char* pw = "") {
  273. commandMode();
  274. sendAT(GF("AP"), 0); // Put in transparent mode
  275. waitResponse();
  276. sendAT(GF("IP"), 1); // Put in TCP mode
  277. waitResponse();
  278. sendAT(GF("AN"), apn); // Set the APN
  279. waitResponse();
  280. writeChanges();
  281. exitCommand();
  282. return true;
  283. }
  284. bool gprsDisconnect() { // TODO
  285. return false;
  286. }
  287. /*
  288. * Messaging functions
  289. */
  290. void sendUSSD() {
  291. }
  292. void sendSMS() {
  293. }
  294. bool sendSMS(const String& number, const String& text) {
  295. commandMode();
  296. sendAT(GF("AP"), 0); // Put in transparent mode
  297. waitResponse();
  298. sendAT(GF("IP"), 2); // Put in text messaging mode
  299. waitResponse();
  300. sendAT(GF("PH"), number); // Set the phone number
  301. waitResponse();
  302. sendAT(GF("TDD")); // Set the text delimiter to the standard 0x0D (carriabe return)
  303. waitResponse();
  304. writeChanges();
  305. exitCommand();
  306. stream.print(text);
  307. stream.write((char)0x0D); // close off with the carriage return
  308. return true;
  309. }
  310. /* Public Utilities */
  311. template<typename... Args>
  312. void sendAT(Args... cmd) {
  313. streamWrite("AT", cmd..., GSM_NL);
  314. stream.flush();
  315. TINY_GSM_YIELD();
  316. DBG(">>> AT ", cmd..., "\r\n");
  317. }
  318. // TODO: Optimize this!
  319. uint8_t waitResponse(uint32_t timeout, String& data,
  320. GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
  321. GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
  322. {
  323. /*String r1s(r1); r1s.trim();
  324. String r2s(r2); r2s.trim();
  325. String r3s(r3); r3s.trim();
  326. String r4s(r4); r4s.trim();
  327. String r5s(r5); r5s.trim();
  328. DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/
  329. data.reserve(64);
  330. int index = 0;
  331. unsigned long startMillis = millis();
  332. do {
  333. TINY_GSM_YIELD();
  334. while (stream.available() > 0) {
  335. int a = streamRead();
  336. if (a <= 0) continue; // Skip 0x00 bytes, just in case
  337. data += (char)a;
  338. if (r1 && data.endsWith(r1)) {
  339. index = 1;
  340. goto finish;
  341. } else if (r2 && data.endsWith(r2)) {
  342. index = 2;
  343. goto finish;
  344. } else if (r3 && data.endsWith(r3)) {
  345. index = 3;
  346. goto finish;
  347. } else if (r4 && data.endsWith(r4)) {
  348. index = 4;
  349. goto finish;
  350. } else if (r5 && data.endsWith(r5)) {
  351. index = 5;
  352. goto finish;
  353. }
  354. }
  355. } while (millis() - startMillis < timeout);
  356. finish:
  357. if (!index) {
  358. data.trim();
  359. data.replace(GSM_NL GSM_NL, GSM_NL);
  360. data.replace(GSM_NL, "\r\n" " ");
  361. if (data.length()) {
  362. DBG("### Unhandled:", data);
  363. }
  364. }
  365. else {
  366. data.trim();
  367. data.replace(GSM_NL GSM_NL, GSM_NL);
  368. data.replace(GSM_NL, "\r\n ");
  369. if (data.length()) {
  370. DBG("<<< ", data, "\r\n");
  371. }
  372. }
  373. // if (gotData) {
  374. // sockets[mux]->sock_available = modemGetAvailable(mux);
  375. // }
  376. return index;
  377. }
  378. uint8_t waitResponse(uint32_t timeout,
  379. GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
  380. GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
  381. {
  382. String data;
  383. return waitResponse(timeout, data, r1, r2, r3, r4, r5);
  384. }
  385. uint8_t waitResponse(GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
  386. GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
  387. {
  388. return waitResponse(1000, r1, r2, r3, r4, r5);
  389. }
  390. private:
  391. int modemConnect(const char* host, uint16_t port, uint8_t mux = 1) {
  392. sendAT(GF("LA"), host);
  393. String ipadd; ipadd.reserve(16);
  394. ipadd = streamReadUntil('\r');
  395. IPAddress ip;
  396. ip.fromString(ipadd);
  397. return modemConnect(ip, port);
  398. }
  399. int modemConnect(IPAddress ip, uint16_t port, uint8_t mux = 1) {
  400. String host; host.reserve(16);
  401. host += ip[0];
  402. host += ".";
  403. host += ip[1];
  404. host += ".";
  405. host += ip[2];
  406. host += ".";
  407. host += ip[3];
  408. sendAT(GF("DL"), host);
  409. waitResponse();
  410. sendAT(GF("DE"), String(port, HEX));
  411. int rsp = waitResponse();
  412. return rsp;
  413. }
  414. int modemSend(const void* buff, size_t len, uint8_t mux = 1) {
  415. stream.write((uint8_t*)buff, len);
  416. return len;
  417. }
  418. bool modemGetConnected(uint8_t mux = 1) {
  419. commandMode();
  420. sendAT(GF("AI"));
  421. int res = waitResponse(GF("0"));
  422. exitCommand();
  423. return 1 == res;
  424. }
  425. /* Private Utilities */
  426. template<typename T>
  427. void streamWrite(T last) {
  428. stream.print(last);
  429. }
  430. template<typename T, typename... Args>
  431. void streamWrite(T head, Args... tail) {
  432. stream.print(head);
  433. streamWrite(tail...);
  434. }
  435. int streamRead() {
  436. int c = stream.read();
  437. DBG((char)c);
  438. return c;
  439. }
  440. String streamReadUntil(char c) {
  441. String return_string = stream.readStringUntil(c);
  442. return_string.trim();
  443. if (String(c) == GSM_NL){
  444. DBG(return_string, "\r\n");
  445. } else DBG(return_string, c);
  446. return return_string;
  447. }
  448. bool commandMode(void){
  449. delay(guardTime); // cannot send anything for 1 second before entering command mode
  450. streamWrite(GF("+++")); // enter command mode
  451. DBG("\r\n+++\r\n");
  452. waitResponse(guardTime);
  453. return 1 == waitResponse(1100); // wait another second for an "OK\r"
  454. }
  455. void writeChanges(void){
  456. sendAT(GF("WR")); // Write changes to flash
  457. waitResponse();
  458. sendAT(GF("AC")); // Apply changes
  459. waitResponse();
  460. }
  461. void exitCommand(void){
  462. sendAT(GF("CN")); // Exit command mode
  463. waitResponse();
  464. }
  465. private:
  466. int guardTime;
  467. Stream& stream;
  468. GsmClient* sockets[1];
  469. };
  470. typedef TinyGsm::GsmClient TinyGsmClient;
  471. #endif