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.

551 lines
12 KiB

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