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.

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