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

  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. if (modemGetConnected()) {
  239. return true;
  240. }
  241. delay(1000);
  242. }
  243. return false;
  244. }
  245. /*
  246. * WiFi functions
  247. */
  248. bool networkConnect(const char* ssid, const char* pwd) {
  249. commandMode();
  250. sendAT(GF("AP"), 0); // Put in transparent mode
  251. waitResponse();
  252. sendAT(GF("IP"), 1); // Put in TCP mode
  253. waitResponse();
  254. sendAT(GF("ID"), ssid);
  255. if (waitResponse() != 1) {
  256. goto fail;
  257. }
  258. sendAT(GF("PK"), pwd);
  259. if (waitResponse() != 1) {
  260. goto fail;
  261. }
  262. writeChanges();
  263. exitCommand();
  264. return true;
  265. fail:
  266. exitCommand();
  267. return false;
  268. }
  269. bool networkDisconnect() {
  270. return false; // Doesn't support disconnecting
  271. }
  272. /*
  273. * GPRS functions
  274. */
  275. bool gprsConnect(const char* apn, const char* user = "", const char* pw = "") {
  276. commandMode();
  277. sendAT(GF("AP"), 0); // Put in transparent mode
  278. waitResponse();
  279. sendAT(GF("IP"), 0); // Put in UDP mode
  280. waitResponse();
  281. sendAT(GF("AN"), apn);
  282. waitResponse();
  283. return true;
  284. }
  285. bool gprsDisconnect() { // TODO
  286. return false;
  287. }
  288. /*
  289. * Messaging functions
  290. */
  291. void sendUSSD() {
  292. }
  293. void sendSMS() {
  294. }
  295. bool sendSMS(const String& number, const String& text) {
  296. commandMode();
  297. sendAT(GF("AP"), 0);
  298. waitResponse();
  299. sendAT(GF("IP"), 2);
  300. waitResponse();
  301. sendAT(GF("PH"), number);
  302. waitResponse();
  303. sendAT(GF("TD D"));
  304. waitResponse();
  305. sendAT(GF("TD D"));
  306. waitResponse();
  307. writeChanges();
  308. exitCommand();
  309. stream.print(text);
  310. stream.write((char)0x0D);
  311. return true;
  312. }
  313. /* Public Utilities */
  314. template<typename... Args>
  315. void sendAT(Args... cmd) {
  316. streamWrite("AT", cmd..., GSM_NL);
  317. stream.flush();
  318. TINY_GSM_YIELD();
  319. DBG("\r\n", ">>> AT:", cmd...);
  320. }
  321. // TODO: Optimize this!
  322. uint8_t waitResponse(uint32_t timeout, String& data,
  323. GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
  324. GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
  325. {
  326. /*String r1s(r1); r1s.trim();
  327. String r2s(r2); r2s.trim();
  328. String r3s(r3); r3s.trim();
  329. String r4s(r4); r4s.trim();
  330. String r5s(r5); r5s.trim();
  331. DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/
  332. data.reserve(64);
  333. int index = 0;
  334. unsigned long startMillis = millis();
  335. do {
  336. TINY_GSM_YIELD();
  337. while (stream.available() > 0) {
  338. int a = streamRead();
  339. if (a <= 0) continue; // Skip 0x00 bytes, just in case
  340. data += (char)a;
  341. if (r1 && data.endsWith(r1)) {
  342. index = 1;
  343. goto finish;
  344. } else if (r2 && data.endsWith(r2)) {
  345. index = 2;
  346. goto finish;
  347. } else if (r3 && data.endsWith(r3)) {
  348. index = 3;
  349. goto finish;
  350. } else if (r4 && data.endsWith(r4)) {
  351. index = 4;
  352. goto finish;
  353. } else if (r5 && data.endsWith(r5)) {
  354. index = 5;
  355. goto finish;
  356. }
  357. }
  358. } while (millis() - startMillis < timeout);
  359. finish:
  360. if (!index) {
  361. data.trim();
  362. if (data.length()) {
  363. DBG("### Unhandled:", data);
  364. }
  365. data = "";
  366. }
  367. else {
  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(GSM_NL, "<<< ", data);
  373. }
  374. }
  375. // if (gotData) {
  376. // sockets[mux]->sock_available = modemGetAvailable(mux);
  377. // }
  378. data = "";
  379. return index;
  380. }
  381. uint8_t waitResponse(uint32_t timeout,
  382. GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
  383. GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
  384. {
  385. String data;
  386. return waitResponse(timeout, data, r1, r2, r3, r4, r5);
  387. }
  388. uint8_t waitResponse(GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
  389. GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
  390. {
  391. return waitResponse(1000, r1, r2, r3, r4, r5);
  392. }
  393. private:
  394. int modemConnect(const char* host, uint16_t port, uint8_t mux = 1) {
  395. sendAT(GF("LA"), host);
  396. String ipadd; ipadd.reserve(16);
  397. ipadd = streamReadUntil('\r');
  398. IPAddress ip;
  399. ip.fromString(ipadd);
  400. return modemConnect(ip, port);
  401. }
  402. int modemConnect(IPAddress ip, uint16_t port, uint8_t mux = 1) {
  403. String host; host.reserve(16);
  404. host += ip[0];
  405. host += ".";
  406. host += ip[1];
  407. host += ".";
  408. host += ip[2];
  409. host += ".";
  410. host += ip[3];
  411. sendAT(GF("DL"), host);
  412. waitResponse();
  413. sendAT(GF("DE"), String(port, HEX));
  414. int rsp = waitResponse();
  415. return rsp;
  416. }
  417. int modemSend(const void* buff, size_t len, uint8_t mux = 1) {
  418. stream.write((uint8_t*)buff, len);
  419. return len;
  420. }
  421. bool modemGetConnected(uint8_t mux = 1) {
  422. commandMode();
  423. sendAT(GF("AI"));
  424. int res = waitResponse(GF("0"));
  425. exitCommand();
  426. return 1 == res;
  427. }
  428. /* Private Utilities */
  429. template<typename T>
  430. void streamWrite(T last) {
  431. stream.print(last);
  432. }
  433. template<typename T, typename... Args>
  434. void streamWrite(T head, Args... tail) {
  435. stream.print(head);
  436. streamWrite(tail...);
  437. }
  438. int streamRead() { return stream.read(); }
  439. String streamReadUntil(char c) {
  440. String return_string = stream.readStringUntil(c);
  441. return_string.trim();
  442. if (String(c) == GSM_NL || String(c) == "\n"){
  443. DBG(return_string, c, " ");
  444. } else DBG(return_string, c);
  445. return return_string;
  446. }
  447. bool commandMode(void){
  448. delay(1000); // cannot send anything for 1 second before entering command mode
  449. streamWrite(GF("+++")); // enter command mode
  450. waitResponse(1100);
  451. return 1 == waitResponse(1100); // wait another second for an "OK\r"
  452. }
  453. void writeChanges(void){
  454. sendAT(GF("WR")); // Write changes to flash
  455. waitResponse();
  456. sendAT(GF("AC")); // Apply changes
  457. waitResponse();
  458. }
  459. void exitCommand(void){
  460. sendAT(GF("CN")); // Exit command mode
  461. waitResponse();
  462. }
  463. private:
  464. Stream& stream;
  465. GsmClient* sockets[1];
  466. };
  467. typedef TinyGsm::GsmClient TinyGsmClient;
  468. #endif