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.

618 lines
14 KiB

8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
  1. /**
  2. * @file TinyGsmClient.h
  3. * @author Volodymyr Shymanskyy
  4. * @license LGPL-3.0
  5. * @copyright Copyright (c) 2016 Volodymyr Shymanskyy
  6. * @date Nov 2016
  7. */
  8. #ifndef TinyGsmClient_h
  9. #define TinyGsmClient_h
  10. #if defined(SPARK) || defined(PARTICLE)
  11. #include "Particle.h"
  12. #elif defined(ARDUINO)
  13. #if ARDUINO >= 100
  14. #include "Arduino.h"
  15. #else
  16. #include "WProgram.h"
  17. #endif
  18. #endif
  19. #include <Client.h>
  20. #include <TinyGsmFifo.h>
  21. #if defined(__AVR__)
  22. #define GSM_PROGMEM PROGMEM
  23. typedef const __FlashStringHelper* GsmConstStr;
  24. #define GFP(x) (reinterpret_cast<GsmConstStr>(x))
  25. #define GF(x) F(x)
  26. #else
  27. #define GSM_PROGMEM
  28. typedef const char* GsmConstStr;
  29. #define GFP(x) x
  30. #define GF(x) x
  31. #endif
  32. //#define GSM_DEBUG Serial
  33. //#define GSM_USE_HEX
  34. #if !defined(TINY_GSM_RX_BUFFER)
  35. #define TINY_GSM_RX_BUFFER 64
  36. #endif
  37. #define GSM_NL "\r\n"
  38. static const char GSM_OK[] GSM_PROGMEM = "OK" GSM_NL;
  39. static const char GSM_ERROR[] GSM_PROGMEM = "ERROR" GSM_NL;
  40. enum SimStatus {
  41. SIM_ERROR = 0,
  42. SIM_READY = 1,
  43. SIM_LOCKED = 2,
  44. };
  45. enum RegStatus {
  46. REG_UNREGISTERED = 0,
  47. REG_SEARCHING = 2,
  48. REG_DENIED = 3,
  49. REG_OK_HOME = 1,
  50. REG_OK_ROAMING = 5,
  51. REG_UNKNOWN = 4,
  52. };
  53. class TinyGsm
  54. {
  55. typedef TinyGsmFifo<uint8_t, TINY_GSM_RX_BUFFER> RxFifo;
  56. #ifdef GSM_DEBUG
  57. template<typename T>
  58. void DBG(T last) {
  59. GSM_DEBUG.println(last);
  60. }
  61. template<typename T, typename... Args>
  62. void DBG(T head, Args... tail) {
  63. GSM_DEBUG.print(head);
  64. GSM_DEBUG.print(' ');
  65. DBG(tail...);
  66. }
  67. #else
  68. #define DBG(...)
  69. #endif
  70. public:
  71. TinyGsm(Stream& stream)
  72. : stream(stream)
  73. {}
  74. public:
  75. class GsmClient : public Client
  76. {
  77. friend class TinyGsm;
  78. typedef TinyGsmFifo<uint8_t, TINY_GSM_RX_BUFFER> RxFifo;
  79. public:
  80. GsmClient() {
  81. init(NULL, -1);
  82. }
  83. GsmClient(TinyGsm& at, uint8_t mux = 1) {
  84. init(&at, mux);
  85. }
  86. bool init(TinyGsm* at, uint8_t mux = 1) {
  87. this->at = at;
  88. this->mux = mux;
  89. at->sockets[mux] = this;
  90. sock_available = 0;
  91. sock_connected = false;
  92. return true;
  93. }
  94. public:
  95. virtual int connect(const char *host, uint16_t port) {
  96. rx.clear();
  97. sock_connected = at->modemConnect(host, port, mux);
  98. return sock_connected;
  99. }
  100. virtual int connect(IPAddress ip, uint16_t port) {
  101. String host; host.reserve(16);
  102. host += ip[0];
  103. host += ".";
  104. host += ip[1];
  105. host += ".";
  106. host += ip[2];
  107. host += ".";
  108. host += ip[3];
  109. return connect(host.c_str(), port);
  110. }
  111. virtual void stop() {
  112. at->sendAT(GF("+CIPCLOSE="), mux);
  113. sock_connected = false;
  114. at->waitResponse();
  115. }
  116. virtual size_t write(const uint8_t *buf, size_t size) {
  117. at->maintain();
  118. return at->modemSend(buf, size, mux);
  119. }
  120. virtual size_t write(uint8_t c) {
  121. return write(&c, 1);
  122. }
  123. virtual int available() {
  124. at->maintain();
  125. return rx.size() + sock_available;
  126. }
  127. virtual int read(uint8_t *buf, size_t size) {
  128. at->maintain();
  129. size_t cnt = 0;
  130. while (cnt < size) {
  131. size_t chunk = min(size-cnt, rx.size());
  132. if (chunk > 0) {
  133. rx.get(buf, chunk);
  134. buf += chunk;
  135. cnt += chunk;
  136. continue;
  137. }
  138. // TODO: Read directly into user buffer?
  139. at->maintain();
  140. if (sock_available > 0) {
  141. at->modemRead(rx.free(), mux);
  142. } else {
  143. break;
  144. }
  145. }
  146. return cnt;
  147. }
  148. virtual int read() {
  149. uint8_t c;
  150. if (read(&c, 1) == 1) {
  151. return c;
  152. }
  153. return -1;
  154. }
  155. virtual int peek() { return -1; } //TODO
  156. virtual void flush() { at->stream.flush(); }
  157. virtual uint8_t connected() {
  158. at->maintain();
  159. return sock_connected;
  160. }
  161. virtual operator bool() { return connected(); }
  162. private:
  163. TinyGsm* at;
  164. uint8_t mux;
  165. uint16_t sock_available;
  166. bool sock_connected;
  167. RxFifo rx;
  168. };
  169. public:
  170. /*
  171. * Basic functions
  172. */
  173. bool begin() {
  174. if (!autoBaud()) {
  175. return false;
  176. }
  177. sendAT(GF("&FZE0")); // Factory + Reset + Echo Off
  178. if (waitResponse() != 1) {
  179. return false;
  180. }
  181. getSimStatus();
  182. return true;
  183. }
  184. bool autoBaud(unsigned long timeout = 10000L) {
  185. for (unsigned long start = millis(); millis() - start < timeout; ) {
  186. sendAT("");
  187. if (waitResponse(200) == 1) {
  188. delay(100);
  189. return true;
  190. }
  191. delay(100);
  192. }
  193. return false;
  194. }
  195. void maintain() {
  196. while (stream.available()) {
  197. waitResponse(10);
  198. }
  199. }
  200. bool factoryDefault() {
  201. sendAT(GF("&FZE0&W")); // Factory + Reset + Echo Off + Write
  202. waitResponse();
  203. sendAT(GF("+IPR=0")); // Auto-baud
  204. waitResponse();
  205. sendAT(GF("+IFC=0,0")); // No Flow Control
  206. waitResponse();
  207. sendAT(GF("+ICF=3,3")); // 8 data 0 parity 1 stop
  208. waitResponse();
  209. sendAT(GF("+CSCLK=0")); // Disable Slow Clock
  210. waitResponse();
  211. sendAT(GF("&W")); // Write configuration
  212. return waitResponse() == 1;
  213. }
  214. /*
  215. * Power functions
  216. */
  217. bool restart() {
  218. return resetSoft();
  219. }
  220. bool resetSoft() {
  221. if (!autoBaud()) {
  222. return false;
  223. }
  224. sendAT(GF("+CFUN=0"));
  225. if (waitResponse(10000L) != 1) {
  226. return false;
  227. }
  228. sendAT(GF("+CFUN=1,1"));
  229. if (waitResponse(10000L) != 1) {
  230. return false;
  231. }
  232. delay(3000);
  233. return begin();
  234. }
  235. // Reboot the module by setting the specified pin LOW, then HIGH.
  236. // (The pin should be connected to a P-MOSFET)
  237. bool resetHard(int pwrPin) {
  238. powerOff(pwrPin);
  239. delay(100);
  240. return powerOn(pwrPin);
  241. }
  242. void powerOff(int pwrPin) {
  243. pinMode(pwrPin, OUTPUT);
  244. digitalWrite(pwrPin, LOW);
  245. }
  246. bool powerOn(int pwrPin) {
  247. pinMode(pwrPin, OUTPUT);
  248. digitalWrite(pwrPin, HIGH);
  249. delay(3000);
  250. return begin();
  251. }
  252. /*
  253. * SIM card & Networ Operator functions
  254. */
  255. bool simUnlock(const char *pin) {
  256. sendAT(GF("+CPIN="), pin);
  257. return waitResponse() == 1;
  258. }
  259. String getSimCCID() {
  260. sendAT(GF("+ICCID"));
  261. if (waitResponse(GF(GSM_NL "+ICCID: ")) != 1) {
  262. return "";
  263. }
  264. String res = stream.readStringUntil('\n');
  265. waitResponse();
  266. res.trim();
  267. return res;
  268. }
  269. SimStatus getSimStatus(unsigned long timeout = 10000L) {
  270. for (unsigned long start = millis(); millis() - start < timeout; ) {
  271. sendAT(GF("+CPIN?"));
  272. if (waitResponse(GF(GSM_NL "+CPIN: ")) != 1) {
  273. delay(1000);
  274. continue;
  275. }
  276. int status = waitResponse(GF("READY"), GF("SIM PIN"), GF("SIM PUK"), GF("NOT INSERTED"));
  277. waitResponse();
  278. switch (status) {
  279. case 2:
  280. case 3: return SIM_LOCKED;
  281. case 1: return SIM_READY;
  282. default: return SIM_ERROR;
  283. }
  284. }
  285. return SIM_ERROR;
  286. }
  287. RegStatus getRegistrationStatus() {
  288. sendAT(GF("+CREG?"));
  289. if (waitResponse(GF(GSM_NL "+CREG: 0,")) != 1) {
  290. return REG_UNKNOWN;
  291. }
  292. int status = stream.readStringUntil('\n').toInt();
  293. waitResponse();
  294. return (RegStatus)status;
  295. }
  296. String getOperator() {
  297. sendAT(GF("+COPS?"));
  298. if (waitResponse(GF(GSM_NL "+COPS: ")) != 1) {
  299. return "";
  300. }
  301. stream.readStringUntil('"'); // Skip mode and format
  302. String res = stream.readStringUntil('"');
  303. waitResponse();
  304. return res;
  305. }
  306. bool waitForNetwork(unsigned long timeout = 60000L) {
  307. for (unsigned long start = millis(); millis() - start < timeout; ) {
  308. RegStatus s = getRegistrationStatus();
  309. if(s == REG_OK_HOME || s == REG_OK_ROAMING) {
  310. return true;
  311. }
  312. delay(1000);
  313. }
  314. return true;
  315. }
  316. /*
  317. * GPRS functions
  318. */
  319. bool gprsConnect(const char* apn, const char* user, const char* pwd) {
  320. gprsDisconnect();
  321. // AT+CGATT?
  322. // AT+CGATT=1
  323. sendAT(GF("+CIPMUX=1"));
  324. if (waitResponse() != 1) {
  325. return false;
  326. }
  327. sendAT(GF("+CIPQSEND=1"));
  328. if (waitResponse() != 1) {
  329. return false;
  330. }
  331. sendAT(GF("+CIPRXGET=1"));
  332. if (waitResponse() != 1) {
  333. return false;
  334. }
  335. sendAT(GF("+CSTT=\""), apn, GF("\",\""), user, GF("\",\""), pwd, GF("\""));
  336. if (waitResponse(60000L) != 1) {
  337. return false;
  338. }
  339. sendAT(GF("+CIICR"));
  340. if (waitResponse(60000L) != 1) {
  341. return false;
  342. }
  343. sendAT(GF("+CIFSR;E0"));
  344. String data;
  345. if (waitResponse(10000L, data) != 1) {
  346. data.replace(GSM_NL, "");
  347. return false;
  348. }
  349. sendAT(GF("+CDNSCFG=\"8.8.8.8\",\"8.8.4.4\""));
  350. if (waitResponse() != 1) {
  351. return false;
  352. }
  353. return true;
  354. }
  355. bool gprsDisconnect() {
  356. sendAT(GF("+CIPSHUT"));
  357. return waitResponse(60000L) == 1;
  358. }
  359. /*
  360. * Phone Call functions
  361. */
  362. /*
  363. * Messaging functions
  364. */
  365. void sendUSSD() {
  366. }
  367. void sendSMS() {
  368. }
  369. /*
  370. * Location functions
  371. */
  372. void getLocation() {
  373. }
  374. /*
  375. * Battery functions
  376. */
  377. private:
  378. int modemConnect(const char* host, uint16_t port, uint8_t mux) {
  379. sendAT(GF("+CIPSTART="), mux, ',', GF("\"TCP"), GF("\",\""), host, GF("\","), port);
  380. int rsp = waitResponse(75000L,
  381. GF("CONNECT OK" GSM_NL),
  382. GF("CONNECT FAIL" GSM_NL),
  383. GF("ALREADY CONNECT" GSM_NL));
  384. return (1 == rsp);
  385. }
  386. int modemSend(const void* buff, size_t len, uint8_t mux) {
  387. sendAT(GF("+CIPSEND="), mux, ',', len);
  388. if (waitResponse(GF(">")) != 1) {
  389. return -1;
  390. }
  391. stream.write((uint8_t*)buff, len);
  392. if (waitResponse(GF(GSM_NL "DATA ACCEPT:")) != 1) {
  393. return -1;
  394. }
  395. stream.readStringUntil(',');
  396. String data = stream.readStringUntil('\n');
  397. return data.toInt();
  398. }
  399. size_t modemRead(size_t size, uint8_t mux) {
  400. #ifdef GSM_USE_HEX
  401. sendAT(GF("+CIPRXGET=3,"), mux, ',', size);
  402. if (waitResponse(GF("+CIPRXGET: 3,")) != 1) {
  403. return 0;
  404. }
  405. #else
  406. sendAT(GF("+CIPRXGET=2,"), mux, ',', size);
  407. if (waitResponse(GF("+CIPRXGET: 2,")) != 1) {
  408. return 0;
  409. }
  410. #endif
  411. stream.readStringUntil(','); // Skip mux
  412. size_t len = stream.readStringUntil(',').toInt();
  413. sockets[mux]->sock_available = stream.readStringUntil('\n').toInt();
  414. for (size_t i=0; i<len; i++) {
  415. #ifdef GSM_USE_HEX
  416. while (stream.available() < 2) { delay(1); }
  417. char buf[4] = { 0, };
  418. buf[0] = stream.read();
  419. buf[1] = stream.read();
  420. char c = strtol(buf, NULL, 16);
  421. #else
  422. while (stream.available() < 1) { delay(1); }
  423. char c = stream.read();
  424. #endif
  425. sockets[mux]->rx.put(c);
  426. }
  427. waitResponse();
  428. return len;
  429. }
  430. size_t modemGetAvailable(uint8_t mux) {
  431. sendAT(GF("+CIPRXGET=4,"), mux);
  432. size_t result = 0;
  433. for (byte i = 0; i < 2; i++) {
  434. int res = waitResponse(GF("+CIPRXGET: 4"), GFP(GSM_OK), GFP(GSM_ERROR));
  435. if (res == 1) {
  436. stream.readStringUntil(',');
  437. stream.readStringUntil(',');
  438. result = stream.readStringUntil('\n').toInt();
  439. } else if (res == 2) {
  440. } else {
  441. return result;
  442. }
  443. }
  444. if (!result) {
  445. sockets[mux]->sock_connected = modemGetConnected(mux);
  446. }
  447. return result;
  448. }
  449. bool modemGetConnected(uint8_t mux) {
  450. sendAT(GF("+CIPSTATUS="), mux);
  451. int res = waitResponse(GF(",\"CONNECTED\""), GF(",\"CLOSED\""), GF(",\"CLOSING\""), GF(",\"INITIAL\""));
  452. waitResponse();
  453. return 1 == res;
  454. }
  455. /* Utilities */
  456. template<typename T>
  457. void streamWrite(T last) {
  458. stream.print(last);
  459. }
  460. template<typename T, typename... Args>
  461. void streamWrite(T head, Args... tail) {
  462. stream.print(head);
  463. streamWrite(tail...);
  464. }
  465. int streamRead() { return stream.read(); }
  466. void streamReadAll() { while(stream.available()) { stream.read(); } }
  467. template<typename... Args>
  468. void sendAT(Args... cmd) {
  469. streamWrite("AT", cmd..., GSM_NL);
  470. //DBG("### AT:", cmd...);
  471. }
  472. // TODO: Optimize this!
  473. uint8_t waitResponse(uint32_t timeout, String& data,
  474. GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
  475. GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
  476. {
  477. data.reserve(64);
  478. bool gotNewData = false;
  479. int index = 0;
  480. for (unsigned long start = millis(); millis() - start < timeout; ) {
  481. while (stream.available() > 0) {
  482. int a = streamRead();
  483. if (a <= 0) continue;
  484. data += (char)a;
  485. if (r1 && data.indexOf(r1) >= 0) {
  486. index = 1;
  487. goto finish;
  488. } else if (r2 && data.indexOf(r2) >= 0) {
  489. index = 2;
  490. goto finish;
  491. } else if (r3 && data.indexOf(r3) >= 0) {
  492. index = 3;
  493. goto finish;
  494. } else if (r4 && data.indexOf(r4) >= 0) {
  495. index = 4;
  496. goto finish;
  497. } else if (r5 && data.indexOf(r5) >= 0) {
  498. index = 5;
  499. goto finish;
  500. } else if (data.indexOf(GF(GSM_NL "+CIPRXGET: 1,1" GSM_NL)) >= 0) { //TODO: use mux
  501. gotNewData = true;
  502. data = "";
  503. } else if (data.indexOf(GF(GSM_NL "1, CLOSED" GSM_NL)) >= 0) { //TODO: use mux
  504. sockets[1]->sock_connected = false;
  505. data = "";
  506. }
  507. }
  508. }
  509. finish:
  510. if (!index) {
  511. if (data.length()) {
  512. DBG("### Unhandled:", data);
  513. }
  514. data = "";
  515. }
  516. if (gotNewData) {
  517. sockets[1]->sock_available = modemGetAvailable(1);
  518. }
  519. return index;
  520. }
  521. uint8_t waitResponse(uint32_t timeout,
  522. GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
  523. GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
  524. {
  525. String data;
  526. return waitResponse(timeout, data, r1, r2, r3, r4, r5);
  527. }
  528. uint8_t waitResponse(GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
  529. GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
  530. {
  531. return waitResponse(1000, r1, r2, r3, r4, r5);
  532. }
  533. private:
  534. Stream& stream;
  535. GsmClient* sockets[5];
  536. };
  537. typedef TinyGsm::GsmClient TinyGsmClient;
  538. #endif