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.

568 lines
12 KiB

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