support library for C027 helper functions for Buffer Pipes, Buffered Serial Port (rtos capable) and GPS parsing. It includes modem APIs for USSD, SMS and Sockets.

Dependents:   HTTPClient_Cellular_HelloWorld Cellular_HelloMQTT MbedSmartRestMain Car_Bon_car_module ... more

This library is intended to be used with u-blox products such as the C027 or a shield with u-blox cellular and GPS modules like the cellular and positioning shield from Embedded Artist.

For 2G/GSM and 3G/UMTS you need to:

  • have a SIM card and know its PIN number
  • need to know you network operators APN setting These setting should be passed to the connect or init and join functions. You can also extend the APN database in MDMAPN.h.

For CDMA products you need to make sure that you have provisioned and activated the modem with either Sprint or Verizon.

Committer:
mazgch
Date:
Wed May 28 07:09:38 2014 +0000
Revision:
81:3966a5c17037
Parent:
80:34985b4d821e
Child:
82:055dcfcf9dcc
add verizon provisioning

Who changed what in which revision?

UserRevisionLine numberNew contents of line
mazgch 18:e5697801df29 1 #include "mbed.h"
mazgch 18:e5697801df29 2 #include "MDM.h"
mazgch 74:208e3e32d263 3 #include "Relax.h"
mazgch 74:208e3e32d263 4 #ifdef TARGET_UBLOX_C027
mazgch 74:208e3e32d263 5 #include "C027_api.h"
mazgch 74:208e3e32d263 6 #endif
mazgch 18:e5697801df29 7
mazgch 74:208e3e32d263 8 #define PROFILE "0" //!< this is the psd profile used
mazgch 74:208e3e32d263 9 #define MAX_SIZE 128 //!< max expected messages
mazgch 74:208e3e32d263 10 //! test if it is a socket
mazgch 21:c4d64830bf02 11 #define ISSOCKET(s) (((s) >= 0) && ((s) < (sizeof(_sockets)/sizeof(*_sockets))))
mazgch 75:ce6e12067d0c 12 //! check for timeout
mazgch 75:ce6e12067d0c 13 #define TIMEOUT(t, ms) ((ms != TIMEOUT_BLOCKING) && (ms < t.read_ms()))
mazgch 80:34985b4d821e 14 //! registration ok check helper
mazgch 79:291df065e345 15 #define REG_OK(r) ((r == REG_HOME) || (r == REG_ROAMING))
mazgch 80:34985b4d821e 16 //! registration done check helper (no need to poll further)
mazgch 79:291df065e345 17 #define REG_DONE(r) ((r == REG_HOME) || (r == REG_ROAMING) || (r == REG_DENIED))
mazgch 79:291df065e345 18
mazgch 74:208e3e32d263 19 #ifdef MDM_DEBUG
mazgch 74:208e3e32d263 20 void dumpAtCmd(const char* buf, int len)
mazgch 21:c4d64830bf02 21 {
mazgch 75:ce6e12067d0c 22 ::printf(" %3d \"", len);
mazgch 21:c4d64830bf02 23 while (len --) {
mazgch 21:c4d64830bf02 24 char ch = *buf++;
mazgch 75:ce6e12067d0c 25 if ((ch > 0x1F) && (ch != 0x7F)) { // is printable
mazgch 75:ce6e12067d0c 26 if (ch == '%') ::printf("%%");
mazgch 75:ce6e12067d0c 27 else if (ch == '"') ::printf("\\\"");
mazgch 75:ce6e12067d0c 28 else if (ch == '\\') ::printf("\\\\");
mazgch 75:ce6e12067d0c 29 else putchar(ch);
mazgch 75:ce6e12067d0c 30 } else {
mazgch 75:ce6e12067d0c 31 if (ch == '\a') ::printf("\\a"); // BEL (0x07)
mazgch 75:ce6e12067d0c 32 else if (ch == '\b') ::printf("\\b"); // Backspace (0x08)
mazgch 75:ce6e12067d0c 33 else if (ch == '\t') ::printf("\\t"); // Horizontal Tab (0x09)
mazgch 75:ce6e12067d0c 34 else if (ch == '\n') ::printf("\\n"); // Linefeed (0x0A)
mazgch 75:ce6e12067d0c 35 else if (ch == '\v') ::printf("\\v"); // Vertical Tab (0x0B)
mazgch 75:ce6e12067d0c 36 else if (ch == '\f') ::printf("\\f"); // Formfeed (0x0C)
mazgch 75:ce6e12067d0c 37 else if (ch == '\r') ::printf("\\r"); // Carriage Return (0x0D)
mazgch 76:f7c3dd568dae 38 else ::printf("\\x%02x", (unsigned char)ch);
mazgch 75:ce6e12067d0c 39 }
mazgch 21:c4d64830bf02 40 }
mazgch 75:ce6e12067d0c 41 ::printf("\"\r\n");
mazgch 21:c4d64830bf02 42 }
mazgch 74:208e3e32d263 43
mazgch 75:ce6e12067d0c 44 #define ERROR(fmt) (_debugLevel < 0) ? : ::printf(RED(fmt))
mazgch 75:ce6e12067d0c 45 #define INFO(fmt) (_debugLevel < 1) ? : ::printf(GRE(fmt))
mazgch 75:ce6e12067d0c 46 #define TRACE(...) (_debugLevel < 2) ? : ::printf(__VA_ARGS__)
mazgch 74:208e3e32d263 47
mazgch 31:a0bed6c1e05d 48 #if 1 // colored terminal output using ANSI escape sequences
mazgch 75:ce6e12067d0c 49 #define COL(c,t) "\033[" c t "\033[" "39m"
mazgch 31:a0bed6c1e05d 50 #else
mazgch 31:a0bed6c1e05d 51 #define COL(c,t) t
mazgch 31:a0bed6c1e05d 52 #endif
mazgch 31:a0bed6c1e05d 53 #define BLA(t) COL("30m",t)
mazgch 31:a0bed6c1e05d 54 #define RED(t) COL("31m",t)
mazgch 31:a0bed6c1e05d 55 #define GRE(t) COL("32m",t)
mazgch 31:a0bed6c1e05d 56 #define YEL(t) COL("33m",t)
mazgch 31:a0bed6c1e05d 57 #define BLU(t) COL("34m",t)
mazgch 31:a0bed6c1e05d 58 #define MAG(t) COL("35m",t)
mazgch 31:a0bed6c1e05d 59 #define CYA(t) COL("36m",t)
mazgch 31:a0bed6c1e05d 60 #define WHY(t) COL("37m",t)
mazgch 74:208e3e32d263 61
mazgch 74:208e3e32d263 62 #else
mazgch 74:208e3e32d263 63
mazgch 75:ce6e12067d0c 64 #define ERROR(...) (void)0 // no tracing
mazgch 74:208e3e32d263 65 #define INFO(...) (void)0 // no tracing
mazgch 74:208e3e32d263 66 #define TRACE(...) (void)0 // no tracing
mazgch 74:208e3e32d263 67
mazgch 31:a0bed6c1e05d 68 #endif
mazgch 21:c4d64830bf02 69
mazgch 44:9d12223b78ff 70 MDMParser* MDMParser::inst;
mazgch 44:9d12223b78ff 71
mazgch 21:c4d64830bf02 72 MDMParser::MDMParser(void)
mazgch 21:c4d64830bf02 73 {
mazgch 44:9d12223b78ff 74 inst = this;
mazgch 31:a0bed6c1e05d 75 memset(&_dev, 0, sizeof(_dev));
mazgch 31:a0bed6c1e05d 76 memset(&_net, 0, sizeof(_net));
mazgch 54:7ba8e4c218e2 77 _net.lac = 0xFFFF;
mazgch 54:7ba8e4c218e2 78 _net.ci = 0xFFFFFFFF;
mazgch 35:9275215a3a5b 79 _ip = NOIP;
mazgch 76:f7c3dd568dae 80 _init = false;
mazgch 31:a0bed6c1e05d 81 memset(_sockets, 0, sizeof(_sockets));
mazgch 74:208e3e32d263 82 #ifdef MDM_DEBUG
mazgch 76:f7c3dd568dae 83 _debugLevel = 1;
mazgch 74:208e3e32d263 84 _debugTime.start();
mazgch 74:208e3e32d263 85 #endif
mazgch 74:208e3e32d263 86 }
mazgch 74:208e3e32d263 87
mazgch 18:e5697801df29 88 int MDMParser::send(const char* buf, int len)
mazgch 18:e5697801df29 89 {
mazgch 74:208e3e32d263 90 #ifdef MDM_DEBUG
mazgch 74:208e3e32d263 91 if (_debugLevel >= 3) {
mazgch 75:ce6e12067d0c 92 ::printf("%10.3f AT send ", _debugTime.read_ms()*0.001);
mazgch 74:208e3e32d263 93 dumpAtCmd(buf,len);
mazgch 74:208e3e32d263 94 }
mazgch 21:c4d64830bf02 95 #endif
mazgch 18:e5697801df29 96 return _send(buf, len);
mazgch 18:e5697801df29 97 }
mazgch 18:e5697801df29 98
mazgch 21:c4d64830bf02 99 int MDMParser::sendFormated(const char* format, ...) {
mazgch 21:c4d64830bf02 100 char buf[MAX_SIZE];
mazgch 21:c4d64830bf02 101 va_list args;
mazgch 21:c4d64830bf02 102 va_start(args, format);
mazgch 21:c4d64830bf02 103 int len = vsnprintf(buf,sizeof(buf), format, args);
mazgch 21:c4d64830bf02 104 va_end(args);
mazgch 21:c4d64830bf02 105 return send(buf, len);
mazgch 21:c4d64830bf02 106 }
mazgch 21:c4d64830bf02 107
mazgch 26:07be5faf8925 108 int MDMParser::waitFinalResp(_CALLBACKPTR cb /* = NULL*/,
mazgch 26:07be5faf8925 109 void* param /* = NULL*/,
mazgch 26:07be5faf8925 110 int timeout_ms /*= 5000*/)
mazgch 26:07be5faf8925 111 {
mazgch 69:4d6fa520dfca 112 char buf[MAX_SIZE + 64 /* add some more space for framing */];
mazgch 21:c4d64830bf02 113 Timer timer;
mazgch 21:c4d64830bf02 114 timer.start();
mazgch 21:c4d64830bf02 115 do {
mazgch 21:c4d64830bf02 116 int ret = getLine(buf, sizeof(buf));
mazgch 74:208e3e32d263 117 #ifdef MDM_DEBUG
mazgch 74:208e3e32d263 118 if ((_debugLevel >= 3) && (ret != WAIT) && (ret != NOT_FOUND))
mazgch 21:c4d64830bf02 119 {
mazgch 31:a0bed6c1e05d 120 int len = LENGTH(ret);
mazgch 31:a0bed6c1e05d 121 int type = TYPE(ret);
mazgch 31:a0bed6c1e05d 122 const char* s = (type == TYPE_UNKNOWN)? YEL("UNK") :
mazgch 35:9275215a3a5b 123 (type == TYPE_TEXT) ? MAG("TXT") :
mazgch 53:cb0d94b9de3a 124 (type == TYPE_OK ) ? GRE("OK ") :
mazgch 31:a0bed6c1e05d 125 (type == TYPE_ERROR) ? RED("ERR") :
mazgch 31:a0bed6c1e05d 126 (type == TYPE_PLUS) ? CYA(" + ") :
mazgch 31:a0bed6c1e05d 127 (type == TYPE_PROMPT) ? BLU(" > ") :
mazgch 31:a0bed6c1e05d 128 "..." ;
mazgch 75:ce6e12067d0c 129 ::printf("%10.3f AT read %s", _debugTime.read_ms()*0.001, s);
mazgch 74:208e3e32d263 130 dumpAtCmd(buf, len);
mazgch 21:c4d64830bf02 131 }
mazgch 21:c4d64830bf02 132 #endif
mazgch 21:c4d64830bf02 133 if ((ret != WAIT) && (ret != NOT_FOUND))
mazgch 18:e5697801df29 134 {
mazgch 21:c4d64830bf02 135 int type = TYPE(ret);
mazgch 21:c4d64830bf02 136 // handle unsolicited commands here
mazgch 21:c4d64830bf02 137 if (type == TYPE_PLUS) {
mazgch 21:c4d64830bf02 138 const char* cmd = buf+3;
mazgch 54:7ba8e4c218e2 139 int a, b, c, d, r;
mazgch 23:05a1aeeb5fd9 140 char s[32];
mazgch 21:c4d64830bf02 141
mazgch 31:a0bed6c1e05d 142 // SMS Command ---------------------------------
mazgch 31:a0bed6c1e05d 143 // +CNMI: <mem>,<index>
mazgch 31:a0bed6c1e05d 144 if (sscanf(cmd, "CMTI: \"%*[^\"]\",%d", &a) == 1) {
mazgch 31:a0bed6c1e05d 145 TRACE("New SMS at index %d\r\n", a);
mazgch 21:c4d64830bf02 146 // Socket Specific Command ---------------------------------
mazgch 21:c4d64830bf02 147 // +UUSORD: <socket>,<length>
mazgch 21:c4d64830bf02 148 } else if ((sscanf(cmd, "UUSORD: %d,%d", &a, &b) == 2) &&
mazgch 63:42cb563a25bc 149 ISSOCKET(a) /*&& (_sockets[a].state == SOCK_CONNECTED)*/) {
mazgch 31:a0bed6c1e05d 150 TRACE("Socket %d: %d bytes pending\r\n", a, b);
mazgch 21:c4d64830bf02 151 _sockets[a].pending = b;
mazgch 69:4d6fa520dfca 152 // +UUSORF: <socket>,<length>
mazgch 69:4d6fa520dfca 153 } else if ((sscanf(cmd, "UUSORF: %d,%d", &a, &b) == 2) &&
mazgch 69:4d6fa520dfca 154 ISSOCKET(a) /*&& (_sockets[a].state == SOCK_CONNECTED)*/) {
mazgch 69:4d6fa520dfca 155 TRACE("Socket %d: %d bytes pending\r\n", a, b);
mazgch 69:4d6fa520dfca 156 _sockets[a].pending = b;
mazgch 21:c4d64830bf02 157 // +UUSOCL: <socket>
mazgch 21:c4d64830bf02 158 } else if ((sscanf(cmd, "UUSOCL: %d", &a) == 1) &&
mazgch 21:c4d64830bf02 159 ISSOCKET(a) && (_sockets[a].state == SOCK_CONNECTED)) {
mazgch 31:a0bed6c1e05d 160 TRACE("Socket %d: closed by remote host\r\n", a);
mazgch 21:c4d64830bf02 161 _sockets[a].state = SOCK_CREATED/*=CLOSED*/;
mazgch 21:c4d64830bf02 162 }
mazgch 32:8f12ac182bbb 163 if (_dev.dev == DEV_LISA_C200) {
mazgch 21:c4d64830bf02 164 // CDMA Specific -------------------------------------------
mazgch 21:c4d64830bf02 165 // +CREG: <n><SID>,<NID>,<stat>
mazgch 54:7ba8e4c218e2 166 if (sscanf(cmd, "CREG: %*d,%d,%d,%d",&a,&b,&c) == 3) {
mazgch 54:7ba8e4c218e2 167 // _net.sid = a;
mazgch 54:7ba8e4c218e2 168 // _net.nid = b;
mazgch 79:291df065e345 169 if (c == 0) _net.csd = REG_NONE; // not registered, home network
mazgch 79:291df065e345 170 else if (c == 1) _net.csd = REG_HOME; // registered, home network
mazgch 79:291df065e345 171 else if (c == 2) _net.csd = REG_NONE; // not registered, but MT is currently searching a new operator to register to
mazgch 79:291df065e345 172 else if (c == 3) _net.csd = REG_DENIED; // registration denied
mazgch 79:291df065e345 173 else if (c == 5) _net.csd = REG_ROAMING; // registered, roaming
mazgch 79:291df065e345 174 _net.psd = _net.csd; // fake PSD registration (CDMA is always registered)
mazgch 31:a0bed6c1e05d 175 _net.act = ACT_CDMA;
mazgch 21:c4d64830bf02 176 // +CSS: <mode>[,<format>,<oper>[,<AcT>]]
mazgch 21:c4d64830bf02 177 } else if (sscanf(cmd, "CSS %*c,%2s,%*d",s) == 1) {
mazgch 31:a0bed6c1e05d 178 //_net.reg = (strcmp("Z", s) == 0) ? REG_UNKNOWN : REG_HOME;
mazgch 21:c4d64830bf02 179 }
mazgch 21:c4d64830bf02 180 } else {
mazgch 21:c4d64830bf02 181 // GSM/UMTS Specific -------------------------------------------
mazgch 79:291df065e345 182 // +UUPSDD: <profile_id>
mazgch 79:291df065e345 183 if (sscanf(cmd, "UUPSDD: %d",&a) == 1) {
mazgch 79:291df065e345 184 if (*PROFILE == a) _ip = NOIP;
mazgch 79:291df065e345 185 } else {
mazgch 79:291df065e345 186 // +CREG|CGREG: <n>,<stat>[,<lac>,<ci>[,AcT[,<rac>]]] // reply to AT+CREG|AT+CGREG
mazgch 79:291df065e345 187 // +CREG|CGREG: <stat>[,<lac>,<ci>[,AcT[,<rac>]]] // URC
mazgch 79:291df065e345 188 b = 0xFFFF; c = 0xFFFFFFFF; d = -1;
mazgch 79:291df065e345 189 r = sscanf(cmd, "%s %*d,%d,\"%X\",\"%X\",%d",s,&a,&b,&c,&d);
mazgch 79:291df065e345 190 if (r <= 1)
mazgch 79:291df065e345 191 r = sscanf(cmd, "%s %d,\"%X\",\"%X\",%d",s,&a,&b,&c,&d);
mazgch 79:291df065e345 192 if (r >= 2) {
mazgch 79:291df065e345 193 Reg *reg = !strcmp(s, "CREG:") ? &_net.csd :
mazgch 79:291df065e345 194 !strcmp(s, "CGREG:") ? &_net.psd : NULL;
mazgch 79:291df065e345 195 if (reg) {
mazgch 79:291df065e345 196 // network status
mazgch 79:291df065e345 197 if (a == 0) *reg = REG_NONE; // 0: not registered, home network
mazgch 79:291df065e345 198 else if (a == 1) *reg = REG_HOME; // 1: registered, home network
mazgch 79:291df065e345 199 else if (a == 2) *reg = REG_NONE; // 2: not registered, but MT is currently searching a new operator to register to
mazgch 79:291df065e345 200 else if (a == 3) *reg = REG_DENIED; // 3: registration denied
mazgch 79:291df065e345 201 else if (a == 4) *reg = REG_UNKNOWN; // 4: unknown
mazgch 79:291df065e345 202 else if (a == 5) *reg = REG_ROAMING; // 5: registered, roaming
mazgch 79:291df065e345 203 if ((r >= 3) && (b != 0xFFFF)) _net.lac = b; // location area code
mazgch 79:291df065e345 204 if ((r >= 4) && (c != 0xFFFFFFFF)) _net.ci = c; // cell ID
mazgch 79:291df065e345 205 // access technology
mazgch 79:291df065e345 206 if (r >= 5) {
mazgch 79:291df065e345 207 if (d == 0) _net.act = ACT_GSM; // 0: GSM
mazgch 79:291df065e345 208 else if (d == 1) _net.act = ACT_GSM; // 1: GSM COMPACT
mazgch 79:291df065e345 209 else if (d == 2) _net.act = ACT_UTRAN; // 2: UTRAN
mazgch 79:291df065e345 210 else if (d == 3) _net.act = ACT_EDGE; // 3: GSM with EDGE availability
mazgch 79:291df065e345 211 else if (d == 4) _net.act = ACT_UTRAN; // 4: UTRAN with HSDPA availability
mazgch 79:291df065e345 212 else if (d == 5) _net.act = ACT_UTRAN; // 5: UTRAN with HSUPA availability
mazgch 79:291df065e345 213 else if (d == 6) _net.act = ACT_UTRAN; // 6: UTRAN with HSDPA and HSUPA availability
mazgch 79:291df065e345 214 }
mazgch 79:291df065e345 215 }
mazgch 54:7ba8e4c218e2 216 }
mazgch 21:c4d64830bf02 217 }
mazgch 21:c4d64830bf02 218 }
mazgch 21:c4d64830bf02 219 }
mazgch 21:c4d64830bf02 220 if (cb) {
mazgch 21:c4d64830bf02 221 int len = LENGTH(ret);
mazgch 21:c4d64830bf02 222 int ret = cb(type, buf, len, param);
mazgch 21:c4d64830bf02 223 if (WAIT != ret)
mazgch 21:c4d64830bf02 224 return ret;
mazgch 21:c4d64830bf02 225 }
mazgch 75:ce6e12067d0c 226 if (type == TYPE_OK) return RESP_OK;
mazgch 75:ce6e12067d0c 227 if (type == TYPE_ERROR) return RESP_ERROR;
mazgch 75:ce6e12067d0c 228 if (type == TYPE_PROMPT) return RESP_PROMPT;
mazgch 21:c4d64830bf02 229 }
mazgch 21:c4d64830bf02 230 // relax a bit
mazgch 74:208e3e32d263 231 RELAX_MS(10);
mazgch 21:c4d64830bf02 232 }
mazgch 75:ce6e12067d0c 233 while (!TIMEOUT(timer, timeout_ms));
mazgch 21:c4d64830bf02 234 return WAIT;
mazgch 21:c4d64830bf02 235 }
mazgch 21:c4d64830bf02 236
mazgch 31:a0bed6c1e05d 237 int MDMParser::_cbString(int type, const char* buf, int len, char* str)
mazgch 21:c4d64830bf02 238 {
mazgch 37:cc3433329d66 239 if (str && (type == TYPE_UNKNOWN)) {
mazgch 31:a0bed6c1e05d 240 if (sscanf(buf, "\r\n%s\r\n", str) == 1)
mazgch 31:a0bed6c1e05d 241 /*nothing*/;
mazgch 21:c4d64830bf02 242 }
mazgch 21:c4d64830bf02 243 return WAIT;
mazgch 21:c4d64830bf02 244 }
mazgch 21:c4d64830bf02 245
mazgch 31:a0bed6c1e05d 246 int MDMParser::_cbInt(int type, const char* buf, int len, int* val)
mazgch 31:a0bed6c1e05d 247 {
mazgch 37:cc3433329d66 248 if (val && (type == TYPE_UNKNOWN)) {
mazgch 31:a0bed6c1e05d 249 if (sscanf(buf, "\r\n%d\r\n", val) == 1)
mazgch 31:a0bed6c1e05d 250 /*nothing*/;
mazgch 31:a0bed6c1e05d 251 }
mazgch 31:a0bed6c1e05d 252 return WAIT;
mazgch 31:a0bed6c1e05d 253 }
mazgch 31:a0bed6c1e05d 254
mazgch 31:a0bed6c1e05d 255 // ----------------------------------------------------------------
mazgch 31:a0bed6c1e05d 256
mazgch 57:869bd35f44cc 257 bool MDMParser::connect(
mazgch 57:869bd35f44cc 258 const char* simpin,
mazgch 80:34985b4d821e 259 const char* apn, const char* username,
mazgch 80:34985b4d821e 260 const char* password, Auth auth,
mazgch 74:208e3e32d263 261 PinName pn)
mazgch 57:869bd35f44cc 262 {
mazgch 75:ce6e12067d0c 263 bool ok = init(simpin, NULL, pn);
mazgch 74:208e3e32d263 264 #ifdef MDM_DEBUG
mazgch 75:ce6e12067d0c 265 if (_debugLevel >= 1) dumpDevStatus(&_dev);
mazgch 74:208e3e32d263 266 #endif
mazgch 75:ce6e12067d0c 267 if (!ok)
mazgch 57:869bd35f44cc 268 return false;
mazgch 75:ce6e12067d0c 269 ok = registerNet();
mazgch 74:208e3e32d263 270 #ifdef MDM_DEBUG
mazgch 75:ce6e12067d0c 271 if (_debugLevel >= 1) dumpNetStatus(&_net);
mazgch 74:208e3e32d263 272 #endif
mazgch 75:ce6e12067d0c 273 if (!ok)
mazgch 57:869bd35f44cc 274 return false;
mazgch 80:34985b4d821e 275 IP ip = join(apn,username,password,auth);
mazgch 74:208e3e32d263 276 #ifdef MDM_DEBUG
mazgch 74:208e3e32d263 277 if (_debugLevel >= 1) dumpIp(ip);
mazgch 74:208e3e32d263 278 #endif
mazgch 57:869bd35f44cc 279 if (ip == NOIP)
mazgch 57:869bd35f44cc 280 return false;
mazgch 57:869bd35f44cc 281 return true;
mazgch 57:869bd35f44cc 282 }
mazgch 57:869bd35f44cc 283
mazgch 74:208e3e32d263 284 bool MDMParser::init(const char* simpin, DevStatus* status, PinName pn)
mazgch 21:c4d64830bf02 285 {
mazgch 74:208e3e32d263 286 int i = 10;
mazgch 76:f7c3dd568dae 287 memset(&_dev, 0, sizeof(_dev));
mazgch 74:208e3e32d263 288 if (pn != NC) {
mazgch 74:208e3e32d263 289 INFO("Modem::wakeup\r\n");
mazgch 74:208e3e32d263 290 DigitalOut pin(pn, 1);
mazgch 74:208e3e32d263 291 while (i--) {
mazgch 79:291df065e345 292 // SARA-U2/LISA-U2 50..80us
mazgch 79:291df065e345 293 pin = 0; wait_us(50);
mazgch 79:291df065e345 294 pin = 1; wait_ms(10);
mazgch 79:291df065e345 295
mazgch 79:291df065e345 296 // SARA-G35 >5ms, LISA-C2 > 150ms
mazgch 79:291df065e345 297 pin = 0; wait_ms(150);
mazgch 79:291df065e345 298 pin = 1; wait_ms(100);
mazgch 79:291df065e345 299
mazgch 79:291df065e345 300 // purge any messages
mazgch 79:291df065e345 301 while (WAIT != waitFinalResp(NULL,NULL,0))
mazgch 79:291df065e345 302 /* nothing */;
mazgch 74:208e3e32d263 303 // check interface and disable local echo
mazgch 74:208e3e32d263 304 sendFormated("AT\r\n");
mazgch 74:208e3e32d263 305 if(RESP_OK == waitFinalResp(NULL,NULL,500))
mazgch 74:208e3e32d263 306 break;
mazgch 74:208e3e32d263 307 }
mazgch 75:ce6e12067d0c 308 if (i < 0) {
mazgch 75:ce6e12067d0c 309 ERROR("No Reply from Modem");
mazgch 74:208e3e32d263 310 return false;
mazgch 75:ce6e12067d0c 311 }
mazgch 21:c4d64830bf02 312 }
mazgch 76:f7c3dd568dae 313 _init = true;
mazgch 75:ce6e12067d0c 314
mazgch 74:208e3e32d263 315 INFO("Modem::init\r\n");
mazgch 21:c4d64830bf02 316 // echo off
mazgch 21:c4d64830bf02 317 sendFormated("AT E0\r\n");
mazgch 52:8071747a7cb3 318 if(RESP_OK != waitFinalResp())
mazgch 21:c4d64830bf02 319 return false;
mazgch 21:c4d64830bf02 320 // enable verbose error messages
mazgch 21:c4d64830bf02 321 sendFormated("AT+CMEE=2\r\n");
mazgch 52:8071747a7cb3 322 if(RESP_OK != waitFinalResp())
mazgch 21:c4d64830bf02 323 return false;
mazgch 21:c4d64830bf02 324 // set baud rate
mazgch 21:c4d64830bf02 325 sendFormated("AT+IPR=115200\r\n");
mazgch 52:8071747a7cb3 326 if (RESP_OK != waitFinalResp())
mazgch 21:c4d64830bf02 327 return false;
mazgch 74:208e3e32d263 328 RELAX_MS(40);
mazgch 21:c4d64830bf02 329 // identify the module
mazgch 21:c4d64830bf02 330 sendFormated("ATI\r\n");
mazgch 52:8071747a7cb3 331 if (RESP_OK != waitFinalResp(_cbATI, &_dev.dev))
mazgch 21:c4d64830bf02 332 return false;
mazgch 32:8f12ac182bbb 333 if (_dev.dev == DEV_UNKNOWN)
mazgch 21:c4d64830bf02 334 return false;
mazgch 32:8f12ac182bbb 335 // device specific init
mazgch 32:8f12ac182bbb 336 if (_dev.dev == DEV_LISA_C200) {
mazgch 32:8f12ac182bbb 337 // get the manufacturer
mazgch 32:8f12ac182bbb 338 sendFormated("AT+GMI\r\n");
mazgch 52:8071747a7cb3 339 if (RESP_OK != waitFinalResp(_cbString, _dev.manu))
mazgch 32:8f12ac182bbb 340 return false;
mazgch 32:8f12ac182bbb 341 // get the model identification
mazgch 32:8f12ac182bbb 342 sendFormated("AT+GMM\r\n");
mazgch 52:8071747a7cb3 343 if (RESP_OK != waitFinalResp(_cbString, _dev.model))
mazgch 32:8f12ac182bbb 344 return false;
mazgch 32:8f12ac182bbb 345 // get the sw version
mazgch 32:8f12ac182bbb 346 sendFormated("AT+GMR\r\n");
mazgch 52:8071747a7cb3 347 if (RESP_OK != waitFinalResp(_cbString, _dev.ver))
mazgch 32:8f12ac182bbb 348 return false;
mazgch 21:c4d64830bf02 349 // Return the pseudo ESN or MEID
mazgch 21:c4d64830bf02 350 sendFormated("AT+GSN\r\n");
mazgch 52:8071747a7cb3 351 if (RESP_OK != waitFinalResp(_cbString, _dev.meid))
mazgch 26:07be5faf8925 352 return false;
mazgch 50:d76aece8038f 353 #if 0
mazgch 50:d76aece8038f 354 // enable power saving
mazgch 50:d76aece8038f 355 if (_dev.lpm != LPM_DISABLED) {
mazgch 50:d76aece8038f 356 // enable power saving (requires flow control, cts at least)
mazgch 50:d76aece8038f 357 sendFormated("AT+UPSV=1,1280\r\n");
mazgch 52:8071747a7cb3 358 if (RESP_OK != waitFinalResp())
mazgch 50:d76aece8038f 359 return false;
mazgch 50:d76aece8038f 360 _dev.lpm = LPM_ACTIVE;
mazgch 50:d76aece8038f 361 }
mazgch 50:d76aece8038f 362 #endif
mazgch 26:07be5faf8925 363 } else {
mazgch 32:8f12ac182bbb 364 if (_dev.dev == DEV_LISA_U200) {
mazgch 35:9275215a3a5b 365 // enable the network identification feature
mazgch 21:c4d64830bf02 366 sendFormated("AT+UGPIOC=20,2\r\n");
mazgch 52:8071747a7cb3 367 if (RESP_OK != waitFinalResp())
mazgch 21:c4d64830bf02 368 return false;
mazgch 21:c4d64830bf02 369 } else {
mazgch 35:9275215a3a5b 370 // enable the network identification feature
mazgch 21:c4d64830bf02 371 sendFormated("AT+UGPIOC=16,2\r\n");
mazgch 52:8071747a7cb3 372 if (RESP_OK != waitFinalResp())
mazgch 21:c4d64830bf02 373 return false;
mazgch 21:c4d64830bf02 374 }
mazgch 21:c4d64830bf02 375 // check the sim card
mazgch 31:a0bed6c1e05d 376 for (int i = 0; (i < 5) && (_dev.sim != SIM_READY); i++) {
mazgch 21:c4d64830bf02 377 sendFormated("AT+CPIN?\r\n");
mazgch 31:a0bed6c1e05d 378 int ret = waitFinalResp(_cbCPIN, &_dev.sim);
mazgch 62:a02f026bdd7c 379 // having an error here is ok (sim may still be initializing)
mazgch 52:8071747a7cb3 380 if ((RESP_OK != ret) && (RESP_ERROR != ret))
mazgch 21:c4d64830bf02 381 return false;
mazgch 31:a0bed6c1e05d 382 // Enter PIN if needed
mazgch 77:55788e619858 383 if (_dev.sim == SIM_PIN) {
mazgch 57:869bd35f44cc 384 if (!simpin) {
mazgch 75:ce6e12067d0c 385 ERROR("SIM PIN not available\r\n");
mazgch 31:a0bed6c1e05d 386 return false;
mazgch 31:a0bed6c1e05d 387 }
mazgch 57:869bd35f44cc 388 sendFormated("AT+CPIN=%s\r\n", simpin);
mazgch 52:8071747a7cb3 389 if (RESP_OK != waitFinalResp(_cbCPIN, &_dev.sim))
mazgch 31:a0bed6c1e05d 390 return false;
mazgch 62:a02f026bdd7c 391 } else if (_dev.sim != SIM_READY) {
mazgch 74:208e3e32d263 392 RELAX_MS(1000);
mazgch 62:a02f026bdd7c 393 }
mazgch 21:c4d64830bf02 394 }
mazgch 77:55788e619858 395 if (_dev.sim != SIM_READY) {
mazgch 77:55788e619858 396 if (_dev.sim == SIM_MISSING)
mazgch 77:55788e619858 397 ERROR("SIM not inserted\r\n");
mazgch 21:c4d64830bf02 398 return false;
mazgch 77:55788e619858 399 }
mazgch 32:8f12ac182bbb 400 // get the manufacturer
mazgch 32:8f12ac182bbb 401 sendFormated("AT+CGMI\r\n");
mazgch 52:8071747a7cb3 402 if (RESP_OK != waitFinalResp(_cbString, _dev.manu))
mazgch 32:8f12ac182bbb 403 return false;
mazgch 32:8f12ac182bbb 404 // get the model identification
mazgch 32:8f12ac182bbb 405 sendFormated("AT+CGMM\r\n");
mazgch 52:8071747a7cb3 406 if (RESP_OK != waitFinalResp(_cbString, _dev.model))
mazgch 32:8f12ac182bbb 407 return false;
mazgch 32:8f12ac182bbb 408 // get the
mazgch 32:8f12ac182bbb 409 sendFormated("AT+CGMR\r\n");
mazgch 52:8071747a7cb3 410 if (RESP_OK != waitFinalResp(_cbString, _dev.ver))
mazgch 32:8f12ac182bbb 411 return false;
mazgch 21:c4d64830bf02 412 // Returns the ICCID (Integrated Circuit Card ID) of the SIM-card.
mazgch 21:c4d64830bf02 413 // ICCID is a serial number identifying the SIM.
mazgch 21:c4d64830bf02 414 sendFormated("AT+CCID\r\n");
mazgch 52:8071747a7cb3 415 if (RESP_OK != waitFinalResp(_cbCCID, _dev.ccid))
mazgch 21:c4d64830bf02 416 return false;
mazgch 21:c4d64830bf02 417 // Returns the product serial number, IMEI (International Mobile Equipment Identity)
mazgch 21:c4d64830bf02 418 sendFormated("AT+CGSN\r\n");
mazgch 52:8071747a7cb3 419 if (RESP_OK != waitFinalResp(_cbString, _dev.imei))
mazgch 21:c4d64830bf02 420 return false;
mazgch 50:d76aece8038f 421 // enable power saving
mazgch 50:d76aece8038f 422 if (_dev.lpm != LPM_DISABLED) {
mazgch 50:d76aece8038f 423 // enable power saving (requires flow control, cts at least)
mazgch 50:d76aece8038f 424 sendFormated("AT+UPSV=1\r\n");
mazgch 52:8071747a7cb3 425 if (RESP_OK != waitFinalResp())
mazgch 50:d76aece8038f 426 return false;
mazgch 50:d76aece8038f 427 _dev.lpm = LPM_ACTIVE;
mazgch 50:d76aece8038f 428 }
mazgch 79:291df065e345 429 // enable the psd registration unsolicited result code
mazgch 79:291df065e345 430 sendFormated("AT+CGREG=2\r\n");
mazgch 79:291df065e345 431 if (RESP_OK != waitFinalResp())
mazgch 79:291df065e345 432 return false;
mazgch 21:c4d64830bf02 433 }
mazgch 79:291df065e345 434 // enable the network registration unsolicited result code
mazgch 79:291df065e345 435 sendFormated("AT+CREG=%d\r\n", (_dev.dev == DEV_LISA_C200) ? 1 : 2);
mazgch 79:291df065e345 436 if (RESP_OK != waitFinalResp())
mazgch 79:291df065e345 437 return false;
mazgch 31:a0bed6c1e05d 438 // Setup SMS in text mode
mazgch 31:a0bed6c1e05d 439 sendFormated("AT+CMGF=1\r\n");
mazgch 52:8071747a7cb3 440 if (RESP_OK != waitFinalResp())
mazgch 31:a0bed6c1e05d 441 return false;
mazgch 31:a0bed6c1e05d 442 // setup new message indication
mazgch 75:ce6e12067d0c 443 sendFormated("AT+CNMI=2,1\r\n");
mazgch 52:8071747a7cb3 444 if (RESP_OK != waitFinalResp())
mazgch 31:a0bed6c1e05d 445 return false;
mazgch 21:c4d64830bf02 446 // Request IMSI (International Mobile Subscriber Identification)
mazgch 21:c4d64830bf02 447 sendFormated("AT+CIMI\r\n");
mazgch 52:8071747a7cb3 448 if (RESP_OK != waitFinalResp(_cbString, _dev.imsi))
mazgch 21:c4d64830bf02 449 return false;
mazgch 28:4d9509e3b1cf 450 if (status)
mazgch 31:a0bed6c1e05d 451 memcpy(status, &_dev, sizeof(DevStatus));
mazgch 31:a0bed6c1e05d 452 return true;
mazgch 31:a0bed6c1e05d 453 }
mazgch 31:a0bed6c1e05d 454
mazgch 74:208e3e32d263 455 bool MDMParser::powerOff(void)
mazgch 74:208e3e32d263 456 {
mazgch 76:f7c3dd568dae 457 if (_init) {
mazgch 76:f7c3dd568dae 458 INFO("Modem::powerOff\r\n");
mazgch 76:f7c3dd568dae 459 sendFormated("AT+CPWROFF\r\n");
mazgch 76:f7c3dd568dae 460 if (RESP_OK != waitFinalResp(NULL,NULL,120*1000))
mazgch 76:f7c3dd568dae 461 return false;
mazgch 76:f7c3dd568dae 462 _init = false;
mazgch 76:f7c3dd568dae 463 }
mazgch 74:208e3e32d263 464 return true;
mazgch 74:208e3e32d263 465 }
mazgch 74:208e3e32d263 466
mazgch 32:8f12ac182bbb 467 int MDMParser::_cbATI(int type, const char* buf, int len, Dev* dev)
mazgch 31:a0bed6c1e05d 468 {
mazgch 37:cc3433329d66 469 if ((type == TYPE_UNKNOWN) && dev) {
mazgch 31:a0bed6c1e05d 470 if (strstr(buf, "SARA-G350")) {
mazgch 32:8f12ac182bbb 471 *dev = DEV_SARA_G350;
mazgch 32:8f12ac182bbb 472 /*TRACE("Identified Device: SARA-G350 2G\\n")*/;
mazgch 31:a0bed6c1e05d 473 } else if (strstr(buf, "LISA-U200")) {
mazgch 32:8f12ac182bbb 474 *dev = DEV_LISA_U200;
mazgch 32:8f12ac182bbb 475 /*TRACE("Identified Device: LISA-U200 2G/3G\r\n")*/;
mazgch 31:a0bed6c1e05d 476 } else if (strstr(buf, "LISA-C200")) {
mazgch 32:8f12ac182bbb 477 *dev= DEV_LISA_C200;
mazgch 32:8f12ac182bbb 478 /*TRACE("Identified Device: LISA-C200 CDMA\r\n")*/;
mazgch 31:a0bed6c1e05d 479 }
mazgch 28:4d9509e3b1cf 480 }
mazgch 31:a0bed6c1e05d 481 return WAIT;
mazgch 31:a0bed6c1e05d 482 }
mazgch 31:a0bed6c1e05d 483
mazgch 31:a0bed6c1e05d 484 int MDMParser::_cbCPIN(int type, const char* buf, int len, Sim* sim)
mazgch 31:a0bed6c1e05d 485 {
mazgch 75:ce6e12067d0c 486 if (sim) {
mazgch 75:ce6e12067d0c 487 if (type == TYPE_PLUS){
mazgch 75:ce6e12067d0c 488 char s[16];
mazgch 75:ce6e12067d0c 489 if (sscanf(buf, "\r\n+CPIN: %[^\r]\r\n", s) >= 1)
mazgch 75:ce6e12067d0c 490 *sim = (0 == strcmp("READY", s)) ? SIM_READY : SIM_PIN;
mazgch 75:ce6e12067d0c 491 } else if (type == TYPE_ERROR) {
mazgch 75:ce6e12067d0c 492 if (strstr(buf, "+CME ERROR: SIM not inserted"))
mazgch 75:ce6e12067d0c 493 *sim = SIM_MISSING;
mazgch 31:a0bed6c1e05d 494 }
mazgch 31:a0bed6c1e05d 495 }
mazgch 31:a0bed6c1e05d 496 return WAIT;
mazgch 21:c4d64830bf02 497 }
mazgch 21:c4d64830bf02 498
mazgch 26:07be5faf8925 499 int MDMParser::_cbCCID(int type, const char* buf, int len, char* ccid)
mazgch 26:07be5faf8925 500 {
mazgch 26:07be5faf8925 501 if ((type == TYPE_PLUS) && ccid){
mazgch 26:07be5faf8925 502 if (sscanf(buf, "\r\n+CCID: %[^\r]\r\n", ccid) == 1)
mazgch 31:a0bed6c1e05d 503 /*TRACE("Got CCID: %s\r\n", ccid)*/;
mazgch 26:07be5faf8925 504 }
mazgch 26:07be5faf8925 505 return WAIT;
mazgch 26:07be5faf8925 506 }
mazgch 26:07be5faf8925 507
mazgch 75:ce6e12067d0c 508 bool MDMParser::registerNet(NetStatus* status /*= NULL*/, int timeout_ms /*= 180000*/)
mazgch 75:ce6e12067d0c 509 {
mazgch 75:ce6e12067d0c 510 Timer timer;
mazgch 75:ce6e12067d0c 511 timer.start();
mazgch 75:ce6e12067d0c 512 INFO("Modem::register\r\n");
mazgch 75:ce6e12067d0c 513 while (!checkNetStatus(status) && !TIMEOUT(timer, timeout_ms))
mazgch 75:ce6e12067d0c 514 RELAX_MS(1000);
mazgch 79:291df065e345 515 if (_net.csd == REG_DENIED) ERROR("CSD Registration Denied\r\n");
mazgch 79:291df065e345 516 if (_net.psd == REG_DENIED) ERROR("PSD Registration Denied\r\n");
mazgch 79:291df065e345 517 return REG_OK(_net.csd) || REG_OK(_net.psd);
mazgch 75:ce6e12067d0c 518 }
mazgch 75:ce6e12067d0c 519
mazgch 28:4d9509e3b1cf 520 bool MDMParser::checkNetStatus(NetStatus* status /*= NULL*/)
mazgch 21:c4d64830bf02 521 {
mazgch 75:ce6e12067d0c 522 memset(&_net, 0, sizeof(_net));
mazgch 75:ce6e12067d0c 523 _net.lac = 0xFFFF;
mazgch 75:ce6e12067d0c 524 _net.ci = 0xFFFFFFFF;
mazgch 21:c4d64830bf02 525 // check registration
mazgch 21:c4d64830bf02 526 sendFormated("AT+CREG?\r\n");
mazgch 52:8071747a7cb3 527 if (RESP_OK != waitFinalResp())
mazgch 21:c4d64830bf02 528 return false;
mazgch 79:291df065e345 529 if (_dev.dev != DEV_LISA_C200) {
mazgch 79:291df065e345 530 // check PSD registration
mazgch 79:291df065e345 531 sendFormated("AT+CGREG?\r\n");
mazgch 79:291df065e345 532 if (RESP_OK != waitFinalResp())
mazgch 79:291df065e345 533 return false;
mazgch 79:291df065e345 534 }
mazgch 79:291df065e345 535 if (REG_OK(_net.csd) || REG_OK(_net.psd))
mazgch 75:ce6e12067d0c 536 {
mazgch 75:ce6e12067d0c 537 // check modem specific status messages
mazgch 75:ce6e12067d0c 538 if (_dev.dev == DEV_LISA_C200) {
mazgch 75:ce6e12067d0c 539 sendFormated("AT+CSS?\r\n");
mazgch 75:ce6e12067d0c 540 if (RESP_OK != waitFinalResp())
mazgch 75:ce6e12067d0c 541 return false;
mazgch 81:3966a5c17037 542 while (1) {
mazgch 81:3966a5c17037 543 // get the Telephone number
mazgch 81:3966a5c17037 544 sendFormated("AT$MDN?\r\n");
mazgch 81:3966a5c17037 545 if (RESP_OK != waitFinalResp(_cbString, _net.num))
mazgch 81:3966a5c17037 546 return false;
mazgch 81:3966a5c17037 547 // check if we have a Mobile Directory Number
mazgch 81:3966a5c17037 548 if (*_net.num && (memcmp(_net.num, "000000", 6) != 0))
mazgch 81:3966a5c17037 549 break;
mazgch 81:3966a5c17037 550
mazgch 81:3966a5c17037 551 INFO("Device not yet activated\r\n");
mazgch 81:3966a5c17037 552 INFO("Make sure you have a valid contract with the network operator for this device.\r\n");
mazgch 81:3966a5c17037 553 // Check if the the version contains a V for Verizon
mazgch 81:3966a5c17037 554 // Verizon: E0.V.xx.00.xxR,
mazgch 81:3966a5c17037 555 // Sprint E0.S.xx.00.xxR
mazgch 81:3966a5c17037 556 if (_dev.ver[3] == 'V') {
mazgch 81:3966a5c17037 557 int i;
mazgch 81:3966a5c17037 558 INFO("Start device over-the-air activation (this can take a few minutes)\r\n");
mazgch 81:3966a5c17037 559 sendFormated("AT+CDV=*22899\r\n");
mazgch 81:3966a5c17037 560 i = 1;
mazgch 81:3966a5c17037 561 if (RESP_OK != waitFinalResp(_cbUACTIND, &i, 120*1000) || (i == 1)) {
mazgch 81:3966a5c17037 562 ERROR("Device over-the-air activation failed\r\n");
mazgch 81:3966a5c17037 563 return false;
mazgch 81:3966a5c17037 564 }
mazgch 81:3966a5c17037 565 INFO("Device over-the-air activation successful\r\n");
mazgch 81:3966a5c17037 566
mazgch 81:3966a5c17037 567 INFO("Start PRL over-the-air update (this can take a few minutes)\r\n");
mazgch 81:3966a5c17037 568 sendFormated("AT+CDV=*22891\r\n");
mazgch 81:3966a5c17037 569 i = 1;
mazgch 81:3966a5c17037 570 if (RESP_OK != waitFinalResp(_cbUACTIND, &i, 120*1000) || (i == 1)) {
mazgch 81:3966a5c17037 571 ERROR("PRL over-the-air update failed\r\n");
mazgch 81:3966a5c17037 572 return false;
mazgch 81:3966a5c17037 573 }
mazgch 81:3966a5c17037 574 INFO("PRL over-the-air update successful\r\n");
mazgch 81:3966a5c17037 575
mazgch 81:3966a5c17037 576 } else {
mazgch 81:3966a5c17037 577 // Sprint or Aeris
mazgch 81:3966a5c17037 578 INFO("Wait for OMA-DM over-the-air activation (this can take a few minutes)\r\n");
mazgch 81:3966a5c17037 579 RELAX_MS(120*1000);
mazgch 81:3966a5c17037 580 }
mazgch 81:3966a5c17037 581 }
mazgch 75:ce6e12067d0c 582 // get the the Network access identifier string
mazgch 75:ce6e12067d0c 583 char nai[64];
mazgch 75:ce6e12067d0c 584 sendFormated("AT$QCMIPNAI?\r\n");
mazgch 75:ce6e12067d0c 585 if (RESP_OK != waitFinalResp(_cbString, nai))
mazgch 75:ce6e12067d0c 586 return false;
mazgch 75:ce6e12067d0c 587 } else {
mazgch 75:ce6e12067d0c 588 // check operator selection
mazgch 75:ce6e12067d0c 589 sendFormated("AT+COPS?\r\n");
mazgch 75:ce6e12067d0c 590 if (RESP_OK != waitFinalResp(_cbCOPS, &_net))
mazgch 75:ce6e12067d0c 591 return false;
mazgch 75:ce6e12067d0c 592 // Returns the MSISDNs related to this subscriber
mazgch 75:ce6e12067d0c 593 sendFormated("AT+CNUM\r\n");
mazgch 75:ce6e12067d0c 594 if (RESP_OK != waitFinalResp(_cbCNUM, _net.num))
mazgch 75:ce6e12067d0c 595 return false;
mazgch 75:ce6e12067d0c 596 }
mazgch 75:ce6e12067d0c 597 // Returns the signal strength indication
mazgch 75:ce6e12067d0c 598 sendFormated("AT+CSQ\r\n");
mazgch 75:ce6e12067d0c 599 if (RESP_OK != waitFinalResp(_cbCSQ, &_net))
mazgch 32:8f12ac182bbb 600 return false;
mazgch 75:ce6e12067d0c 601 }
mazgch 28:4d9509e3b1cf 602 if (status) {
mazgch 31:a0bed6c1e05d 603 memcpy(status, &_net, sizeof(NetStatus));
mazgch 25:4045d02e44f1 604 }
mazgch 79:291df065e345 605 return REG_DONE(_net.csd) && REG_DONE(_net.psd);
mazgch 31:a0bed6c1e05d 606 }
mazgch 31:a0bed6c1e05d 607
mazgch 31:a0bed6c1e05d 608 int MDMParser::_cbCOPS(int type, const char* buf, int len, NetStatus* status)
mazgch 31:a0bed6c1e05d 609 {
mazgch 31:a0bed6c1e05d 610 if ((type == TYPE_PLUS) && status){
mazgch 31:a0bed6c1e05d 611 int act = 99;
mazgch 31:a0bed6c1e05d 612 // +COPS: <mode>[,<format>,<oper>[,<AcT>]]
mazgch 31:a0bed6c1e05d 613 if (sscanf(buf, "\r\n+COPS: %*d,%*d,\"%[^\"]\",%d",status->opr,&act) >= 1) {
mazgch 31:a0bed6c1e05d 614 if (act == 0) status->act = ACT_GSM; // 0: GSM,
mazgch 31:a0bed6c1e05d 615 else if (act == 2) status->act = ACT_UTRAN; // 2: UTRAN
mazgch 31:a0bed6c1e05d 616 }
mazgch 31:a0bed6c1e05d 617 }
mazgch 31:a0bed6c1e05d 618 return WAIT;
mazgch 31:a0bed6c1e05d 619 }
mazgch 31:a0bed6c1e05d 620
mazgch 31:a0bed6c1e05d 621 int MDMParser::_cbCNUM(int type, const char* buf, int len, char* num)
mazgch 31:a0bed6c1e05d 622 {
mazgch 31:a0bed6c1e05d 623 if ((type == TYPE_PLUS) && num){
mazgch 31:a0bed6c1e05d 624 int a;
mazgch 31:a0bed6c1e05d 625 if ((sscanf(buf, "\r\n+CNUM: \"My Number\",\"%31[^\"]\",%d", num, &a) == 2) &&
mazgch 31:a0bed6c1e05d 626 ((a == 129) || (a == 145))) {
mazgch 31:a0bed6c1e05d 627 }
mazgch 31:a0bed6c1e05d 628 }
mazgch 31:a0bed6c1e05d 629 return WAIT;
mazgch 31:a0bed6c1e05d 630 }
mazgch 31:a0bed6c1e05d 631
mazgch 54:7ba8e4c218e2 632 int MDMParser::_cbCSQ(int type, const char* buf, int len, NetStatus* status)
mazgch 31:a0bed6c1e05d 633 {
mazgch 54:7ba8e4c218e2 634 if ((type == TYPE_PLUS) && status){
mazgch 54:7ba8e4c218e2 635 int a,b;
mazgch 54:7ba8e4c218e2 636 char _ber[] = { 49, 43, 37, 25, 19, 13, 7, 0 }; // see 3GPP TS 45.008 [20] subclause 8.2.4
mazgch 31:a0bed6c1e05d 637 // +CSQ: <rssi>,<qual>
mazgch 54:7ba8e4c218e2 638 if (sscanf(buf, "\r\n+CSQ: %d,%d",&a,&b) == 2) {
mazgch 54:7ba8e4c218e2 639 if (a != 99) status->rssi = -113 + 2*a; // 0: -113 1: -111 ... 30: -53 dBm with 2 dBm steps
mazgch 54:7ba8e4c218e2 640 if ((b != 99) && (b < sizeof(_ber))) status->ber = _ber[b]; //
mazgch 31:a0bed6c1e05d 641 }
mazgch 31:a0bed6c1e05d 642 }
mazgch 31:a0bed6c1e05d 643 return WAIT;
mazgch 31:a0bed6c1e05d 644 }
mazgch 21:c4d64830bf02 645
mazgch 81:3966a5c17037 646 int MDMParser::_cbUACTIND(int type, const char* buf, int len, int* i)
mazgch 81:3966a5c17037 647 {
mazgch 81:3966a5c17037 648 if ((type == TYPE_PLUS) && i){
mazgch 81:3966a5c17037 649 if (sscanf(buf, "\r\n+UACTIND: %d", i) == 1) {
mazgch 81:3966a5c17037 650 }
mazgch 81:3966a5c17037 651 }
mazgch 81:3966a5c17037 652 return WAIT;
mazgch 81:3966a5c17037 653 }
mazgch 81:3966a5c17037 654
mazgch 21:c4d64830bf02 655 // ----------------------------------------------------------------
mazgch 21:c4d64830bf02 656 // internet connection
mazgch 21:c4d64830bf02 657
mazgch 79:291df065e345 658 MDMParser::IP MDMParser::join(const char* apn /*= NULL*/, const char* username /*= NULL*/,
mazgch 79:291df065e345 659 const char* password /*= NULL*/, Auth auth /*= AUTH_DETECT*/)
mazgch 21:c4d64830bf02 660 {
mazgch 78:caf0014375cb 661 INFO("Modem::join\r\n");
mazgch 32:8f12ac182bbb 662 _ip = NOIP;
mazgch 32:8f12ac182bbb 663 if (_dev.dev == DEV_LISA_C200) {
mazgch 76:f7c3dd568dae 664 // make a dumy dns lookup (which will fail, so ignore the result)
mazgch 76:f7c3dd568dae 665 sendFormated("AT+UDNSRN=0,\"u-blox.com\"\r\n");
mazgch 76:f7c3dd568dae 666 waitFinalResp();
mazgch 76:f7c3dd568dae 667 // This fake lookup will enable the IP connection and we
mazgch 76:f7c3dd568dae 668 // should have an IP after this, so we check it
mazgch 76:f7c3dd568dae 669
mazgch 21:c4d64830bf02 670 //Get local IP address
mazgch 21:c4d64830bf02 671 sendFormated("AT+CMIP?\r\n");
mazgch 52:8071747a7cb3 672 if (RESP_OK != waitFinalResp(_cbCMIP, &_ip))
mazgch 31:a0bed6c1e05d 673 return NOIP;
mazgch 21:c4d64830bf02 674 } else {
mazgch 21:c4d64830bf02 675 // check gprs attach status
mazgch 72:d1e943ad6558 676 sendFormated("AT+CGATT=1\r\n");
mazgch 74:208e3e32d263 677 if (RESP_OK != waitFinalResp(NULL,NULL,3*60*1000))
mazgch 31:a0bed6c1e05d 678 return NOIP;
mazgch 31:a0bed6c1e05d 679
mazgch 31:a0bed6c1e05d 680 // Check the profile
mazgch 31:a0bed6c1e05d 681 int a = 0;
mazgch 79:291df065e345 682 bool force = true;
mazgch 31:a0bed6c1e05d 683 sendFormated("AT+UPSND=" PROFILE ",8\r\n");
mazgch 52:8071747a7cb3 684 if (RESP_OK != waitFinalResp(_cbUPSND, &a))
mazgch 31:a0bed6c1e05d 685 return NOIP;
mazgch 79:291df065e345 686 if (a == 1 && force) {
mazgch 31:a0bed6c1e05d 687 // disconnect the profile already if it is connected
mazgch 31:a0bed6c1e05d 688 sendFormated("AT+UPSDA=" PROFILE ",4\r\n");
mazgch 58:e38a2e942fbb 689 if (RESP_OK != waitFinalResp(NULL,NULL,40*1000))
mazgch 31:a0bed6c1e05d 690 return NOIP;;
mazgch 79:291df065e345 691 a = 0;
mazgch 31:a0bed6c1e05d 692 }
mazgch 79:291df065e345 693 if (a == 0) {
mazgch 79:291df065e345 694 // Set up the APN
mazgch 79:291df065e345 695 if (apn) {
mazgch 79:291df065e345 696 sendFormated("AT+UPSD=" PROFILE ",1,\"%s\"\r\n", apn);
mazgch 79:291df065e345 697 if (RESP_OK != waitFinalResp())
mazgch 79:291df065e345 698 return NOIP;
mazgch 79:291df065e345 699 }
mazgch 79:291df065e345 700 if (username) {
mazgch 79:291df065e345 701 sendFormated("AT+UPSD=" PROFILE ",2,\"%s\"\r\n", username);
mazgch 79:291df065e345 702 if (RESP_OK != waitFinalResp())
mazgch 79:291df065e345 703 return NOIP;
mazgch 79:291df065e345 704 }
mazgch 79:291df065e345 705 if (password) {
mazgch 79:291df065e345 706 sendFormated("AT+UPSD=" PROFILE ",3,\"%s\"\r\n", password);
mazgch 79:291df065e345 707 if (RESP_OK != waitFinalResp())
mazgch 79:291df065e345 708 return NOIP;
mazgch 79:291df065e345 709 }
mazgch 79:291df065e345 710 // Set up the dynamic IP address assignment.
mazgch 79:291df065e345 711 sendFormated("AT+UPSD=" PROFILE ",7,\"0.0.0.0\"\r\n");
mazgch 52:8071747a7cb3 712 if (RESP_OK != waitFinalResp())
mazgch 31:a0bed6c1e05d 713 return NOIP;
mazgch 79:291df065e345 714 // try different Authentication Protocols
mazgch 79:291df065e345 715 // 0 = none
mazgch 79:291df065e345 716 // 1 = PAP (Password Authentication Protocol)
mazgch 79:291df065e345 717 // 2 = CHAP (Challenge Handshake Authentication Protocol)
mazgch 79:291df065e345 718 int i = AUTH_NONE;
mazgch 79:291df065e345 719 while (i <= AUTH_CHAP)
mazgch 79:291df065e345 720 {
mazgch 79:291df065e345 721 if ((auth == AUTH_DETECT) || (auth == i)) {
mazgch 79:291df065e345 722 // Set up the dynamic IP address assignment.
mazgch 79:291df065e345 723 sendFormated("AT+UPSD=" PROFILE ",6,%d\r\n", i);
mazgch 79:291df065e345 724 if (RESP_OK != waitFinalResp())
mazgch 79:291df065e345 725 return NOIP;
mazgch 79:291df065e345 726 // Activate the profile and make connection
mazgch 79:291df065e345 727 sendFormated("AT+UPSDA=" PROFILE ",3\r\n");
mazgch 79:291df065e345 728 if (RESP_OK == waitFinalResp(NULL,NULL,150*1000))
mazgch 79:291df065e345 729 break;
mazgch 79:291df065e345 730 }
mazgch 79:291df065e345 731 i ++;
mazgch 79:291df065e345 732 }
mazgch 79:291df065e345 733 if (i > AUTH_CHAP) {
mazgch 79:291df065e345 734 ERROR("Your modem APN/password/username may be wrong\r\n");
mazgch 31:a0bed6c1e05d 735 return NOIP;
mazgch 79:291df065e345 736 }
mazgch 74:208e3e32d263 737 }
mazgch 21:c4d64830bf02 738 //Get local IP address
mazgch 21:c4d64830bf02 739 sendFormated("AT+UPSND=" PROFILE ",0\r\n");
mazgch 52:8071747a7cb3 740 if (RESP_OK != waitFinalResp(_cbUPSND, &_ip))
mazgch 31:a0bed6c1e05d 741 return NOIP;
mazgch 31:a0bed6c1e05d 742 }
mazgch 32:8f12ac182bbb 743 return _ip;
mazgch 31:a0bed6c1e05d 744 }
mazgch 31:a0bed6c1e05d 745
mazgch 32:8f12ac182bbb 746 int MDMParser::_cbCMIP(int type, const char* buf, int len, IP* ip)
mazgch 32:8f12ac182bbb 747 {
mazgch 32:8f12ac182bbb 748 if ((type == TYPE_PLUS) && ip) {
mazgch 32:8f12ac182bbb 749 int a,b,c,d;
mazgch 32:8f12ac182bbb 750 if (sscanf(buf, "\r\n+CMIP: " IPSTR, &a,&b,&c,&d) == 4)
mazgch 32:8f12ac182bbb 751 *ip = IPADR(a,b,c,d);
mazgch 32:8f12ac182bbb 752 }
mazgch 32:8f12ac182bbb 753 return WAIT;
mazgch 32:8f12ac182bbb 754 }
mazgch 32:8f12ac182bbb 755
mazgch 31:a0bed6c1e05d 756 int MDMParser::_cbUPSND(int type, const char* buf, int len, int* act)
mazgch 31:a0bed6c1e05d 757 {
mazgch 31:a0bed6c1e05d 758 if ((type == TYPE_PLUS) && act) {
mazgch 31:a0bed6c1e05d 759 if (sscanf(buf, "\r\n+UPSND: %*d,%*d,%d", act) == 1)
mazgch 31:a0bed6c1e05d 760 /*nothing*/;
mazgch 21:c4d64830bf02 761 }
mazgch 31:a0bed6c1e05d 762 return WAIT;
mazgch 31:a0bed6c1e05d 763 }
mazgch 31:a0bed6c1e05d 764
mazgch 31:a0bed6c1e05d 765 int MDMParser::_cbUPSND(int type, const char* buf, int len, IP* ip)
mazgch 31:a0bed6c1e05d 766 {
mazgch 31:a0bed6c1e05d 767 if ((type == TYPE_PLUS) && ip) {
mazgch 31:a0bed6c1e05d 768 int a,b,c,d;
mazgch 31:a0bed6c1e05d 769 // +UPSND=<profile_id>,<param_tag>[,<dynamic_param_val>]
mazgch 31:a0bed6c1e05d 770 if (sscanf(buf, "\r\n+UPSND: " PROFILE ",0,\"" IPSTR "\"", &a,&b,&c,&d) == 4)
mazgch 31:a0bed6c1e05d 771 *ip = IPADR(a,b,c,d);
mazgch 31:a0bed6c1e05d 772 }
mazgch 31:a0bed6c1e05d 773 return WAIT;
mazgch 31:a0bed6c1e05d 774 }
mazgch 31:a0bed6c1e05d 775
mazgch 31:a0bed6c1e05d 776 int MDMParser::_cbUDNSRN(int type, const char* buf, int len, IP* ip)
mazgch 31:a0bed6c1e05d 777 {
mazgch 31:a0bed6c1e05d 778 if ((type == TYPE_PLUS) && ip) {
mazgch 31:a0bed6c1e05d 779 int a,b,c,d;
mazgch 31:a0bed6c1e05d 780 if (sscanf(buf, "\r\n+UDNSRN: \""IPSTR"\"", &a,&b,&c,&d) == 4)
mazgch 31:a0bed6c1e05d 781 *ip = IPADR(a,b,c,d);
mazgch 31:a0bed6c1e05d 782 }
mazgch 31:a0bed6c1e05d 783 return WAIT;
mazgch 21:c4d64830bf02 784 }
mazgch 21:c4d64830bf02 785
mazgch 21:c4d64830bf02 786 bool MDMParser::disconnect(void)
mazgch 21:c4d64830bf02 787 {
mazgch 31:a0bed6c1e05d 788 if (_ip == NOIP)
mazgch 21:c4d64830bf02 789 return true;
mazgch 74:208e3e32d263 790 INFO("Modem::disconnect\r\n");
mazgch 32:8f12ac182bbb 791 if (_dev.dev == DEV_LISA_C200) {
mazgch 76:f7c3dd568dae 792 // There something to do here
mazgch 21:c4d64830bf02 793 } else {
mazgch 21:c4d64830bf02 794 sendFormated("AT+UPSDA=" PROFILE ",4\r\n");
mazgch 52:8071747a7cb3 795 if (RESP_OK != waitFinalResp())
mazgch 32:8f12ac182bbb 796 return false;
mazgch 21:c4d64830bf02 797 }
mazgch 31:a0bed6c1e05d 798 _ip = NOIP;
mazgch 21:c4d64830bf02 799 return true;
mazgch 21:c4d64830bf02 800 }
mazgch 21:c4d64830bf02 801
mazgch 31:a0bed6c1e05d 802 MDMParser::IP MDMParser::gethostbyname(const char* host)
mazgch 21:c4d64830bf02 803 {
mazgch 31:a0bed6c1e05d 804 IP ip = NOIP;
mazgch 31:a0bed6c1e05d 805 int a,b,c,d;
mazgch 31:a0bed6c1e05d 806 if (sscanf(host, IPSTR, &a,&b,&c,&d) == 4)
mazgch 31:a0bed6c1e05d 807 ip = IPADR(a,b,c,d);
mazgch 31:a0bed6c1e05d 808 else {
mazgch 31:a0bed6c1e05d 809 sendFormated("AT+UDNSRN=0,\"%s\"\r\n", host);
mazgch 52:8071747a7cb3 810 if (RESP_OK != waitFinalResp(_cbUDNSRN, &ip))
mazgch 31:a0bed6c1e05d 811 return false;
mazgch 21:c4d64830bf02 812 }
mazgch 31:a0bed6c1e05d 813 return ip;
mazgch 21:c4d64830bf02 814 }
mazgch 21:c4d64830bf02 815
mazgch 21:c4d64830bf02 816 // ----------------------------------------------------------------
mazgch 21:c4d64830bf02 817 // sockets
mazgch 21:c4d64830bf02 818
mazgch 21:c4d64830bf02 819 int MDMParser::_cbUSOCR(int type, const char* buf, int len, int* socket)
mazgch 21:c4d64830bf02 820 {
mazgch 21:c4d64830bf02 821 if ((type == TYPE_PLUS) && socket) {
mazgch 21:c4d64830bf02 822 const char* p = strstr(buf,"+USOCR: ");
mazgch 21:c4d64830bf02 823 if (p)
mazgch 21:c4d64830bf02 824 *socket = atoi(p+8);
mazgch 21:c4d64830bf02 825 }
mazgch 21:c4d64830bf02 826 return WAIT;
mazgch 21:c4d64830bf02 827 }
mazgch 21:c4d64830bf02 828
mazgch 63:42cb563a25bc 829 int MDMParser::socketSocket(IpProtocol ipproto, int port)
mazgch 21:c4d64830bf02 830 {
mazgch 47:9a89e5195721 831 TRACE("socketSocket(%d)\r\n", ipproto);
mazgch 21:c4d64830bf02 832 if(ipproto == IPPROTO_TCP) {
mazgch 63:42cb563a25bc 833 sendFormated("AT+USOCR=6\r\n");
mazgch 63:42cb563a25bc 834 } else if ((ipproto == IPPROTO_UDP) && (port == -1)){
mazgch 63:42cb563a25bc 835 sendFormated("AT+USOCR=17\r\n");
mazgch 63:42cb563a25bc 836 } else if (ipproto == IPPROTO_UDP){
mazgch 63:42cb563a25bc 837 sendFormated("AT+USOCR=17,%d\r\n", port);
mazgch 21:c4d64830bf02 838 } else { // other types not supported
mazgch 21:c4d64830bf02 839 return SOCKET_ERROR;
mazgch 21:c4d64830bf02 840 }
mazgch 21:c4d64830bf02 841 int socket = -1;
mazgch 52:8071747a7cb3 842 if (RESP_OK != waitFinalResp(_cbUSOCR, &socket))
mazgch 21:c4d64830bf02 843 return SOCKET_ERROR;
mazgch 21:c4d64830bf02 844 if (!ISSOCKET(socket) || (_sockets[socket].state != SOCK_FREE))
mazgch 21:c4d64830bf02 845 return SOCKET_ERROR;
mazgch 21:c4d64830bf02 846 // successfull
mazgch 21:c4d64830bf02 847 _sockets[socket].state = SOCK_CREATED;
mazgch 21:c4d64830bf02 848 _sockets[socket].pending = 0;
mazgch 66:69072b3c5bca 849 _sockets[socket].timeout_ms = TIMEOUT_BLOCKING;
mazgch 21:c4d64830bf02 850 return socket;
mazgch 21:c4d64830bf02 851 }
mazgch 21:c4d64830bf02 852
mazgch 21:c4d64830bf02 853 bool MDMParser::socketConnect(int socket, const char * host, int port)
mazgch 21:c4d64830bf02 854 {
mazgch 47:9a89e5195721 855 TRACE("socketConnect(%d,%s,%d)\r\n", socket, host,port);
mazgch 31:a0bed6c1e05d 856 IP ip = gethostbyname(host);
mazgch 31:a0bed6c1e05d 857 if (ip == NOIP)
mazgch 21:c4d64830bf02 858 return false;
mazgch 21:c4d64830bf02 859 // connect to socket
mazgch 21:c4d64830bf02 860 if (!ISSOCKET(socket) || (_sockets[socket].state != SOCK_CREATED))
mazgch 21:c4d64830bf02 861 return false;
mazgch 21:c4d64830bf02 862 sendFormated("AT+USOCO=%d,\"" IPSTR "\",%d\r\n", socket, IPNUM(ip), port);
mazgch 52:8071747a7cb3 863 if (RESP_OK != waitFinalResp())
mazgch 21:c4d64830bf02 864 return false;
mazgch 21:c4d64830bf02 865 _sockets[socket].state = SOCK_CONNECTED;
mazgch 21:c4d64830bf02 866 return true;
mazgch 21:c4d64830bf02 867 }
mazgch 21:c4d64830bf02 868
mazgch 44:9d12223b78ff 869 bool MDMParser::socketIsConnected(int socket)
mazgch 44:9d12223b78ff 870 {
mazgch 47:9a89e5195721 871 TRACE("socketIsConnected(%d)\r\n", socket);
mazgch 47:9a89e5195721 872 if (!ISSOCKET(socket))
mazgch 47:9a89e5195721 873 return false;
mazgch 47:9a89e5195721 874 return _sockets[socket].state == SOCK_CONNECTED;
mazgch 44:9d12223b78ff 875 }
mazgch 44:9d12223b78ff 876
mazgch 66:69072b3c5bca 877 bool MDMParser::socketSetBlocking(int socket, int timeout_ms)
mazgch 44:9d12223b78ff 878 {
mazgch 47:9a89e5195721 879 TRACE("socketSetBlocking(%d,%d)\r\n", socket, timeout_ms);
mazgch 44:9d12223b78ff 880 if (!ISSOCKET(socket))
mazgch 44:9d12223b78ff 881 return false;
mazgch 44:9d12223b78ff 882 _sockets[socket].timeout_ms = timeout_ms;
mazgch 44:9d12223b78ff 883 return true;
mazgch 44:9d12223b78ff 884 }
mazgch 44:9d12223b78ff 885
mazgch 21:c4d64830bf02 886 bool MDMParser::socketClose(int socket)
mazgch 21:c4d64830bf02 887 {
mazgch 47:9a89e5195721 888 TRACE("socketClose(%d)\r\n", socket);
mazgch 21:c4d64830bf02 889 if (!ISSOCKET(socket) || (_sockets[socket].state != SOCK_CONNECTED))
mazgch 21:c4d64830bf02 890 return false;
mazgch 21:c4d64830bf02 891 sendFormated("AT+USOCL=%d\r\n", socket);
mazgch 52:8071747a7cb3 892 if (RESP_OK != waitFinalResp())
mazgch 21:c4d64830bf02 893 return false;
mazgch 44:9d12223b78ff 894 _sockets[socket].state = SOCK_CREATED;
mazgch 21:c4d64830bf02 895 return true;
mazgch 21:c4d64830bf02 896 }
mazgch 21:c4d64830bf02 897
mazgch 21:c4d64830bf02 898 bool MDMParser::socketFree(int socket)
mazgch 21:c4d64830bf02 899 {
mazgch 47:9a89e5195721 900 TRACE("socketFree(%d)\r\n", socket);
mazgch 21:c4d64830bf02 901 socketClose(socket);
mazgch 21:c4d64830bf02 902 if (!ISSOCKET(socket) || (_sockets[socket].state != SOCK_CREATED))
mazgch 21:c4d64830bf02 903 return false;
mazgch 21:c4d64830bf02 904 _sockets[socket].state = SOCK_FREE;
mazgch 21:c4d64830bf02 905 return true;
mazgch 21:c4d64830bf02 906 }
mazgch 21:c4d64830bf02 907
mazgch 69:4d6fa520dfca 908 #define USO_MAX_WRITE 1024 //!< maximum number of bytes to write to socket
mazgch 69:4d6fa520dfca 909
mazgch 21:c4d64830bf02 910 int MDMParser::socketSend(int socket, const char * buf, int len)
mazgch 21:c4d64830bf02 911 {
mazgch 47:9a89e5195721 912 TRACE("socketSend(%d,,%d)\r\n", socket,len);
mazgch 68:33a96cf64986 913 int cnt = len;
mazgch 68:33a96cf64986 914 while (cnt > 0) {
mazgch 69:4d6fa520dfca 915 int blk = USO_MAX_WRITE;
mazgch 68:33a96cf64986 916 if (cnt < blk)
mazgch 68:33a96cf64986 917 blk = cnt;
mazgch 68:33a96cf64986 918 sendFormated("AT+USOWR=%d,%d\r\n",socket,blk);
mazgch 52:8071747a7cb3 919 if (RESP_PROMPT != waitFinalResp())
mazgch 21:c4d64830bf02 920 return SOCKET_ERROR;
mazgch 74:208e3e32d263 921 RELAX_MS(50);
mazgch 68:33a96cf64986 922 send(buf, blk);
mazgch 52:8071747a7cb3 923 if (RESP_OK != waitFinalResp())
mazgch 21:c4d64830bf02 924 return SOCKET_ERROR;
mazgch 68:33a96cf64986 925 buf += blk;
mazgch 68:33a96cf64986 926 cnt -= blk;
mazgch 21:c4d64830bf02 927 }
mazgch 68:33a96cf64986 928 return (len - cnt);
mazgch 21:c4d64830bf02 929 }
mazgch 21:c4d64830bf02 930
mazgch 21:c4d64830bf02 931 int MDMParser::socketSendTo(int socket, IP ip, int port, const char * buf, int len)
mazgch 21:c4d64830bf02 932 {
mazgch 65:dd94f920a762 933 TRACE("socketSendTo(%d," IPSTR ",%d,,%d)\r\n", socket, IPNUM(ip),port,len);
mazgch 68:33a96cf64986 934 int cnt = len;
mazgch 68:33a96cf64986 935 while (cnt > 0) {
mazgch 69:4d6fa520dfca 936 int blk = USO_MAX_WRITE;
mazgch 68:33a96cf64986 937 if (cnt < blk)
mazgch 68:33a96cf64986 938 blk = cnt;
mazgch 68:33a96cf64986 939 sendFormated("AT+USOST=%d,\"" IPSTR "\",%d,%d\r\n",socket,IPNUM(ip),port,blk);
mazgch 52:8071747a7cb3 940 if (RESP_PROMPT != waitFinalResp())
mazgch 21:c4d64830bf02 941 return SOCKET_ERROR;
mazgch 74:208e3e32d263 942 RELAX_MS(50);
mazgch 68:33a96cf64986 943 send(buf, blk);
mazgch 63:42cb563a25bc 944 if (RESP_OK != waitFinalResp())
mazgch 21:c4d64830bf02 945 return SOCKET_ERROR;
mazgch 68:33a96cf64986 946 buf += blk;
mazgch 68:33a96cf64986 947 cnt -= blk;
mazgch 21:c4d64830bf02 948 }
mazgch 68:33a96cf64986 949 return (len - cnt);
mazgch 21:c4d64830bf02 950 }
mazgch 21:c4d64830bf02 951
mazgch 21:c4d64830bf02 952 int MDMParser::socketReadable(int socket)
mazgch 21:c4d64830bf02 953 {
mazgch 47:9a89e5195721 954 TRACE("socketReadable(%d)\r\n", socket);
mazgch 21:c4d64830bf02 955 if (!ISSOCKET(socket) || (_sockets[socket].state != SOCK_CONNECTED))
mazgch 21:c4d64830bf02 956 return SOCKET_ERROR;
mazgch 21:c4d64830bf02 957 // allow to receive unsolicited commands
mazgch 21:c4d64830bf02 958 waitFinalResp(NULL, NULL, 0);
mazgch 21:c4d64830bf02 959 if (_sockets[socket].state != SOCK_CONNECTED)
mazgch 21:c4d64830bf02 960 return SOCKET_ERROR;
mazgch 21:c4d64830bf02 961 return _sockets[socket].pending;
mazgch 21:c4d64830bf02 962 }
mazgch 21:c4d64830bf02 963
mazgch 21:c4d64830bf02 964 int MDMParser::_cbUSORD(int type, const char* buf, int len, char* out)
mazgch 21:c4d64830bf02 965 {
mazgch 21:c4d64830bf02 966 if ((type == TYPE_PLUS) && out) {
mazgch 21:c4d64830bf02 967 int sz, sk;
mazgch 21:c4d64830bf02 968 if ((sscanf(buf, "\r\n+USORD: %d,%d,", &sk, &sz) == 2) &&
mazgch 21:c4d64830bf02 969 (buf[len-sz-2] == '\"') && (buf[len-1] == '\"')) {
mazgch 21:c4d64830bf02 970 memcpy(out, &buf[len-1-sz], sz);
mazgch 21:c4d64830bf02 971 }
mazgch 21:c4d64830bf02 972 }
mazgch 21:c4d64830bf02 973 return WAIT;
mazgch 21:c4d64830bf02 974 }
mazgch 21:c4d64830bf02 975
mazgch 21:c4d64830bf02 976 int MDMParser::socketRecv(int socket, char* buf, int len)
mazgch 21:c4d64830bf02 977 {
mazgch 21:c4d64830bf02 978 int cnt = 0;
mazgch 47:9a89e5195721 979 TRACE("socketRecv(%d,,%d)\r\n", socket, len);
mazgch 21:c4d64830bf02 980 if (!ISSOCKET(socket))
mazgch 21:c4d64830bf02 981 return SOCKET_ERROR;
mazgch 21:c4d64830bf02 982 memset(buf, '\0', len);
mazgch 44:9d12223b78ff 983 Timer timer;
mazgch 44:9d12223b78ff 984 timer.start();
mazgch 21:c4d64830bf02 985 while (len) {
mazgch 69:4d6fa520dfca 986 int blk = MAX_SIZE; // still need space for headers and unsolicited commands
mazgch 21:c4d64830bf02 987 if (_sockets[socket].pending < blk)
mazgch 21:c4d64830bf02 988 blk = _sockets[socket].pending;
mazgch 21:c4d64830bf02 989 if (len < blk) blk = len;
mazgch 21:c4d64830bf02 990 if (blk) {
mazgch 44:9d12223b78ff 991 sendFormated("AT+USORD=%d,%d\r\n",socket, blk);
mazgch 52:8071747a7cb3 992 if (RESP_OK != waitFinalResp(_cbUSORD, buf)) {
mazgch 44:9d12223b78ff 993 return SOCKET_ERROR;
mazgch 21:c4d64830bf02 994 }
mazgch 21:c4d64830bf02 995 len -= blk;
mazgch 21:c4d64830bf02 996 cnt += blk;
mazgch 21:c4d64830bf02 997 buf += blk;
mazgch 21:c4d64830bf02 998 _sockets[socket].pending -= blk;
mazgch 75:ce6e12067d0c 999 } else if ((_sockets[socket].state == SOCK_CONNECTED) &&
mazgch 75:ce6e12067d0c 1000 !TIMEOUT(timer, _sockets[socket].timeout_ms)) {
mazgch 21:c4d64830bf02 1001 // allow to receive unsolicited commands
mazgch 21:c4d64830bf02 1002 waitFinalResp(NULL, NULL, 10);
mazgch 44:9d12223b78ff 1003 } else {
mazgch 44:9d12223b78ff 1004 len = 0; // no more data and socket closed or timed-out
mazgch 21:c4d64830bf02 1005 }
mazgch 21:c4d64830bf02 1006 }
mazgch 21:c4d64830bf02 1007 return cnt;
mazgch 21:c4d64830bf02 1008 }
mazgch 21:c4d64830bf02 1009
mazgch 21:c4d64830bf02 1010 int MDMParser::_cbUSORF(int type, const char* buf, int len, USORFparam* param)
mazgch 21:c4d64830bf02 1011 {
mazgch 21:c4d64830bf02 1012 if ((type == TYPE_PLUS) && param) {
mazgch 21:c4d64830bf02 1013 int sz, sk, p, a,b,c,d;
mazgch 21:c4d64830bf02 1014 if ((sscanf(buf, "\r\n+USORF: %d,\""IPSTR"\",%d,%d,",
mazgch 21:c4d64830bf02 1015 &sk,&a,&b,&c,&d,&p,&sz) == 7) &&
mazgch 21:c4d64830bf02 1016 (buf[len-sz-2] == '\"') && (buf[len-1] == '\"')) {
mazgch 21:c4d64830bf02 1017 memcpy(param->buf, &buf[len-1-sz], sz);
mazgch 21:c4d64830bf02 1018 param->ip = IPADR(a,b,c,d);
mazgch 21:c4d64830bf02 1019 param->port = p;
mazgch 21:c4d64830bf02 1020 }
mazgch 21:c4d64830bf02 1021 }
mazgch 21:c4d64830bf02 1022 return WAIT;
mazgch 21:c4d64830bf02 1023 }
mazgch 21:c4d64830bf02 1024
mazgch 63:42cb563a25bc 1025 int MDMParser::socketRecvFrom(int socket, IP* ip, int* port, char* buf, int len)
mazgch 21:c4d64830bf02 1026 {
mazgch 21:c4d64830bf02 1027 int cnt = 0;
mazgch 63:42cb563a25bc 1028 TRACE("socketRecvFrom(%d,,%d)\r\n", socket, len);
mazgch 21:c4d64830bf02 1029 if (!ISSOCKET(socket))
mazgch 21:c4d64830bf02 1030 return SOCKET_ERROR;
mazgch 21:c4d64830bf02 1031 memset(buf, '\0', len);
mazgch 44:9d12223b78ff 1032 Timer timer;
mazgch 44:9d12223b78ff 1033 timer.start();
mazgch 21:c4d64830bf02 1034 while (len) {
mazgch 69:4d6fa520dfca 1035 int blk = MAX_SIZE; // still need space for headers and unsolicited commands
mazgch 21:c4d64830bf02 1036 if (_sockets[socket].pending < blk)
mazgch 21:c4d64830bf02 1037 blk = _sockets[socket].pending;
mazgch 21:c4d64830bf02 1038 if (len < blk) blk = len;
mazgch 21:c4d64830bf02 1039 if (blk) {
mazgch 21:c4d64830bf02 1040 sendFormated("AT+USORF=%d,%d\r\n",socket, blk);
mazgch 21:c4d64830bf02 1041 USORFparam param;
mazgch 21:c4d64830bf02 1042 param.buf = buf;
mazgch 52:8071747a7cb3 1043 if (RESP_OK != waitFinalResp(_cbUSORF, &param)) {
mazgch 44:9d12223b78ff 1044 return SOCKET_ERROR;
mazgch 21:c4d64830bf02 1045 }
mazgch 21:c4d64830bf02 1046 *ip = param.ip;
mazgch 63:42cb563a25bc 1047 *port = param.port;
mazgch 21:c4d64830bf02 1048 len -= blk;
mazgch 21:c4d64830bf02 1049 cnt += blk;
mazgch 21:c4d64830bf02 1050 buf += blk;
mazgch 21:c4d64830bf02 1051 _sockets[socket].pending -= blk;
mazgch 75:ce6e12067d0c 1052 } else if (!TIMEOUT(timer, _sockets[socket].timeout_ms)) {
mazgch 21:c4d64830bf02 1053 // allow to receive unsolicited commands
mazgch 21:c4d64830bf02 1054 waitFinalResp(NULL, NULL, 10);
mazgch 75:ce6e12067d0c 1055 } else
mazgch 44:9d12223b78ff 1056 len = 0; // no more data and socket closed or timed-out
mazgch 21:c4d64830bf02 1057 }
mazgch 44:9d12223b78ff 1058 timer.stop();
mazgch 44:9d12223b78ff 1059 timer.reset();
mazgch 21:c4d64830bf02 1060 return cnt;
mazgch 21:c4d64830bf02 1061 }
mazgch 21:c4d64830bf02 1062
mazgch 21:c4d64830bf02 1063 // ----------------------------------------------------------------
mazgch 31:a0bed6c1e05d 1064
mazgch 31:a0bed6c1e05d 1065 int MDMParser::_cbCMGL(int type, const char* buf, int len, CMGLparam* param)
mazgch 21:c4d64830bf02 1066 {
mazgch 31:a0bed6c1e05d 1067 if ((type == TYPE_PLUS) && param && param->num) {
mazgch 31:a0bed6c1e05d 1068 // +CMGL: <ix>,...
mazgch 31:a0bed6c1e05d 1069 int ix;
mazgch 31:a0bed6c1e05d 1070 if (sscanf(buf, "\r\n+CMGL: %d,", &ix) == 1)
mazgch 31:a0bed6c1e05d 1071 {
mazgch 31:a0bed6c1e05d 1072 *param->ix++ = ix;
mazgch 31:a0bed6c1e05d 1073 param->num--;
mazgch 31:a0bed6c1e05d 1074 }
mazgch 29:53d346010624 1075 }
mazgch 29:53d346010624 1076 return WAIT;
mazgch 21:c4d64830bf02 1077 }
mazgch 21:c4d64830bf02 1078
mazgch 31:a0bed6c1e05d 1079 int MDMParser::smsList(const char* stat /*= "ALL"*/, int* ix /*=NULL*/, int num /*= 0*/) {
mazgch 31:a0bed6c1e05d 1080 sendFormated("AT+CMGL=\"%s\"\r\n", stat);
mazgch 31:a0bed6c1e05d 1081 CMGLparam param;
mazgch 31:a0bed6c1e05d 1082 param.ix = ix;
mazgch 31:a0bed6c1e05d 1083 param.num = num;
mazgch 52:8071747a7cb3 1084 if (RESP_OK != waitFinalResp(_cbCMGL, &param))
mazgch 31:a0bed6c1e05d 1085 return -1;
mazgch 31:a0bed6c1e05d 1086 return num - param.num;
mazgch 21:c4d64830bf02 1087 }
mazgch 21:c4d64830bf02 1088
mazgch 21:c4d64830bf02 1089 bool MDMParser::smsSend(const char* num, const char* buf)
mazgch 21:c4d64830bf02 1090 {
mazgch 80:34985b4d821e 1091 sendFormated("AT+CMGS=\"%s\"\r\n",num);
mazgch 58:e38a2e942fbb 1092 if (RESP_PROMPT != waitFinalResp(NULL,NULL,150*1000)) {
mazgch 21:c4d64830bf02 1093 return false;
mazgch 21:c4d64830bf02 1094 }
mazgch 21:c4d64830bf02 1095 send(buf, strlen(buf));
mazgch 21:c4d64830bf02 1096 const char ctrlZ = 0x1A;
mazgch 21:c4d64830bf02 1097 send(&ctrlZ, sizeof(ctrlZ));
mazgch 52:8071747a7cb3 1098 if (RESP_OK != waitFinalResp()) {
mazgch 21:c4d64830bf02 1099 return false;
mazgch 21:c4d64830bf02 1100 }
mazgch 21:c4d64830bf02 1101 return true;
mazgch 21:c4d64830bf02 1102 }
mazgch 21:c4d64830bf02 1103
mazgch 21:c4d64830bf02 1104 bool MDMParser::smsDelete(int ix)
mazgch 21:c4d64830bf02 1105 {
mazgch 21:c4d64830bf02 1106 sendFormated("AT+CMGD=%d\r\n",ix);
mazgch 52:8071747a7cb3 1107 if (RESP_OK != waitFinalResp()) {
mazgch 21:c4d64830bf02 1108 return false;
mazgch 21:c4d64830bf02 1109 }
mazgch 21:c4d64830bf02 1110 return true;
mazgch 21:c4d64830bf02 1111 }
mazgch 21:c4d64830bf02 1112
mazgch 21:c4d64830bf02 1113 int MDMParser::_cbCMGR(int type, const char* buf, int len, CMGRparam* param)
mazgch 21:c4d64830bf02 1114 {
mazgch 21:c4d64830bf02 1115 if (param) {
mazgch 21:c4d64830bf02 1116 if (type == TYPE_PLUS) {
mazgch 21:c4d64830bf02 1117 if (sscanf(buf, "\r\n+CMGR: \"%*[^\"]\",\"%[^\"]", param->num) == 1) {
mazgch 21:c4d64830bf02 1118 }
mazgch 37:cc3433329d66 1119 } else if ((type == TYPE_UNKNOWN) && (buf[len-2] == '\r') && (buf[len-1] == '\n')) {
mazgch 21:c4d64830bf02 1120 memcpy(param->buf, buf, len-2);
mazgch 21:c4d64830bf02 1121 param->buf[len-2] = '\0';
mazgch 21:c4d64830bf02 1122 }
mazgch 21:c4d64830bf02 1123 }
mazgch 21:c4d64830bf02 1124 return WAIT;
mazgch 21:c4d64830bf02 1125 }
mazgch 21:c4d64830bf02 1126
mazgch 21:c4d64830bf02 1127 bool MDMParser::smsRead(int ix, char* num, char* buf, int len)
mazgch 21:c4d64830bf02 1128 {
mazgch 21:c4d64830bf02 1129 CMGRparam param;
mazgch 21:c4d64830bf02 1130 param.num = num;
mazgch 21:c4d64830bf02 1131 param.buf = buf;
mazgch 21:c4d64830bf02 1132 sendFormated("AT+CMGR=%d\r\n",ix);
mazgch 52:8071747a7cb3 1133 if (RESP_OK != waitFinalResp(_cbCMGR, &param)) {
mazgch 21:c4d64830bf02 1134 return false;
mazgch 21:c4d64830bf02 1135 }
mazgch 21:c4d64830bf02 1136 return true;
mazgch 21:c4d64830bf02 1137 }
mazgch 54:7ba8e4c218e2 1138
mazgch 54:7ba8e4c218e2 1139 // ----------------------------------------------------------------
mazgch 70:0a87d256cd24 1140
mazgch 70:0a87d256cd24 1141 int MDMParser::_cbCUSD(int type, const char* buf, int len, char* resp)
mazgch 70:0a87d256cd24 1142 {
mazgch 70:0a87d256cd24 1143 if ((type == TYPE_PLUS) && resp) {
mazgch 70:0a87d256cd24 1144 // +USD: \"%*[^\"]\",\"%[^\"]\",,\"%*[^\"]\",%d,%d,%d,%d,\"*[^\"]\",%d,%d"..);
mazgch 70:0a87d256cd24 1145 if (sscanf(buf, "\r\n+CUSD: %*d,\"%[^\"]\",%*d", resp) == 1) {
mazgch 70:0a87d256cd24 1146 /*nothing*/
mazgch 70:0a87d256cd24 1147 }
mazgch 70:0a87d256cd24 1148 }
mazgch 70:0a87d256cd24 1149 return WAIT;
mazgch 70:0a87d256cd24 1150 }
mazgch 70:0a87d256cd24 1151
mazgch 70:0a87d256cd24 1152 bool MDMParser::ussdCommand(const char* cmd, char* buf)
mazgch 70:0a87d256cd24 1153 {
mazgch 80:34985b4d821e 1154 if (_dev.dev == DEV_LISA_C200)
mazgch 80:34985b4d821e 1155 return false;
mazgch 70:0a87d256cd24 1156 *buf = '\0';
mazgch 70:0a87d256cd24 1157 sendFormated("AT+CUSD=1,\"%s\"\r\n",cmd);
mazgch 70:0a87d256cd24 1158 if (RESP_OK != waitFinalResp(_cbCUSD, buf)) {
mazgch 70:0a87d256cd24 1159 return false;
mazgch 70:0a87d256cd24 1160 }
mazgch 70:0a87d256cd24 1161 return true;
mazgch 70:0a87d256cd24 1162 }
mazgch 80:34985b4d821e 1163
mazgch 80:34985b4d821e 1164 // ----------------------------------------------------------------
mazgch 70:0a87d256cd24 1165
mazgch 80:34985b4d821e 1166 bool MDMParser::delFile(const char* filename)
mazgch 80:34985b4d821e 1167 {
mazgch 80:34985b4d821e 1168 sendFormated("AT+UDELFILE=\"%s\"\r\n", filename);
mazgch 80:34985b4d821e 1169 if (RESP_OK != waitFinalResp())
mazgch 80:34985b4d821e 1170 return false;
mazgch 80:34985b4d821e 1171 return true;
mazgch 80:34985b4d821e 1172 }
mazgch 80:34985b4d821e 1173
mazgch 80:34985b4d821e 1174 int MDMParser::writeFile(const char* filename, const char* buf, int len)
mazgch 80:34985b4d821e 1175 {
mazgch 80:34985b4d821e 1176 sendFormated("AT+UDWNFILE=\"%s\",%d\r\n", filename, len);
mazgch 80:34985b4d821e 1177 if (RESP_PROMPT != waitFinalResp())
mazgch 80:34985b4d821e 1178 return 0;
mazgch 80:34985b4d821e 1179 send(buf, len);
mazgch 80:34985b4d821e 1180 if (RESP_OK != waitFinalResp())
mazgch 80:34985b4d821e 1181 return 0;
mazgch 80:34985b4d821e 1182 return len;
mazgch 80:34985b4d821e 1183 }
mazgch 80:34985b4d821e 1184
mazgch 80:34985b4d821e 1185 int MDMParser::readFile(const char* filename, char* buf, int len)
mazgch 80:34985b4d821e 1186 {
mazgch 80:34985b4d821e 1187 sendFormated("AT+URDFILE=\"%s\"\r\n", filename, len);
mazgch 80:34985b4d821e 1188 URDFILEparam param;
mazgch 80:34985b4d821e 1189 param.filename = filename;
mazgch 80:34985b4d821e 1190 param.buf = buf;
mazgch 80:34985b4d821e 1191 param.sz = len;
mazgch 80:34985b4d821e 1192 param.len = 0;
mazgch 80:34985b4d821e 1193 if (RESP_OK != waitFinalResp(_cbURDFILE, &param))
mazgch 80:34985b4d821e 1194 return -1;
mazgch 80:34985b4d821e 1195 return param.len;
mazgch 80:34985b4d821e 1196 }
mazgch 80:34985b4d821e 1197
mazgch 80:34985b4d821e 1198 int MDMParser::_cbURDFILE(int type, const char* buf, int len, URDFILEparam* param)
mazgch 80:34985b4d821e 1199 {
mazgch 80:34985b4d821e 1200 if ((type == TYPE_PLUS) && param && param->filename && param->buf) {
mazgch 80:34985b4d821e 1201 char filename[48];
mazgch 80:34985b4d821e 1202 int sz;
mazgch 80:34985b4d821e 1203 if ((sscanf(buf, "\r\n+URDFILE: \"%[^\"]\",%d,", filename, &sz) == 2) &&
mazgch 80:34985b4d821e 1204 (0 == strcmp(param->filename, filename)) &&
mazgch 80:34985b4d821e 1205 (buf[len-sz-2] == '\"') && (buf[len-1] == '\"')) {
mazgch 80:34985b4d821e 1206 param->len = (sz < param->sz) ? sz : param->sz;
mazgch 80:34985b4d821e 1207 memcpy(param->buf, &buf[len-1-sz], param->len);
mazgch 80:34985b4d821e 1208 }
mazgch 80:34985b4d821e 1209 }
mazgch 80:34985b4d821e 1210 return WAIT;
mazgch 80:34985b4d821e 1211 }
mazgch 80:34985b4d821e 1212
mazgch 70:0a87d256cd24 1213 // ----------------------------------------------------------------
mazgch 74:208e3e32d263 1214 bool MDMParser::setDebug(int level)
mazgch 74:208e3e32d263 1215 {
mazgch 74:208e3e32d263 1216 #ifdef MDM_DEBUG
mazgch 74:208e3e32d263 1217 if ((_debugLevel >= 0) && (level >= 0)) {
mazgch 74:208e3e32d263 1218 _debugLevel = level;
mazgch 74:208e3e32d263 1219 return true;
mazgch 74:208e3e32d263 1220 }
mazgch 74:208e3e32d263 1221 #endif
mazgch 74:208e3e32d263 1222 return false;
mazgch 74:208e3e32d263 1223 }
mazgch 74:208e3e32d263 1224
mazgch 73:2b32e0a21df2 1225 void MDMParser::dumpDevStatus(MDMParser::DevStatus* status,
mazgch 73:2b32e0a21df2 1226 _DPRINT dprint, void* param)
mazgch 54:7ba8e4c218e2 1227 {
mazgch 75:ce6e12067d0c 1228 dprint(param, "Modem::devStatus\r\n");
mazgch 54:7ba8e4c218e2 1229 const char* txtDev[] = { "Unknown", "SARA-G350", "LISA-U200", "LISA-C200" };
mazgch 54:7ba8e4c218e2 1230 if (status->dev < sizeof(txtDev)/sizeof(*txtDev) && (status->dev != MDMParser::DEV_UNKNOWN))
mazgch 73:2b32e0a21df2 1231 dprint(param, " Device: %s\r\n", txtDev[status->dev]);
mazgch 54:7ba8e4c218e2 1232 const char* txtLpm[] = { "Disabled", "Enabled", "Active" };
mazgch 54:7ba8e4c218e2 1233 if (status->lpm < sizeof(txtLpm)/sizeof(*txtLpm))
mazgch 73:2b32e0a21df2 1234 dprint(param, " Power Save: %s\r\n", txtLpm[status->lpm]);
mazgch 75:ce6e12067d0c 1235 const char* txtSim[] = { "Unknown", "Missing", "Pin", "Ready" };
mazgch 54:7ba8e4c218e2 1236 if (status->sim < sizeof(txtSim)/sizeof(*txtSim) && (status->sim != MDMParser::SIM_UNKNOWN))
mazgch 73:2b32e0a21df2 1237 dprint(param, " SIM: %s\r\n", txtSim[status->sim]);
mazgch 54:7ba8e4c218e2 1238 if (*status->ccid)
mazgch 73:2b32e0a21df2 1239 dprint(param, " CCID: %s\r\n", status->ccid);
mazgch 54:7ba8e4c218e2 1240 if (*status->imei)
mazgch 73:2b32e0a21df2 1241 dprint(param, " IMEI: %s\r\n", status->imei);
mazgch 54:7ba8e4c218e2 1242 if (*status->imsi)
mazgch 73:2b32e0a21df2 1243 dprint(param, " IMSI: %s\r\n", status->imsi);
mazgch 54:7ba8e4c218e2 1244 if (*status->meid)
mazgch 73:2b32e0a21df2 1245 dprint(param, " MEID: %s\r\n", status->meid); // LISA-C
mazgch 54:7ba8e4c218e2 1246 if (*status->manu)
mazgch 73:2b32e0a21df2 1247 dprint(param, " Manufacturer: %s\r\n", status->manu);
mazgch 54:7ba8e4c218e2 1248 if (*status->model)
mazgch 73:2b32e0a21df2 1249 dprint(param, " Model: %s\r\n", status->model);
mazgch 54:7ba8e4c218e2 1250 if (*status->ver)
mazgch 73:2b32e0a21df2 1251 dprint(param, " Version: %s\r\n", status->ver);
mazgch 54:7ba8e4c218e2 1252 }
mazgch 54:7ba8e4c218e2 1253
mazgch 73:2b32e0a21df2 1254 void MDMParser::dumpNetStatus(MDMParser::NetStatus *status,
mazgch 73:2b32e0a21df2 1255 _DPRINT dprint, void* param)
mazgch 54:7ba8e4c218e2 1256 {
mazgch 75:ce6e12067d0c 1257 dprint(param, "Modem::netStatus\r\n");
mazgch 54:7ba8e4c218e2 1258 const char* txtReg[] = { "Unknown", "Denied", "None", "Home", "Roaming" };
mazgch 79:291df065e345 1259 if (status->csd < sizeof(txtReg)/sizeof(*txtReg) && (status->csd != MDMParser::REG_UNKNOWN))
mazgch 79:291df065e345 1260 dprint(param, " CSD Registration: %s\r\n", txtReg[status->csd]);
mazgch 79:291df065e345 1261 if (status->psd < sizeof(txtReg)/sizeof(*txtReg) && (status->psd != MDMParser::REG_UNKNOWN))
mazgch 79:291df065e345 1262 dprint(param, " PSD Registration: %s\r\n", txtReg[status->psd]);
mazgch 54:7ba8e4c218e2 1263 const char* txtAct[] = { "Unknown", "GSM", "Edge", "3G", "CDMA" };
mazgch 54:7ba8e4c218e2 1264 if (status->act < sizeof(txtAct)/sizeof(*txtAct) && (status->act != MDMParser::ACT_UNKNOWN))
mazgch 73:2b32e0a21df2 1265 dprint(param, " Access Technology: %s\r\n", txtAct[status->act]);
mazgch 54:7ba8e4c218e2 1266 if (status->rssi)
mazgch 73:2b32e0a21df2 1267 dprint(param, " Signal Strength: %d dBm\r\n", status->rssi);
mazgch 54:7ba8e4c218e2 1268 if (status->ber)
mazgch 73:2b32e0a21df2 1269 dprint(param, " Bit Error Rate: %d\r\n", status->ber);
mazgch 54:7ba8e4c218e2 1270 if (*status->opr)
mazgch 73:2b32e0a21df2 1271 dprint(param, " Operator: %s\r\n", status->opr);
mazgch 54:7ba8e4c218e2 1272 if (status->lac != 0xFFFF)
mazgch 73:2b32e0a21df2 1273 dprint(param, " Location Area Code: %04X\r\n", status->lac);
mazgch 54:7ba8e4c218e2 1274 if (status->ci != 0xFFFFFFFF)
mazgch 73:2b32e0a21df2 1275 dprint(param, " Cell ID: %08X\r\n", status->ci);
mazgch 54:7ba8e4c218e2 1276 if (*status->num)
mazgch 73:2b32e0a21df2 1277 dprint(param, " Phone Number: %s\r\n", status->num);
mazgch 54:7ba8e4c218e2 1278 }
mazgch 54:7ba8e4c218e2 1279
mazgch 73:2b32e0a21df2 1280 void MDMParser::dumpIp(MDMParser::IP ip,
mazgch 73:2b32e0a21df2 1281 _DPRINT dprint, void* param)
mazgch 54:7ba8e4c218e2 1282 {
mazgch 57:869bd35f44cc 1283 if (ip != NOIP)
mazgch 75:ce6e12067d0c 1284 dprint(param, "Modem:IP " IPSTR "\r\n", IPNUM(ip));
mazgch 54:7ba8e4c218e2 1285 }
mazgch 70:0a87d256cd24 1286
mazgch 21:c4d64830bf02 1287 // ----------------------------------------------------------------
mazgch 21:c4d64830bf02 1288 int MDMParser::_parseMatch(Pipe<char>* pipe, int len, const char* sta, const char* end)
mazgch 18:e5697801df29 1289 {
mazgch 18:e5697801df29 1290 int o = 0;
mazgch 21:c4d64830bf02 1291 if (sta) {
mazgch 21:c4d64830bf02 1292 while (*sta) {
mazgch 21:c4d64830bf02 1293 if (++o > len) return WAIT;
mazgch 21:c4d64830bf02 1294 char ch = pipe->next();
mazgch 21:c4d64830bf02 1295 if (*sta++ != ch) return NOT_FOUND;
mazgch 21:c4d64830bf02 1296 }
mazgch 21:c4d64830bf02 1297 }
mazgch 21:c4d64830bf02 1298 if (!end) return o; // no termination
mazgch 35:9275215a3a5b 1299 // at least any char
mazgch 35:9275215a3a5b 1300 if (++o > len) return WAIT;
mazgch 35:9275215a3a5b 1301 pipe->next();
mazgch 35:9275215a3a5b 1302 // check the end
mazgch 21:c4d64830bf02 1303 int x = 0;
mazgch 21:c4d64830bf02 1304 while (end[x]) {
mazgch 21:c4d64830bf02 1305 if (++o > len) return WAIT;
mazgch 21:c4d64830bf02 1306 char ch = pipe->next();
mazgch 21:c4d64830bf02 1307 x = (end[x] == ch) ? x + 1 :
mazgch 21:c4d64830bf02 1308 (end[0] == ch) ? 1 :
mazgch 21:c4d64830bf02 1309 0;
mazgch 21:c4d64830bf02 1310 }
mazgch 21:c4d64830bf02 1311 return o;
mazgch 21:c4d64830bf02 1312 }
mazgch 21:c4d64830bf02 1313
mazgch 21:c4d64830bf02 1314 int MDMParser::_parseFormated(Pipe<char>* pipe, int len, const char* fmt)
mazgch 21:c4d64830bf02 1315 {
mazgch 21:c4d64830bf02 1316 int o = 0;
mazgch 21:c4d64830bf02 1317 int num = 0;
mazgch 21:c4d64830bf02 1318 if (fmt) {
mazgch 21:c4d64830bf02 1319 while (*fmt) {
mazgch 21:c4d64830bf02 1320 if (++o > len) return WAIT;
mazgch 21:c4d64830bf02 1321 char ch = pipe->next();
mazgch 21:c4d64830bf02 1322 if (*fmt == '%') {
mazgch 21:c4d64830bf02 1323 fmt++;
mazgch 21:c4d64830bf02 1324 if (*fmt == 'd') { // numeric
mazgch 21:c4d64830bf02 1325 fmt ++;
mazgch 21:c4d64830bf02 1326 num = 0;
mazgch 21:c4d64830bf02 1327 while (ch >= '0' && ch <= '9') {
mazgch 21:c4d64830bf02 1328 num = num * 10 + (ch - '0');
mazgch 21:c4d64830bf02 1329 if (++o > len) return WAIT;
mazgch 21:c4d64830bf02 1330 ch = pipe->next();
mazgch 21:c4d64830bf02 1331 }
mazgch 21:c4d64830bf02 1332 }
mazgch 21:c4d64830bf02 1333 else if (*fmt == 'c') { // char buffer (takes last numeric as length)
mazgch 21:c4d64830bf02 1334 fmt ++;
mazgch 21:c4d64830bf02 1335 while (num --) {
mazgch 21:c4d64830bf02 1336 if (++o > len) return WAIT;
mazgch 21:c4d64830bf02 1337 ch = pipe->next();
mazgch 21:c4d64830bf02 1338 }
mazgch 21:c4d64830bf02 1339 }
mazgch 80:34985b4d821e 1340 else if (*fmt == 's') {
mazgch 80:34985b4d821e 1341 fmt ++;
mazgch 80:34985b4d821e 1342 if (ch != '\"') return NOT_FOUND;
mazgch 80:34985b4d821e 1343 do {
mazgch 80:34985b4d821e 1344 if (++o > len) return WAIT;
mazgch 80:34985b4d821e 1345 ch = pipe->next();
mazgch 80:34985b4d821e 1346 } while (ch != '\"');
mazgch 80:34985b4d821e 1347 if (++o > len) return WAIT;
mazgch 80:34985b4d821e 1348 ch = pipe->next();
mazgch 80:34985b4d821e 1349 }
mazgch 21:c4d64830bf02 1350 }
mazgch 21:c4d64830bf02 1351 if (*fmt++ != ch) return NOT_FOUND;
mazgch 18:e5697801df29 1352 }
mazgch 18:e5697801df29 1353 }
mazgch 21:c4d64830bf02 1354 return o;
mazgch 21:c4d64830bf02 1355 }
mazgch 21:c4d64830bf02 1356
mazgch 21:c4d64830bf02 1357 int MDMParser::_getLine(Pipe<char>* pipe, char* buf, int len)
mazgch 21:c4d64830bf02 1358 {
mazgch 21:c4d64830bf02 1359 int unkn = 0;
mazgch 21:c4d64830bf02 1360 int sz = pipe->size();
mazgch 21:c4d64830bf02 1361 int fr = pipe->free();
mazgch 21:c4d64830bf02 1362 if (len > sz)
mazgch 21:c4d64830bf02 1363 len = sz;
mazgch 21:c4d64830bf02 1364 while (len > 0)
mazgch 21:c4d64830bf02 1365 {
mazgch 21:c4d64830bf02 1366 static struct {
mazgch 21:c4d64830bf02 1367 const char* fmt; int type;
mazgch 21:c4d64830bf02 1368 } lutF[] = {
mazgch 21:c4d64830bf02 1369 { "\r\n+USORD: %d,%d,\"%c\"", TYPE_PLUS },
mazgch 21:c4d64830bf02 1370 { "\r\n+USORF: %d,\""IPSTR"\",%d,%d,\"%c\"", TYPE_PLUS },
mazgch 80:34985b4d821e 1371 { "\r\n+URDFILE: %s,%d,\"%c\"", TYPE_PLUS },
mazgch 21:c4d64830bf02 1372 };
mazgch 21:c4d64830bf02 1373 static struct {
mazgch 21:c4d64830bf02 1374 const char* sta; const char* end; int type;
mazgch 21:c4d64830bf02 1375 } lut[] = {
mazgch 21:c4d64830bf02 1376 { "\r\nOK\r\n", NULL, TYPE_OK },
mazgch 21:c4d64830bf02 1377 { "\r\nERROR\r\n", NULL, TYPE_ERROR },
mazgch 31:a0bed6c1e05d 1378 { "\r\n+CME ERROR:", "\r\n", TYPE_ERROR },
mazgch 21:c4d64830bf02 1379 { "\r\n+CMS ERROR:", "\r\n", TYPE_ERROR },
mazgch 21:c4d64830bf02 1380 { "\r\nRING\r\n", NULL, TYPE_RING },
mazgch 21:c4d64830bf02 1381 { "\r\nCONNECT\r\n", NULL, TYPE_CONNECT },
mazgch 21:c4d64830bf02 1382 { "\r\nNO CARRIER\r\n", NULL, TYPE_NOCARRIER },
mazgch 21:c4d64830bf02 1383 { "\r\nNO DIALTONE\r\n", NULL, TYPE_NODIALTONE },
mazgch 21:c4d64830bf02 1384 { "\r\nBUSY\r\n", NULL, TYPE_BUSY },
mazgch 21:c4d64830bf02 1385 { "\r\nNO ANSWER\r\n", NULL, TYPE_NOANSWER },
mazgch 21:c4d64830bf02 1386 { "\r\n+", "\r\n", TYPE_PLUS },
mazgch 21:c4d64830bf02 1387 { "\r\n@", NULL, TYPE_PROMPT }, // Sockets
mazgch 21:c4d64830bf02 1388 { "\r\n>", NULL, TYPE_PROMPT }, // SMS
mazgch 80:34985b4d821e 1389 { "\n>", NULL, TYPE_PROMPT }, // File
mazgch 21:c4d64830bf02 1390 };
mazgch 21:c4d64830bf02 1391 for (int i = 0; i < sizeof(lutF)/sizeof(*lutF); i ++) {
mazgch 21:c4d64830bf02 1392 pipe->set(unkn);
mazgch 21:c4d64830bf02 1393 int ln = _parseFormated(pipe, len, lutF[i].fmt);
mazgch 21:c4d64830bf02 1394 if (ln == WAIT && fr)
mazgch 21:c4d64830bf02 1395 return WAIT;
mazgch 21:c4d64830bf02 1396 if ((ln != NOT_FOUND) && (unkn > 0))
mazgch 31:a0bed6c1e05d 1397 return TYPE_UNKNOWN | pipe->get(buf, unkn);
mazgch 21:c4d64830bf02 1398 if (ln > 0)
mazgch 21:c4d64830bf02 1399 return lutF[i].type | pipe->get(buf, ln);
mazgch 21:c4d64830bf02 1400 }
mazgch 21:c4d64830bf02 1401 for (int i = 0; i < sizeof(lut)/sizeof(*lut); i ++) {
mazgch 21:c4d64830bf02 1402 pipe->set(unkn);
mazgch 21:c4d64830bf02 1403 int ln = _parseMatch(pipe, len, lut[i].sta, lut[i].end);
mazgch 21:c4d64830bf02 1404 if (ln == WAIT && fr)
mazgch 21:c4d64830bf02 1405 return WAIT;
mazgch 21:c4d64830bf02 1406 if ((ln != NOT_FOUND) && (unkn > 0))
mazgch 31:a0bed6c1e05d 1407 return TYPE_UNKNOWN | pipe->get(buf, unkn);
mazgch 21:c4d64830bf02 1408 if (ln > 0)
mazgch 21:c4d64830bf02 1409 return lut[i].type | pipe->get(buf, ln);
mazgch 21:c4d64830bf02 1410 }
mazgch 21:c4d64830bf02 1411 // UNKNOWN
mazgch 21:c4d64830bf02 1412 unkn ++;
mazgch 21:c4d64830bf02 1413 len--;
mazgch 21:c4d64830bf02 1414 }
mazgch 18:e5697801df29 1415 return WAIT;
mazgch 18:e5697801df29 1416 }
mazgch 18:e5697801df29 1417
mazgch 18:e5697801df29 1418 // ----------------------------------------------------------------
mazgch 18:e5697801df29 1419 // Serial Implementation
mazgch 18:e5697801df29 1420 // ----------------------------------------------------------------
mazgch 18:e5697801df29 1421
mazgch 76:f7c3dd568dae 1422 /*! Helper Dev Null Device
mazgch 76:f7c3dd568dae 1423 Small helper class used to shut off stderr/stdout. Sometimes stdin/stdout
mazgch 76:f7c3dd568dae 1424 is shared with the serial port of the modem. Having printfs inbetween the
mazgch 76:f7c3dd568dae 1425 AT commands you cause a failure of the modem.
mazgch 76:f7c3dd568dae 1426 */
mazgch 76:f7c3dd568dae 1427 class DevNull : public Stream {
mazgch 76:f7c3dd568dae 1428 public:
mazgch 76:f7c3dd568dae 1429 DevNull() : Stream(_name+1) { } //!< Constructor
mazgch 76:f7c3dd568dae 1430 void claim(const char* mode, FILE* file)
mazgch 76:f7c3dd568dae 1431 { freopen(_name, mode, file); } //!< claim a stream
mazgch 76:f7c3dd568dae 1432 protected:
mazgch 76:f7c3dd568dae 1433 virtual int _getc() { return EOF; } //!< Nothing
mazgch 76:f7c3dd568dae 1434 virtual int _putc(int c) { return c; } //!< Discard
mazgch 76:f7c3dd568dae 1435 static const char* _name; //!< File name
mazgch 76:f7c3dd568dae 1436 };
mazgch 76:f7c3dd568dae 1437 const char* DevNull::_name = "/null"; //!< the null device name
mazgch 76:f7c3dd568dae 1438 static DevNull null; //!< the null device
mazgch 76:f7c3dd568dae 1439
mazgch 19:2b5d097ca15d 1440 MDMSerial::MDMSerial(PinName tx /*= MDMTXD*/, PinName rx /*= MDMRXD*/,
mazgch 19:2b5d097ca15d 1441 int baudrate /*= MDMBAUD*/,
mazgch 43:a89a7a505991 1442 #if DEVICE_SERIAL_FC
mazgch 19:2b5d097ca15d 1443 PinName rts /*= MDMRTS*/, PinName cts /*= MDMCTS*/,
mazgch 43:a89a7a505991 1444 #endif
mazgch 18:e5697801df29 1445 int rxSize /*= 256*/, int txSize /*= 128*/) :
mazgch 35:9275215a3a5b 1446 SerialPipe(tx, rx, rxSize, txSize)
mazgch 18:e5697801df29 1447 {
mazgch 76:f7c3dd568dae 1448 if (rx == USBRX)
mazgch 76:f7c3dd568dae 1449 null.claim("r", stdin);
mazgch 76:f7c3dd568dae 1450 if (tx == USBTX) {
mazgch 76:f7c3dd568dae 1451 null.claim("w", stdout);
mazgch 76:f7c3dd568dae 1452 null.claim("w", stderr);
mazgch 74:208e3e32d263 1453 #ifdef MDM_DEBUG
mazgch 76:f7c3dd568dae 1454 _debugLevel = -1;
mazgch 76:f7c3dd568dae 1455 #endif
mazgch 76:f7c3dd568dae 1456 }
mazgch 74:208e3e32d263 1457 #ifdef TARGET_UBLOX_C027
mazgch 74:208e3e32d263 1458 _onboard = (tx == MDMTXD) && (rx == MDMRXD);
mazgch 74:208e3e32d263 1459 if (_onboard)
mazgch 74:208e3e32d263 1460 c027_mdm_powerOn(false);
mazgch 74:208e3e32d263 1461 #endif
mazgch 18:e5697801df29 1462 baud(baudrate);
mazgch 35:9275215a3a5b 1463 #if DEVICE_SERIAL_FC
mazgch 35:9275215a3a5b 1464 if ((rts != NC) || (cts != NC))
mazgch 35:9275215a3a5b 1465 {
mazgch 35:9275215a3a5b 1466 Flow flow = (cts == NC) ? RTS :
mazgch 35:9275215a3a5b 1467 (rts == NC) ? CTS : RTSCTS ;
mazgch 35:9275215a3a5b 1468 set_flow_control(flow, rts, cts);
mazgch 35:9275215a3a5b 1469 if (cts != NC) _dev.lpm = LPM_ENABLED;
mazgch 35:9275215a3a5b 1470 }
mazgch 35:9275215a3a5b 1471 #endif
mazgch 18:e5697801df29 1472 }
mazgch 18:e5697801df29 1473
mazgch 76:f7c3dd568dae 1474 MDMSerial::~MDMSerial(void)
mazgch 76:f7c3dd568dae 1475 {
mazgch 76:f7c3dd568dae 1476 powerOff();
mazgch 76:f7c3dd568dae 1477 #ifdef TARGET_UBLOX_C027
mazgch 76:f7c3dd568dae 1478 if (_onboard)
mazgch 76:f7c3dd568dae 1479 c027_mdm_powerOff();
mazgch 76:f7c3dd568dae 1480 #endif
mazgch 76:f7c3dd568dae 1481 }
mazgch 76:f7c3dd568dae 1482
mazgch 18:e5697801df29 1483 int MDMSerial::_send(const void* buf, int len)
mazgch 18:e5697801df29 1484 {
mazgch 35:9275215a3a5b 1485 return put((const char*)buf, len, true/*=blocking*/);
mazgch 18:e5697801df29 1486 }
mazgch 18:e5697801df29 1487
mazgch 18:e5697801df29 1488 int MDMSerial::getLine(char* buffer, int length)
mazgch 18:e5697801df29 1489 {
mazgch 18:e5697801df29 1490 return _getLine(&_pipeRx, buffer, length);
mazgch 18:e5697801df29 1491 }
mazgch 18:e5697801df29 1492
mazgch 18:e5697801df29 1493 // ----------------------------------------------------------------
mazgch 18:e5697801df29 1494 // USB Implementation
mazgch 18:e5697801df29 1495 // ----------------------------------------------------------------
mazgch 18:e5697801df29 1496
mazgch 18:e5697801df29 1497 #ifdef HAVE_MDMUSB
mazgch 76:f7c3dd568dae 1498 MDMUsb::MDMUsb(void)
mazgch 74:208e3e32d263 1499 {
mazgch 74:208e3e32d263 1500 #ifdef MDM_DEBUG
mazgch 74:208e3e32d263 1501 _debugLevel = 1;
mazgch 74:208e3e32d263 1502 #endif
mazgch 74:208e3e32d263 1503 #ifdef TARGET_UBLOX_C027
mazgch 74:208e3e32d263 1504 _onboard = true;
mazgch 74:208e3e32d263 1505 c027_mdm_powerOn(true);
mazgch 74:208e3e32d263 1506 #endif
mazgch 74:208e3e32d263 1507 }
mazgch 76:f7c3dd568dae 1508
mazgch 76:f7c3dd568dae 1509 MDMUsb::~MDMUsb(void)
mazgch 76:f7c3dd568dae 1510 {
mazgch 76:f7c3dd568dae 1511 powerOff();
mazgch 76:f7c3dd568dae 1512 #ifdef TARGET_UBLOX_C027
mazgch 76:f7c3dd568dae 1513 if (_onboard)
mazgch 76:f7c3dd568dae 1514 c027_mdm_powerOff();
mazgch 76:f7c3dd568dae 1515 #endif
mazgch 76:f7c3dd568dae 1516 }
mazgch 76:f7c3dd568dae 1517
mazgch 76:f7c3dd568dae 1518 int MDMUsb::_send(const void* buf, int len) { return 0; }
mazgch 76:f7c3dd568dae 1519
mazgch 18:e5697801df29 1520 int MDMUsb::getLine(char* buffer, int length) { return NOT_FOUND; }
mazgch 76:f7c3dd568dae 1521
mazgch 35:9275215a3a5b 1522 #endif