Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of C027_Support by
MDM.cpp
00001 #include "mbed.h" 00002 #include "MDM.h" 00003 #ifdef TARGET_UBLOX_C027 00004 #include "C027_api.h" 00005 #endif 00006 #include "MDMAPN.h" 00007 00008 #define PROFILE "0" //!< this is the psd profile used 00009 #define MAX_SIZE 128 //!< max expected messages 00010 // num sockets 00011 #define NUMSOCKETS (sizeof(_sockets)/sizeof(*_sockets)) 00012 //! test if it is a socket is ok to use 00013 #define ISSOCKET(s) (((s) >= 0) && ((s) < NUMSOCKETS) && (_sockets[s].handle != SOCKET_ERROR)) 00014 //! check for timeout 00015 #define TIMEOUT(t, ms) ((ms != TIMEOUT_BLOCKING) && (ms < t.read_ms())) 00016 //! registration ok check helper 00017 #define REG_OK(r) ((r == REG_HOME) || (r == REG_ROAMING)) 00018 //! registration done check helper (no need to poll further) 00019 #define REG_DONE(r) ((r == REG_HOME) || (r == REG_ROAMING) || (r == REG_DENIED)) 00020 //! helper to make sure that lock unlock pair is always balaced 00021 #define LOCK() { lock() 00022 //! helper to make sure that lock unlock pair is always balaced 00023 #define UNLOCK() } unlock() 00024 00025 #ifdef MDM_DEBUG 00026 #if 1 // colored terminal output using ANSI escape sequences 00027 #define COL(c) "\033[" c 00028 #else 00029 #define COL(c) 00030 #endif 00031 #define DEF COL("39m") 00032 #define BLA COL("30m") 00033 #define RED COL("31m") 00034 #define GRE COL("32m") 00035 #define YEL COL("33m") 00036 #define BLU COL("34m") 00037 #define MAG COL("35m") 00038 #define CYA COL("36m") 00039 #define WHY COL("37m") 00040 00041 void dumpAtCmd(const char* buf, int len) 00042 { 00043 ::printf(" %3d \"", len); 00044 while (len --) { 00045 char ch = *buf++; 00046 if ((ch > 0x1F) && (ch != 0x7F)) { // is printable 00047 if (ch == '%') ::printf("%%"); 00048 else if (ch == '"') ::printf("\\\""); 00049 else if (ch == '\\') ::printf("\\\\"); 00050 else putchar(ch); 00051 } else { 00052 if (ch == '\a') ::printf("\\a"); // BEL (0x07) 00053 else if (ch == '\b') ::printf("\\b"); // Backspace (0x08) 00054 else if (ch == '\t') ::printf("\\t"); // Horizontal Tab (0x09) 00055 else if (ch == '\n') ::printf("\\n"); // Linefeed (0x0A) 00056 else if (ch == '\v') ::printf("\\v"); // Vertical Tab (0x0B) 00057 else if (ch == '\f') ::printf("\\f"); // Formfeed (0x0C) 00058 else if (ch == '\r') ::printf("\\r"); // Carriage Return (0x0D) 00059 else ::printf("\\x%02x", (unsigned char)ch); 00060 } 00061 } 00062 ::printf("\"\r\n"); 00063 } 00064 00065 void MDMParser::_debugPrint(int level, const char* color, const char* format, ...) 00066 { 00067 if (_debugLevel >= level) 00068 { 00069 va_list args; 00070 va_start (args, format); 00071 if (color) ::printf(color); 00072 ::vprintf(format, args); 00073 if (color) ::printf(DEF); 00074 va_end (args); 00075 } 00076 } 00077 00078 #define ERROR(...) _debugPrint(0, RED, __VA_ARGS__) 00079 #define INFO(...) _debugPrint(1, GRE, __VA_ARGS__) 00080 #define TRACE(...) _debugPrint(2, DEF, __VA_ARGS__) 00081 #define TEST(...) _debugPrint(3, CYA, __VA_ARGS__) 00082 00083 #else 00084 00085 #define ERROR(...) (void)0 // no tracing 00086 #define TEST(...) (void)0 // no tracing 00087 #define INFO(...) (void)0 // no tracing 00088 #define TRACE(...) (void)0 // no tracing 00089 00090 #endif 00091 00092 MDMParser* MDMParser::inst; 00093 00094 MDMParser::MDMParser(void) 00095 { 00096 inst = this; 00097 memset(&_dev, 0, sizeof(_dev)); 00098 memset(&_net, 0, sizeof(_net)); 00099 _net.lac = 0xFFFF; 00100 _net.ci = 0xFFFFFFFF; 00101 _ip = NOIP; 00102 _init = false; 00103 memset(_sockets, 0, sizeof(_sockets)); 00104 for (int socket = 0; socket < NUMSOCKETS; socket ++) 00105 _sockets[socket].handle = SOCKET_ERROR; 00106 #ifdef MDM_DEBUG 00107 _debugLevel = 1; 00108 _debugTime.start(); 00109 #endif 00110 } 00111 00112 int MDMParser::send(const char* buf, int len) 00113 { 00114 #ifdef MDM_DEBUG 00115 if (_debugLevel >= 3) { 00116 ::printf("%10.3f AT send ", _debugTime.read_ms()*0.001); 00117 dumpAtCmd(buf,len); 00118 } 00119 #endif 00120 return _send(buf, len); 00121 } 00122 00123 int MDMParser::sendFormated(const char* format, ...) { 00124 char buf[MAX_SIZE]; 00125 va_list args; 00126 va_start(args, format); 00127 int len = vsnprintf(buf,sizeof(buf), format, args); 00128 va_end(args); 00129 return send(buf, len); 00130 } 00131 00132 int MDMParser::waitFinalResp(_CALLBACKPTR cb /* = NULL*/, 00133 void* param /* = NULL*/, 00134 int timeout_ms /*= 5000*/) 00135 { 00136 char buf[MAX_SIZE + 64 /* add some more space for framing */]; 00137 Timer timer; 00138 timer.start(); 00139 do { 00140 int ret = getLine(buf, sizeof(buf)); 00141 #ifdef MDM_DEBUG 00142 if ((_debugLevel >= 3) && (ret != WAIT) && (ret != NOT_FOUND)) 00143 { 00144 int len = LENGTH(ret); 00145 int type = TYPE(ret); 00146 const char* s = (type == TYPE_UNKNOWN)? YEL "UNK" DEF : 00147 (type == TYPE_TEXT) ? MAG "TXT" DEF : 00148 (type == TYPE_OK ) ? GRE "OK " DEF : 00149 (type == TYPE_ERROR) ? RED "ERR" DEF : 00150 (type == TYPE_PLUS) ? CYA " + " DEF : 00151 (type == TYPE_PROMPT) ? BLU " > " DEF : 00152 "..." ; 00153 ::printf("%10.3f AT read %s", _debugTime.read_ms()*0.001, s); 00154 dumpAtCmd(buf, len); 00155 } 00156 #endif 00157 if ((ret != WAIT) && (ret != NOT_FOUND)) 00158 { 00159 int type = TYPE(ret); 00160 // handle unsolicited commands here 00161 if (type == TYPE_PLUS) { 00162 const char* cmd = buf+3; 00163 int a, b, c, d, r; 00164 char s[32]; 00165 00166 // SMS Command --------------------------------- 00167 // +CNMI: <mem>,<index> 00168 if (sscanf(cmd, "CMTI: \"%*[^\"]\",%d", &a) == 1) { 00169 TRACE("New SMS at index %d\r\n", a); 00170 // Socket Specific Command --------------------------------- 00171 // +UUSORD: <socket>,<length> 00172 } else if ((sscanf(cmd, "UUSORD: %d,%d", &a, &b) == 2)) { 00173 int socket = _findSocket(a); 00174 TRACE("Socket %d: handle %d has %d bytes pending\r\n", socket, a, b); 00175 if (socket != SOCKET_ERROR) 00176 _sockets[socket].pending = b; 00177 // +UUSORF: <socket>,<length> 00178 } else if ((sscanf(cmd, "UUSORF: %d,%d", &a, &b) == 2)) { 00179 int socket = _findSocket(a); 00180 TRACE("Socket %d: handle %d has %d bytes pending\r\n", socket, a, b); 00181 if (socket != SOCKET_ERROR) 00182 _sockets[socket].pending = b; 00183 // +UUSOCL: <socket> 00184 } else if ((sscanf(cmd, "UUSOCL: %d", &a) == 1)) { 00185 int socket = _findSocket(a); 00186 TRACE("Socket %d: handle %d closed by remote host\r\n", socket, a); 00187 if ((socket != SOCKET_ERROR) && _sockets[socket].connected) 00188 _sockets[socket].connected = false; 00189 } 00190 if (_dev.dev == DEV_LISA_C2) { 00191 // CDMA Specific ------------------------------------------- 00192 // +CREG: <n><SID>,<NID>,<stat> 00193 if (sscanf(cmd, "CREG: %*d,%d,%d,%d",&a,&b,&c) == 3) { 00194 // _net.sid = a; 00195 // _net.nid = b; 00196 if (c == 0) _net.csd = REG_NONE; // not registered, home network 00197 else if (c == 1) _net.csd = REG_HOME; // registered, home network 00198 else if (c == 2) _net.csd = REG_NONE; // not registered, but MT is currently searching a new operator to register to 00199 else if (c == 3) _net.csd = REG_DENIED; // registration denied 00200 else if (c == 5) _net.csd = REG_ROAMING; // registered, roaming 00201 _net.psd = _net.csd; // fake PSD registration (CDMA is always registered) 00202 _net.act = ACT_CDMA; 00203 // +CSS: <mode>[,<format>,<oper>[,<AcT>]] 00204 } else if (sscanf(cmd, "CSS %*c,%2s,%*d",s) == 1) { 00205 //_net.reg = (strcmp("Z", s) == 0) ? REG_UNKNOWN : REG_HOME; 00206 } 00207 } else { 00208 // GSM/UMTS Specific ------------------------------------------- 00209 // +UUPSDD: <profile_id> 00210 if (sscanf(cmd, "UUPSDD: %d",&a) == 1) { 00211 if (*PROFILE == a) _ip = NOIP; 00212 } else { 00213 // +CREG|CGREG: <n>,<stat>[,<lac>,<ci>[,AcT[,<rac>]]] // reply to AT+CREG|AT+CGREG 00214 // +CREG|CGREG: <stat>[,<lac>,<ci>[,AcT[,<rac>]]] // URC 00215 b = 0xFFFF; c = 0xFFFFFFFF; d = -1; 00216 r = sscanf(cmd, "%s %*d,%d,\"%X\",\"%X\",%d",s,&a,&b,&c,&d); 00217 if (r <= 1) 00218 r = sscanf(cmd, "%s %d,\"%X\",\"%X\",%d",s,&a,&b,&c,&d); 00219 if (r >= 2) { 00220 Reg *reg = !strcmp(s, "CREG:") ? &_net.csd : 00221 !strcmp(s, "CGREG:") ? &_net.psd : 00222 !strcmp(s, "CEREG:") ? &_net.eps : NULL; 00223 if (reg) { 00224 // network status 00225 if (a == 0) *reg = REG_NONE; // 0: not registered, home network 00226 else if (a == 1) *reg = REG_HOME; // 1: registered, home network 00227 else if (a == 2) *reg = REG_NONE; // 2: not registered, but MT is currently searching a new operator to register to 00228 else if (a == 3) *reg = REG_DENIED; // 3: registration denied 00229 else if (a == 4) *reg = REG_UNKNOWN; // 4: unknown 00230 else if (a == 5) *reg = REG_ROAMING; // 5: registered, roaming 00231 else if (a == 6) *reg = REG_HOME; // 6: registered, sms only, home 00232 if ((r >= 3) && (b != 0xFFFF)) _net.lac = b; // location area code 00233 if ((r >= 4) && (c != 0xFFFFFFFF)) _net.ci = c; // cell ID 00234 // access technology 00235 if (r >= 5) { 00236 if (d == 0) _net.act = ACT_GSM; // 0: GSM 00237 else if (d == 1) _net.act = ACT_GSM; // 1: GSM COMPACT 00238 else if (d == 2) _net.act = ACT_UTRAN; // 2: UTRAN 00239 else if (d == 3) _net.act = ACT_EDGE; // 3: GSM with EDGE availability 00240 else if (d == 4) _net.act = ACT_UTRAN; // 4: UTRAN with HSDPA availability 00241 else if (d == 5) _net.act = ACT_UTRAN; // 5: UTRAN with HSUPA availability 00242 else if (d == 6) _net.act = ACT_UTRAN; // 6: UTRAN with HSDPA and HSUPA availability 00243 else if (d == 7) _net.act = ACT_LTE; // 7: LTE 00244 } 00245 } 00246 } 00247 } 00248 } 00249 } 00250 if (cb) { 00251 int len = LENGTH(ret); 00252 int ret = cb(type, buf, len, param); 00253 if (WAIT != ret) 00254 return ret; 00255 } 00256 if (type == TYPE_OK) 00257 return RESP_OK; 00258 if (type == TYPE_ERROR) 00259 return RESP_ERROR; 00260 if (type == TYPE_PROMPT) 00261 return RESP_PROMPT; 00262 } 00263 // relax a bit 00264 wait_ms(10); 00265 } 00266 while (!TIMEOUT(timer, timeout_ms)); 00267 return WAIT; 00268 } 00269 00270 int MDMParser::_cbString(int type, const char* buf, int len, char* str) 00271 { 00272 if (str && (type == TYPE_UNKNOWN)) { 00273 if (sscanf(buf, "\r\n%s\r\n", str) == 1) 00274 /*nothing*/; 00275 } 00276 return WAIT; 00277 } 00278 00279 int MDMParser::_cbInt(int type, const char* buf, int len, int* val) 00280 { 00281 if (val && (type == TYPE_UNKNOWN)) { 00282 if (sscanf(buf, "\r\n%d\r\n", val) == 1) 00283 /*nothing*/; 00284 } 00285 return WAIT; 00286 } 00287 00288 // ---------------------------------------------------------------- 00289 00290 bool MDMParser::connect( 00291 const char* simpin, 00292 const char* apn, const char* username, 00293 const char* password, Auth auth, 00294 PinName pn) 00295 { 00296 bool ok = init(simpin, NULL, pn); 00297 #ifdef MDM_DEBUG 00298 if (_debugLevel >= 1) dumpDevStatus(&_dev); 00299 #endif 00300 if (!ok) 00301 return false; 00302 ok = registerNet(); 00303 #ifdef MDM_DEBUG 00304 if (_debugLevel >= 1) dumpNetStatus(&_net); 00305 #endif 00306 if (!ok) 00307 return false; 00308 IP ip = join(apn,username,password,auth); 00309 #ifdef MDM_DEBUG 00310 if (_debugLevel >= 1) dumpIp(ip); 00311 #endif 00312 if (ip == NOIP) 00313 return false; 00314 return true; 00315 } 00316 00317 bool MDMParser::init(const char* simpin, DevStatus* status, PinName pn) 00318 { 00319 int i = 10; 00320 LOCK(); 00321 memset(&_dev, 0, sizeof(_dev)); 00322 if (pn != NC) { 00323 INFO("Modem::wakeup\r\n"); 00324 DigitalOut pin(pn, 1); 00325 while (i--) { 00326 // SARA-U2/LISA-U2 50..80us 00327 pin = 0; ::wait_us(50); 00328 pin = 1; ::wait_ms(10); 00329 00330 // SARA-G35 >5ms, LISA-C2 > 150ms, LEON-G2 >5ms 00331 pin = 0; ::wait_ms(150); 00332 pin = 1; ::wait_ms(100); 00333 00334 // purge any messages 00335 purge(); 00336 00337 // check interface 00338 sendFormated("AT\r\n"); 00339 int r = waitFinalResp(NULL,NULL,1000); 00340 if(RESP_OK == r) break; 00341 } 00342 if (i < 0) { 00343 ERROR("No Reply from Modem\r\n"); 00344 goto failure; 00345 } 00346 } 00347 _init = true; 00348 00349 INFO("Modem::init\r\n"); 00350 // echo off 00351 sendFormated("AT E0\r\n"); 00352 if(RESP_OK != waitFinalResp()) 00353 goto failure; 00354 // enable verbose error messages 00355 sendFormated("AT+CMEE=2\r\n"); 00356 if(RESP_OK != waitFinalResp()) 00357 goto failure; 00358 // set baud rate 00359 sendFormated("AT+IPR=115200\r\n"); 00360 if (RESP_OK != waitFinalResp()) 00361 goto failure; 00362 // wait some time until baudrate is applied 00363 wait_ms(200); // SARA-G > 40ms 00364 // identify the module 00365 sendFormated("ATI\r\n"); 00366 if (RESP_OK != waitFinalResp(_cbATI, &_dev.dev)) 00367 goto failure; 00368 if (_dev.dev == DEV_UNKNOWN) 00369 goto failure; 00370 // device specific init 00371 if (_dev.dev == DEV_LISA_C2) { 00372 // get the manufacturer 00373 sendFormated("AT+GMI\r\n"); 00374 if (RESP_OK != waitFinalResp(_cbString, _dev.manu)) 00375 goto failure; 00376 // get the model identification 00377 sendFormated("AT+GMM\r\n"); 00378 if (RESP_OK != waitFinalResp(_cbString, _dev.model)) 00379 goto failure; 00380 // get the sw version 00381 sendFormated("AT+GMR\r\n"); 00382 if (RESP_OK != waitFinalResp(_cbString, _dev.ver)) 00383 goto failure; 00384 // get the pseudo ESN or MEID 00385 sendFormated("AT+GSN\r\n"); 00386 if (RESP_OK != waitFinalResp(_cbString, _dev.meid)) 00387 goto failure; 00388 #if 0 00389 // enable power saving 00390 if (_dev.lpm != LPM_DISABLED) { 00391 // enable power saving (requires flow control, cts at least) 00392 sendFormated("AT+UPSV=1,1280\r\n"); 00393 if (RESP_OK != waitFinalResp()) 00394 goto failure; 00395 _dev.lpm = LPM_ACTIVE; 00396 } 00397 #endif 00398 } else { 00399 if ((_dev.dev == DEV_LISA_U2) || (_dev.dev == DEV_LEON_G2) || 00400 (_dev.dev == DEV_TOBY_L2)) { 00401 // enable the network identification feature 00402 sendFormated("AT+UGPIOC=20,2\r\n"); 00403 if (RESP_OK != waitFinalResp()) 00404 goto failure; 00405 } else if ((_dev.dev == DEV_SARA_U2) || (_dev.dev == DEV_SARA_G35)) { 00406 // enable the network identification feature 00407 sendFormated("AT+UGPIOC=16,2\r\n"); 00408 if (RESP_OK != waitFinalResp()) 00409 goto failure; 00410 } 00411 // check the sim card 00412 for (int i = 0; (i < 5) && (_dev.sim != SIM_READY); i++) { 00413 sendFormated("AT+CPIN?\r\n"); 00414 int ret = waitFinalResp(_cbCPIN, &_dev.sim); 00415 // having an error here is ok (sim may still be initializing) 00416 if ((RESP_OK != ret) && (RESP_ERROR != ret)) 00417 goto failure; 00418 // Enter PIN if needed 00419 if (_dev.sim == SIM_PIN) { 00420 if (!simpin) { 00421 ERROR("SIM PIN not available\r\n"); 00422 goto failure; 00423 } 00424 sendFormated("AT+CPIN=%s\r\n", simpin); 00425 if (RESP_OK != waitFinalResp(_cbCPIN, &_dev.sim)) 00426 goto failure; 00427 } else if (_dev.sim != SIM_READY) { 00428 wait_ms(1000); 00429 } 00430 } 00431 if (_dev.sim != SIM_READY) { 00432 if (_dev.sim == SIM_MISSING) 00433 ERROR("SIM not inserted\r\n"); 00434 goto failure; 00435 } 00436 // get the manufacturer 00437 sendFormated("AT+CGMI\r\n"); 00438 if (RESP_OK != waitFinalResp(_cbString, _dev.manu)) 00439 goto failure; 00440 // get the model identification 00441 sendFormated("AT+CGMM\r\n"); 00442 if (RESP_OK != waitFinalResp(_cbString, _dev.model)) 00443 goto failure; 00444 // get the version 00445 sendFormated("ATI9\r\n"); 00446 if (RESP_OK != waitFinalResp(_cbString, _dev.ver)) 00447 goto failure; 00448 // Returns the ICCID (Integrated Circuit Card ID) of the SIM-card. 00449 // ICCID is a serial number identifying the SIM. 00450 sendFormated("AT+CCID\r\n"); 00451 if (RESP_OK != waitFinalResp(_cbCCID, _dev.ccid)) 00452 goto failure; 00453 // Returns the product serial number, IMEI (International Mobile Equipment Identity) 00454 sendFormated("AT+CGSN\r\n"); 00455 if (RESP_OK != waitFinalResp(_cbString, _dev.imei)) 00456 goto failure; 00457 // enable power saving 00458 if (_dev.lpm != LPM_DISABLED) { 00459 // enable power saving (requires flow control, cts at least) 00460 sendFormated("AT+UPSV=1\r\n"); 00461 if (RESP_OK != waitFinalResp()) 00462 goto failure; 00463 _dev.lpm = LPM_ACTIVE; 00464 } 00465 // enable the psd registration unsolicited result code 00466 sendFormated("AT+CGREG=2\r\n"); 00467 if (RESP_OK != waitFinalResp()) 00468 goto failure; 00469 } 00470 // enable the network registration unsolicited result code 00471 sendFormated("AT+CREG=%d\r\n", (_dev.dev == DEV_LISA_C2) ? 1 : 2); 00472 if (RESP_OK != waitFinalResp()) 00473 goto failure; 00474 // Setup SMS in text mode 00475 sendFormated("AT+CMGF=1\r\n"); 00476 if (RESP_OK != waitFinalResp()) 00477 goto failure; 00478 // setup new message indication 00479 sendFormated("AT+CNMI=2,1\r\n"); 00480 if (RESP_OK != waitFinalResp()) 00481 goto failure; 00482 // Request IMSI (International Mobile Subscriber Identification) 00483 sendFormated("AT+CIMI\r\n"); 00484 if (RESP_OK != waitFinalResp(_cbString, _dev.imsi)) 00485 goto failure; 00486 if (status) 00487 memcpy(status, &_dev, sizeof(DevStatus)); 00488 UNLOCK(); 00489 return true; 00490 failure: 00491 unlock(); 00492 return false; 00493 } 00494 00495 bool MDMParser::powerOff(void) 00496 { 00497 bool ok = false; 00498 if (_init) { 00499 LOCK(); 00500 INFO("Modem::powerOff\r\n"); 00501 sendFormated("AT+CPWROFF\r\n"); 00502 if (RESP_OK == waitFinalResp(NULL,NULL,120*1000)) { 00503 _init = false; 00504 ok = true; 00505 } 00506 UNLOCK(); 00507 } 00508 return ok; 00509 } 00510 00511 int MDMParser::_cbATI(int type, const char* buf, int len, Dev* dev) 00512 { 00513 if ((type == TYPE_UNKNOWN) && dev) { 00514 if (strstr(buf, "SARA-G35")) *dev = DEV_SARA_G35; 00515 else if (strstr(buf, "LISA-U2")) *dev = DEV_LISA_U2; 00516 else if (strstr(buf, "LISA-C2")) *dev = DEV_LISA_C2; 00517 else if (strstr(buf, "SARA-U2")) *dev = DEV_SARA_U2; 00518 else if (strstr(buf, "LEON-G2")) *dev = DEV_LEON_G2; 00519 else if (strstr(buf, "TOBY-L2")) *dev = DEV_TOBY_L2; 00520 else if (strstr(buf, "MPCI-L2")) *dev = DEV_MPCI_L2; 00521 } 00522 return WAIT; 00523 } 00524 00525 int MDMParser::_cbCPIN(int type, const char* buf, int len, Sim* sim) 00526 { 00527 if (sim) { 00528 if (type == TYPE_PLUS){ 00529 char s[16]; 00530 if (sscanf(buf, "\r\n+CPIN: %[^\r]\r\n", s) >= 1) 00531 *sim = (0 == strcmp("READY", s)) ? SIM_READY : SIM_PIN; 00532 } else if (type == TYPE_ERROR) { 00533 if (strstr(buf, "+CME ERROR: SIM not inserted")) 00534 *sim = SIM_MISSING; 00535 } 00536 } 00537 return WAIT; 00538 } 00539 00540 int MDMParser::_cbCCID(int type, const char* buf, int len, char* ccid) 00541 { 00542 if ((type == TYPE_PLUS) && ccid){ 00543 if (sscanf(buf, "\r\n+CCID: %[^\r]\r\n", ccid) == 1) 00544 /*TRACE("Got CCID: %s\r\n", ccid)*/; 00545 } 00546 return WAIT; 00547 } 00548 00549 bool MDMParser::registerNet(NetStatus* status /*= NULL*/, int timeout_ms /*= 180000*/) 00550 { 00551 Timer timer; 00552 timer.start(); 00553 INFO("Modem::register\r\n"); 00554 while (!checkNetStatus(status) && !TIMEOUT(timer, timeout_ms)) 00555 wait_ms(1000); 00556 if (_net.csd == REG_DENIED) ERROR("CSD Registration Denied\r\n"); 00557 if (_net.psd == REG_DENIED) ERROR("PSD Registration Denied\r\n"); 00558 if (_net.eps == REG_DENIED) ERROR("EPS Registration Denied\r\n"); 00559 return REG_OK(_net.csd) || REG_OK(_net.psd) || REG_OK(_net.eps); 00560 } 00561 00562 bool MDMParser::checkNetStatus(NetStatus* status /*= NULL*/) 00563 { 00564 bool ok = false; 00565 LOCK(); 00566 memset(&_net, 0, sizeof(_net)); 00567 _net.lac = 0xFFFF; 00568 _net.ci = 0xFFFFFFFF; 00569 // check registration 00570 sendFormated("AT+CREG?\r\n"); 00571 waitFinalResp(); // don't fail as service could be not subscribed 00572 if (_dev.dev != DEV_LISA_C2) { 00573 // check PSD registration 00574 sendFormated("AT+CGREG?\r\n"); 00575 waitFinalResp(); // don't fail as service could be not subscribed 00576 if ((_dev.dev == DEV_TOBY_L2) || (_dev.dev == DEV_MPCI_L2)) { 00577 // check EPS network registration 00578 sendFormated("AT+CEREG?\r\n"); 00579 waitFinalResp(); // don't fail as service could be not subscribed 00580 } 00581 } 00582 if (REG_OK(_net.csd) || REG_OK(_net.psd) || REG_OK(_net.eps)) 00583 { 00584 // check modem specific status messages 00585 if (_dev.dev == DEV_LISA_C2) { 00586 sendFormated("AT+CSS?\r\n"); 00587 if (RESP_OK != waitFinalResp()) 00588 goto failure; 00589 while (1) { 00590 // get the Telephone number 00591 sendFormated("AT$MDN?\r\n"); 00592 if (RESP_OK != waitFinalResp(_cbString, _net.num)) 00593 goto failure; 00594 // check if we have a Mobile Directory Number 00595 if (*_net.num && (memcmp(_net.num, "000000", 6) != 0)) 00596 break; 00597 00598 INFO("Device not yet activated\r\n"); 00599 INFO("Make sure you have a valid contract with the network operator for this device.\r\n"); 00600 // Check if the the version contains a V for Verizon 00601 // Verizon: E0.V.xx.00.xxR, 00602 // Sprint E0.S.xx.00.xxR 00603 if (_dev.ver[3] == 'V') { 00604 int i; 00605 INFO("Start device over-the-air activation (this can take a few minutes)\r\n"); 00606 sendFormated("AT+CDV=*22899\r\n"); 00607 i = 1; 00608 if ((RESP_OK != waitFinalResp(_cbUACTIND, &i, 120*1000)) || (i == 1)) { 00609 ERROR("Device over-the-air activation failed\r\n"); 00610 goto failure; 00611 } 00612 INFO("Device over-the-air activation successful\r\n"); 00613 00614 INFO("Start PRL over-the-air update (this can take a few minutes)\r\n"); 00615 sendFormated("AT+CDV=*22891\r\n"); 00616 i = 1; 00617 if ((RESP_OK != waitFinalResp(_cbUACTIND, &i, 120*1000)) || (i == 1)) { 00618 ERROR("PRL over-the-air update failed\r\n"); 00619 goto failure; 00620 } 00621 INFO("PRL over-the-air update successful\r\n"); 00622 00623 } else { 00624 // Sprint or Aeris 00625 INFO("Wait for OMA-DM over-the-air activation (this can take a few minutes)\r\n"); 00626 wait_ms(120*1000); 00627 } 00628 } 00629 // get the the Network access identifier string 00630 char nai[64]; 00631 sendFormated("AT$QCMIPNAI?\r\n"); 00632 if (RESP_OK != waitFinalResp(_cbString, nai)) 00633 goto failure; 00634 } else { 00635 sendFormated("AT+COPS?\r\n"); 00636 if (RESP_OK != waitFinalResp(_cbCOPS, &_net)) 00637 goto failure; 00638 // get the MSISDNs related to this subscriber 00639 sendFormated("AT+CNUM\r\n"); 00640 if (RESP_OK != waitFinalResp(_cbCNUM, _net.num)) 00641 goto failure; 00642 } 00643 // get the signal strength indication 00644 sendFormated("AT+CSQ\r\n"); 00645 if (RESP_OK != waitFinalResp(_cbCSQ, &_net)) 00646 goto failure; 00647 } 00648 if (status) { 00649 memcpy(status, &_net, sizeof(NetStatus)); 00650 } 00651 ok = REG_DONE(_net.csd) && 00652 (REG_DONE(_net.psd) || REG_DONE(_net.eps)); 00653 UNLOCK(); 00654 return ok; 00655 failure: 00656 unlock(); 00657 return false; 00658 } 00659 00660 int MDMParser::_cbCOPS(int type, const char* buf, int len, NetStatus* status) 00661 { 00662 if ((type == TYPE_PLUS) && status){ 00663 int act = 99; 00664 // +COPS: <mode>[,<format>,<oper>[,<AcT>]] 00665 if (sscanf(buf, "\r\n+COPS: %*d,%*d,\"%[^\"]\",%d",status->opr,&act) >= 1) { 00666 if (act == 0) status->act = ACT_GSM; // 0: GSM, 00667 else if (act == 2) status->act = ACT_UTRAN; // 2: UTRAN 00668 else if (act == 7) status->act = ACT_LTE; // 2: UTRAN 00669 } 00670 } 00671 return WAIT; 00672 } 00673 00674 int MDMParser::_cbCNUM(int type, const char* buf, int len, char* num) 00675 { 00676 if ((type == TYPE_PLUS) && num){ 00677 int a; 00678 if ((sscanf(buf, "\r\n+CNUM: \"My Number\",\"%31[^\"]\",%d", num, &a) == 2) && 00679 ((a == 129) || (a == 145))) { 00680 } 00681 } 00682 return WAIT; 00683 } 00684 00685 int MDMParser::_cbCSQ(int type, const char* buf, int len, NetStatus* status) 00686 { 00687 if ((type == TYPE_PLUS) && status){ 00688 int a,b; 00689 char _ber[] = { 49, 43, 37, 25, 19, 13, 7, 0 }; // see 3GPP TS 45.008 [20] subclause 8.2.4 00690 // +CSQ: <rssi>,<qual> 00691 if (sscanf(buf, "\r\n+CSQ: %d,%d",&a,&b) == 2) { 00692 if (a != 99) status->rssi = -113 + 2*a; // 0: -113 1: -111 ... 30: -53 dBm with 2 dBm steps, 31: >-51 dBm 00693 if ((b != 99) && (b < sizeof(_ber))) status->ber = _ber[b]; // 00694 } 00695 } 00696 return WAIT; 00697 } 00698 00699 00700 int MDMParser::_cbUACTIND(int type, const char* buf, int len, int* i) 00701 { 00702 if ((type == TYPE_PLUS) && i){ 00703 int a; 00704 if (sscanf(buf, "\r\n+UACTIND: %d", &a) == 1) { 00705 *i = a; 00706 } 00707 } 00708 return WAIT; 00709 } 00710 00711 // ---------------------------------------------------------------- 00712 // internet connection 00713 00714 bool MDMParser::_activateProfile(const char* apn, const char* username, const char* password, Auth auth) 00715 { 00716 // Set up the APN 00717 if (*apn) { 00718 sendFormated("AT+UPSD=" PROFILE ",1,\"%s\"\r\n", apn); 00719 if (RESP_OK != waitFinalResp()) 00720 return false; 00721 } 00722 if (*username) { 00723 sendFormated("AT+UPSD=" PROFILE ",2,\"%s\"\r\n", username); 00724 if (RESP_OK != waitFinalResp()) 00725 return false; 00726 } 00727 if (*password) { 00728 sendFormated("AT+UPSD=" PROFILE ",3,\"%s\"\r\n", password); 00729 if (RESP_OK != waitFinalResp()) 00730 return false; 00731 } 00732 // Set up the dynamic IP address assignment. 00733 sendFormated("AT+UPSD=" PROFILE ",7,\"0.0.0.0\"\r\n"); 00734 if (RESP_OK != waitFinalResp()) 00735 return false; 00736 // try different Authentication Protocols 00737 // 0 = none 00738 // 1 = PAP (Password Authentication Protocol) 00739 // 2 = CHAP (Challenge Handshake Authentication Protocol) 00740 for (int i = AUTH_NONE; i <= AUTH_CHAP; i ++) { 00741 if ((auth == AUTH_DETECT) || (auth == i)) { 00742 // Set up the Authentication Protocol 00743 sendFormated("AT+UPSD=" PROFILE ",6,%d\r\n",i); 00744 if (RESP_OK != waitFinalResp()) 00745 return false; 00746 // Activate the profile and make connection 00747 sendFormated("AT+UPSDA=" PROFILE ",3\r\n"); 00748 if (RESP_OK == waitFinalResp(NULL,NULL,150*1000)) 00749 return true; 00750 } 00751 } 00752 return false; 00753 } 00754 00755 bool MDMParser::_activateProfileByCid(int cid, const char* apn, const char* username, const char* password, Auth auth) 00756 { 00757 sendFormated("AT+CGDCONT=%d,\"IP\",\"%s\"\r\n", cid, apn); 00758 if (RESP_OK != waitFinalResp()) 00759 return false; 00760 sendFormated("AT+UAUTHREQ=%d,%d,\"%s\",\"%s\"\r\n", cid, auth, username, password); 00761 if (RESP_OK != waitFinalResp()) 00762 return false; 00763 sendFormated("AT+UPSD=" PROFILE ",100,%d\r\n", cid); 00764 if (RESP_OK != waitFinalResp()) 00765 return false; 00766 // Activate the profile and make connection 00767 sendFormated("AT+UPSDA=" PROFILE ",3\r\n"); 00768 return (RESP_OK == waitFinalResp(NULL,NULL,150*1000)); 00769 } 00770 00771 MDMParser::IP MDMParser::join(const char* apn /*= NULL*/, const char* username /*= NULL*/, 00772 const char* password /*= NULL*/, Auth auth /*= AUTH_DETECT*/) 00773 { 00774 LOCK(); 00775 INFO("Modem::join\r\n"); 00776 _ip = NOIP; 00777 if (_dev.dev == DEV_LISA_C2) { 00778 // make a dumy dns lookup (which will fail, so ignore the result) 00779 sendFormated("AT+UDNSRN=0,\"u-blox.com\"\r\n"); 00780 waitFinalResp(); 00781 // This fake lookup will enable the IP connection and we 00782 // should have an IP after this, so we check it 00783 00784 //Get local IP address 00785 sendFormated("AT+CMIP?\r\n"); 00786 if (RESP_OK != waitFinalResp(_cbCMIP, &_ip)) 00787 goto failure; 00788 00789 } else { 00790 // check gprs attach status 00791 sendFormated("AT+CGATT=1\r\n"); 00792 if (RESP_OK != waitFinalResp(NULL,NULL,3*60*1000)) 00793 goto failure; 00794 // Check the profile 00795 int a = 0; 00796 bool force = true; 00797 sendFormated("AT+UPSND=" PROFILE ",8\r\n"); 00798 if (RESP_OK != waitFinalResp(_cbUPSND, &a)) 00799 goto failure; 00800 if (a == 1 && force) { 00801 // disconnect the profile already if it is connected 00802 sendFormated("AT+UPSDA=" PROFILE ",4\r\n"); 00803 if (RESP_OK != waitFinalResp(NULL,NULL,40*1000)) 00804 goto failure; 00805 a = 0; 00806 } 00807 if (a == 0) { 00808 bool ok = false; 00809 // try to lookup the apn settings from our local database by mccmnc 00810 const char* config = NULL; 00811 if (!apn && !username && !password) 00812 config = apnconfig(_dev.imsi); 00813 do { 00814 if (config) { 00815 apn = _APN_GET(config); 00816 username = _APN_GET(config); 00817 password = _APN_GET(config); 00818 } 00819 // convert pointer to empty strings 00820 apn = apn ? apn : ""; 00821 username = username ? username : ""; 00822 password = password ? password : ""; 00823 auth = (*username && *password) ? auth : AUTH_NONE; 00824 TRACE("Testing APN Settings(\"%s\",\"%s\",\"%s\",%d)\r\n", apn, username, password, auth); 00825 if ((_dev.dev != DEV_TOBY_L2) && (_dev.dev != DEV_MPCI_L2)) 00826 ok = _activateProfile(apn, username, password, auth); 00827 else 00828 ok = _activateProfileByCid(1, apn, username, password, auth); 00829 } while (!ok && config && *config); // maybe use next setting ? 00830 if (!ok) { 00831 ERROR("Your modem APN/password/username may be wrong\r\n"); 00832 goto failure; 00833 } 00834 } 00835 //Get local IP address 00836 sendFormated("AT+UPSND=" PROFILE ",0\r\n"); 00837 if (RESP_OK != waitFinalResp(_cbUPSND, &_ip)) 00838 goto failure; 00839 } 00840 UNLOCK(); 00841 return _ip; 00842 failure: 00843 unlock(); 00844 return NOIP; 00845 } 00846 00847 int MDMParser::_cbUDOPN(int type, const char* buf, int len, char* mccmnc) 00848 { 00849 if ((type == TYPE_PLUS) && mccmnc) { 00850 if (sscanf(buf, "\r\n+UDOPN: 0,\"%[^\"]\"", mccmnc) == 1) 00851 ; 00852 } 00853 return WAIT; 00854 } 00855 00856 int MDMParser::_cbCMIP(int type, const char* buf, int len, IP* ip) 00857 { 00858 if ((type == TYPE_UNKNOWN) && ip) { 00859 int a,b,c,d; 00860 if (sscanf(buf, "\r\n" IPSTR, &a,&b,&c,&d) == 4) 00861 *ip = IPADR(a,b,c,d); 00862 } 00863 return WAIT; 00864 } 00865 00866 int MDMParser::_cbUPSND(int type, const char* buf, int len, int* act) 00867 { 00868 if ((type == TYPE_PLUS) && act) { 00869 if (sscanf(buf, "\r\n+UPSND: %*d,%*d,%d", act) == 1) 00870 /*nothing*/; 00871 } 00872 return WAIT; 00873 } 00874 00875 int MDMParser::_cbUPSND(int type, const char* buf, int len, IP* ip) 00876 { 00877 if ((type == TYPE_PLUS) && ip) { 00878 int a,b,c,d; 00879 // +UPSND=<profile_id>,<param_tag>[,<dynamic_param_val>] 00880 if (sscanf(buf, "\r\n+UPSND: " PROFILE ",0,\"" IPSTR "\"", &a,&b,&c,&d) == 4) 00881 *ip = IPADR(a,b,c,d); 00882 } 00883 return WAIT; 00884 } 00885 00886 int MDMParser::_cbUDNSRN(int type, const char* buf, int len, IP* ip) 00887 { 00888 if ((type == TYPE_PLUS) && ip) { 00889 int a,b,c,d; 00890 if (sscanf(buf, "\r\n+UDNSRN: \"" IPSTR "\"", &a,&b,&c,&d) == 4) 00891 *ip = IPADR(a,b,c,d); 00892 } 00893 return WAIT; 00894 } 00895 00896 bool MDMParser::disconnect(void) 00897 { 00898 bool ok = false; 00899 LOCK(); 00900 INFO("Modem::disconnect\r\n"); 00901 if (_ip != NOIP) { 00902 if (_dev.dev == DEV_LISA_C2) { 00903 // There something to do here 00904 _ip = NOIP; 00905 ok = true; 00906 } else { 00907 sendFormated("AT+UPSDA=" PROFILE ",4\r\n"); 00908 if (RESP_OK != waitFinalResp()) { 00909 _ip = NOIP; 00910 ok = true; 00911 } 00912 } 00913 } 00914 UNLOCK(); 00915 return ok; 00916 } 00917 00918 MDMParser::IP MDMParser::gethostbyname(const char* host) 00919 { 00920 IP ip = NOIP; 00921 int a,b,c,d; 00922 if (sscanf(host, IPSTR, &a,&b,&c,&d) == 4) 00923 ip = IPADR(a,b,c,d); 00924 else { 00925 LOCK(); 00926 sendFormated("AT+UDNSRN=0,\"%s\"\r\n", host); 00927 if (RESP_OK != waitFinalResp(_cbUDNSRN, &ip)) 00928 ip = NOIP; 00929 UNLOCK(); 00930 } 00931 return ip; 00932 } 00933 00934 // ---------------------------------------------------------------- 00935 // sockets 00936 00937 int MDMParser::_cbUSOCR(int type, const char* buf, int len, int* handle) 00938 { 00939 if ((type == TYPE_PLUS) && handle) { 00940 // +USOCR: socket 00941 if (sscanf(buf, "\r\n+USOCR: %d", handle) == 1) 00942 /*nothing*/; 00943 } 00944 return WAIT; 00945 } 00946 00947 int MDMParser::socketSocket(IpProtocol ipproto, int port) 00948 { 00949 int socket; 00950 LOCK(); 00951 // find an free socket 00952 socket = _findSocket(); 00953 TRACE("socketSocket(%d)\r\n", ipproto); 00954 if (socket != SOCKET_ERROR) { 00955 if (ipproto == IPPROTO_UDP) { 00956 // sending port can only be set on 2G/3G modules 00957 if ((port != -1) && (_dev.dev != DEV_LISA_C2)) { 00958 sendFormated("AT+USOCR=17,%d\r\n", port); 00959 } else { 00960 sendFormated("AT+USOCR=17\r\n"); 00961 } 00962 } else /*(ipproto == IPPROTO_TCP)*/ { 00963 sendFormated("AT+USOCR=6\r\n"); 00964 } 00965 int handle = SOCKET_ERROR; 00966 if ((RESP_OK == waitFinalResp(_cbUSOCR, &handle)) && 00967 (handle != SOCKET_ERROR)) { 00968 TRACE("Socket %d: handle %d was created\r\n", socket, handle); 00969 _sockets[socket].handle = handle; 00970 _sockets[socket].timeout_ms = TIMEOUT_BLOCKING; 00971 _sockets[socket].connected = false; 00972 _sockets[socket].pending = 0; 00973 } 00974 else 00975 socket = SOCKET_ERROR; 00976 } 00977 UNLOCK(); 00978 return socket; 00979 } 00980 00981 bool MDMParser::socketConnect(int socket, const char * host, int port) 00982 { 00983 IP ip = gethostbyname(host); 00984 if (ip == NOIP) 00985 return false; 00986 // connect to socket 00987 bool ok = false; 00988 LOCK(); 00989 if (ISSOCKET(socket) && (!_sockets[socket].connected)) { 00990 TRACE("socketConnect(%d,%s,%d)\r\n", socket,host,port); 00991 sendFormated("AT+USOCO=%d,\"" IPSTR "\",%d\r\n", _sockets[socket].handle, IPNUM(ip), port); 00992 if (RESP_OK == waitFinalResp()) 00993 ok = _sockets[socket].connected = true; 00994 } 00995 UNLOCK(); 00996 return ok; 00997 } 00998 00999 bool MDMParser::socketIsConnected(int socket) 01000 { 01001 bool ok = false; 01002 LOCK(); 01003 ok = ISSOCKET(socket) && _sockets[socket].connected; 01004 TRACE("socketIsConnected(%d) %s\r\n", socket, ok?"yes":"no"); 01005 UNLOCK(); 01006 return ok; 01007 } 01008 01009 bool MDMParser::socketSetBlocking(int socket, int timeout_ms) 01010 { 01011 bool ok = false; 01012 LOCK(); 01013 TRACE("socketSetBlocking(%d,%d)\r\n", socket,timeout_ms); 01014 if (ISSOCKET(socket)) { 01015 _sockets[socket].timeout_ms = timeout_ms; 01016 ok = true; 01017 } 01018 UNLOCK(); 01019 return ok; 01020 } 01021 01022 bool MDMParser::socketClose(int socket) 01023 { 01024 bool ok = false; 01025 LOCK(); 01026 if (ISSOCKET(socket) && _sockets[socket].connected) { 01027 TRACE("socketClose(%d)\r\n", socket); 01028 sendFormated("AT+USOCL=%d\r\n", _sockets[socket].handle); 01029 if (RESP_OK == waitFinalResp()) { 01030 _sockets[socket].connected = false; 01031 ok = true; 01032 } 01033 } 01034 UNLOCK(); 01035 return ok; 01036 } 01037 01038 bool MDMParser::socketFree(int socket) 01039 { 01040 // make sure it is closed 01041 socketClose(socket); 01042 bool ok = true; 01043 LOCK(); 01044 if (ISSOCKET(socket)) { 01045 TRACE("socketFree(%d)\r\n", socket); 01046 _sockets[socket].handle = SOCKET_ERROR; 01047 _sockets[socket].timeout_ms = TIMEOUT_BLOCKING; 01048 _sockets[socket].connected = false; 01049 _sockets[socket].pending = 0; 01050 ok = true; 01051 } 01052 UNLOCK(); 01053 return ok; 01054 } 01055 01056 #define USO_MAX_WRITE 1024 //!< maximum number of bytes to write to socket 01057 01058 int MDMParser::socketSend(int socket, const char * buf, int len) 01059 { 01060 TRACE("socketSend(%d,,%d)\r\n", socket,len); 01061 int cnt = len; 01062 while (cnt > 0) { 01063 int blk = USO_MAX_WRITE; 01064 if (cnt < blk) 01065 blk = cnt; 01066 bool ok = false; 01067 LOCK(); 01068 if (ISSOCKET(socket)) { 01069 sendFormated("AT+USOWR=%d,%d\r\n",_sockets[socket].handle,blk); 01070 if (RESP_PROMPT == waitFinalResp()) { 01071 wait_ms(50); 01072 send(buf, blk); 01073 if (RESP_OK == waitFinalResp()) 01074 ok = true; 01075 } 01076 } 01077 UNLOCK(); 01078 if (!ok) 01079 return SOCKET_ERROR; 01080 buf += blk; 01081 cnt -= blk; 01082 } 01083 return (len - cnt); 01084 } 01085 01086 int MDMParser::socketSendTo(int socket, IP ip, int port, const char * buf, int len) 01087 { 01088 TRACE("socketSendTo(%d," IPSTR ",%d,,%d)\r\n", socket,IPNUM(ip),port,len); 01089 int cnt = len; 01090 while (cnt > 0) { 01091 int blk = USO_MAX_WRITE; 01092 if (cnt < blk) 01093 blk = cnt; 01094 bool ok = false; 01095 LOCK(); 01096 if (ISSOCKET(socket)) { 01097 sendFormated("AT+USOST=%d,\"" IPSTR "\",%d,%d\r\n",_sockets[socket].handle,IPNUM(ip),port,blk); 01098 if (RESP_PROMPT == waitFinalResp()) { 01099 wait_ms(50); 01100 send(buf, blk); 01101 if (RESP_OK == waitFinalResp()) 01102 ok = true; 01103 } 01104 } 01105 UNLOCK(); 01106 if (!ok) 01107 return SOCKET_ERROR; 01108 buf += blk; 01109 cnt -= blk; 01110 } 01111 return (len - cnt); 01112 } 01113 01114 int MDMParser::socketReadable(int socket) 01115 { 01116 int pending = SOCKET_ERROR; 01117 LOCK(); 01118 if (ISSOCKET(socket) && _sockets[socket].connected) { 01119 TRACE("socketReadable(%d)\r\n", socket); 01120 // allow to receive unsolicited commands 01121 waitFinalResp(NULL, NULL, 0); 01122 if (_sockets[socket].connected) 01123 pending = _sockets[socket].pending; 01124 } 01125 UNLOCK(); 01126 return pending; 01127 } 01128 01129 int MDMParser::_cbUSORD(int type, const char* buf, int len, char* out) 01130 { 01131 if ((type == TYPE_PLUS) && out) { 01132 int sz, sk; 01133 if ((sscanf(buf, "\r\n+USORD: %d,%d,", &sk, &sz) == 2) && 01134 (buf[len-sz-2] == '\"') && (buf[len-1] == '\"')) { 01135 memcpy(out, &buf[len-1-sz], sz); 01136 } 01137 } 01138 return WAIT; 01139 } 01140 01141 int MDMParser::socketRecv(int socket, char* buf, int len) 01142 { 01143 int cnt = 0; 01144 TRACE("socketRecv(%d,,%d)\r\n", socket, len); 01145 #ifdef MDM_DEBUG 01146 memset(buf, '\0', len); 01147 #endif 01148 Timer timer; 01149 timer.start(); 01150 while (len) { 01151 int blk = MAX_SIZE; // still need space for headers and unsolicited commands 01152 if (len < blk) blk = len; 01153 bool ok = false; 01154 LOCK(); 01155 if (ISSOCKET(socket)) { 01156 if (_sockets[socket].connected) { 01157 if (_sockets[socket].pending < blk) 01158 blk = _sockets[socket].pending; 01159 if (blk > 0) { 01160 sendFormated("AT+USORD=%d,%d\r\n",_sockets[socket].handle, blk); 01161 if (RESP_OK == waitFinalResp(_cbUSORD, buf)) { 01162 _sockets[socket].pending -= blk; 01163 len -= blk; 01164 cnt += blk; 01165 buf += blk; 01166 ok = true; 01167 } 01168 } else if (!TIMEOUT(timer, _sockets[socket].timeout_ms)) { 01169 ok = (WAIT == waitFinalResp(NULL,NULL,0)); // wait for URCs 01170 } else { 01171 len = 0; 01172 ok = true; 01173 } 01174 } else { 01175 len = 0; 01176 ok = true; 01177 } 01178 } 01179 UNLOCK(); 01180 if (!ok) { 01181 TRACE("socketRecv: ERROR\r\n"); 01182 return SOCKET_ERROR; 01183 } 01184 } 01185 TRACE("socketRecv: %d \"%*s\"\r\n", cnt, cnt, buf-cnt); 01186 return cnt; 01187 } 01188 01189 int MDMParser::_cbUSORF(int type, const char* buf, int len, USORFparam* param) 01190 { 01191 if ((type == TYPE_PLUS) && param) { 01192 int sz, sk, p, a,b,c,d; 01193 int r = sscanf(buf, "\r\n+USORF: %d,\"" IPSTR "\",%d,%d,", 01194 &sk,&a,&b,&c,&d,&p,&sz); 01195 if ((r == 7) && (buf[len-sz-2] == '\"') && (buf[len-1] == '\"')) { 01196 memcpy(param->buf, &buf[len-1-sz], sz); 01197 param->ip = IPADR(a,b,c,d); 01198 param->port = p; 01199 } 01200 } 01201 return WAIT; 01202 } 01203 01204 int MDMParser::socketRecvFrom(int socket, IP* ip, int* port, char* buf, int len) 01205 { 01206 int cnt = 0; 01207 TRACE("socketRecvFrom(%d,,%d)\r\n", socket, len); 01208 #ifdef MDM_DEBUG 01209 memset(buf, '\0', len); 01210 #endif 01211 Timer timer; 01212 timer.start(); 01213 while (len) { 01214 int blk = MAX_SIZE; // still need space for headers and unsolicited commands 01215 if (len < blk) blk = len; 01216 bool ok = false; 01217 LOCK(); 01218 if (ISSOCKET(socket)) { 01219 if (_sockets[socket].pending < blk) 01220 blk = _sockets[socket].pending; 01221 if (blk > 0) { 01222 sendFormated("AT+USORF=%d,%d\r\n",_sockets[socket].handle, blk); 01223 USORFparam param; 01224 param.buf = buf; 01225 if (RESP_OK == waitFinalResp(_cbUSORF, ¶m)) { 01226 _sockets[socket].pending -= blk; 01227 *ip = param.ip; 01228 *port = param.port; 01229 len -= blk; 01230 cnt += blk; 01231 buf += blk; 01232 len = 0; // done 01233 ok = true; 01234 } 01235 } else if (!TIMEOUT(timer, _sockets[socket].timeout_ms)) { 01236 ok = (WAIT == waitFinalResp(NULL,NULL,0)); // wait for URCs 01237 } else { 01238 len = 0; // no more data and socket closed or timed-out 01239 ok = true; 01240 } 01241 } 01242 UNLOCK(); 01243 if (!ok) { 01244 TRACE("socketRecv: ERROR\r\n"); 01245 return SOCKET_ERROR; 01246 } 01247 } 01248 timer.stop(); 01249 timer.reset(); 01250 TRACE("socketRecv: %d \"%*s\"\r\n", cnt, cnt, buf-cnt); 01251 return cnt; 01252 } 01253 01254 int MDMParser::_findSocket(int handle) { 01255 for (int socket = 0; socket < NUMSOCKETS; socket ++) { 01256 if (_sockets[socket].handle == handle) 01257 return socket; 01258 } 01259 return SOCKET_ERROR; 01260 } 01261 01262 // ---------------------------------------------------------------- 01263 01264 int MDMParser::_cbCMGL(int type, const char* buf, int len, CMGLparam* param) 01265 { 01266 if ((type == TYPE_PLUS) && param && param->num) { 01267 // +CMGL: <ix>,... 01268 int ix; 01269 if (sscanf(buf, "\r\n+CMGL: %d,", &ix) == 1) 01270 { 01271 *param->ix++ = ix; 01272 param->num--; 01273 } 01274 } 01275 return WAIT; 01276 } 01277 01278 int MDMParser::smsList(const char* stat /*= "ALL"*/, int* ix /*=NULL*/, int num /*= 0*/) { 01279 int ret = -1; 01280 LOCK(); 01281 sendFormated("AT+CMGL=\"%s\"\r\n", stat); 01282 CMGLparam param; 01283 param.ix = ix; 01284 param.num = num; 01285 if (RESP_OK == waitFinalResp(_cbCMGL, ¶m)) 01286 ret = num - param.num; 01287 UNLOCK(); 01288 return ret; 01289 } 01290 01291 bool MDMParser::smsSend(const char* num, const char* buf) 01292 { 01293 bool ok = false; 01294 LOCK(); 01295 sendFormated("AT+CMGS=\"%s\"\r\n",num); 01296 if (RESP_PROMPT == waitFinalResp(NULL,NULL,150*1000)) { 01297 send(buf, strlen(buf)); 01298 const char ctrlZ = 0x1A; 01299 send(&ctrlZ, sizeof(ctrlZ)); 01300 ok = (RESP_OK == waitFinalResp()); 01301 } 01302 UNLOCK(); 01303 return ok; 01304 } 01305 01306 bool MDMParser::smsDelete(int ix) 01307 { 01308 bool ok = false; 01309 LOCK(); 01310 sendFormated("AT+CMGD=%d\r\n",ix); 01311 ok = (RESP_OK == waitFinalResp()); 01312 UNLOCK(); 01313 return ok; 01314 } 01315 01316 int MDMParser::_cbCMGR(int type, const char* buf, int len, CMGRparam* param) 01317 { 01318 if (param) { 01319 if (type == TYPE_PLUS) { 01320 if (sscanf(buf, "\r\n+CMGR: \"%*[^\"]\",\"%[^\"]", param->num) == 1) { 01321 } 01322 } else if ((type == TYPE_UNKNOWN) && (buf[len-2] == '\r') && (buf[len-1] == '\n')) { 01323 memcpy(param->buf, buf, len-2); 01324 param->buf[len-2] = '\0'; 01325 } 01326 } 01327 return WAIT; 01328 } 01329 01330 bool MDMParser::smsRead(int ix, char* num, char* buf, int len) 01331 { 01332 bool ok = false; 01333 LOCK(); 01334 CMGRparam param; 01335 param.num = num; 01336 param.buf = buf; 01337 sendFormated("AT+CMGR=%d\r\n",ix); 01338 ok = (RESP_OK == waitFinalResp(_cbCMGR, ¶m)); 01339 UNLOCK(); 01340 return ok; 01341 } 01342 01343 // ---------------------------------------------------------------- 01344 01345 int MDMParser::_cbCUSD(int type, const char* buf, int len, char* resp) 01346 { 01347 if ((type == TYPE_PLUS) && resp) { 01348 // +USD: \"%*[^\"]\",\"%[^\"]\",,\"%*[^\"]\",%d,%d,%d,%d,\"*[^\"]\",%d,%d"..); 01349 if (sscanf(buf, "\r\n+CUSD: %*d,\"%[^\"]\",%*d", resp) == 1) { 01350 /*nothing*/ 01351 } 01352 } 01353 return WAIT; 01354 } 01355 01356 bool MDMParser::ussdCommand(const char* cmd, char* buf) 01357 { 01358 bool ok = false; 01359 LOCK(); 01360 *buf = '\0'; 01361 if (_dev.dev != DEV_LISA_C2) { 01362 sendFormated("AT+CUSD=1,\"%s\"\r\n",cmd); 01363 ok = (RESP_OK == waitFinalResp(_cbCUSD, buf)); 01364 } 01365 UNLOCK(); 01366 return ok; 01367 } 01368 01369 // ---------------------------------------------------------------- 01370 01371 int MDMParser::_cbUDELFILE(int type, const char* buf, int len, void*) 01372 { 01373 if ((type == TYPE_ERROR) && strstr(buf, "+CME ERROR: FILE NOT FOUND")) 01374 return RESP_OK; // file does not exist, so all ok... 01375 return WAIT; 01376 } 01377 01378 bool MDMParser::delFile(const char* filename) 01379 { 01380 bool ok = false; 01381 LOCK(); 01382 sendFormated("AT+UDELFILE=\"%s\"\r\n", filename); 01383 ok = (RESP_OK == waitFinalResp(_cbUDELFILE)); 01384 UNLOCK(); 01385 return ok; 01386 } 01387 01388 int MDMParser::writeFile(const char* filename, const char* buf, int len) 01389 { 01390 bool ok = false; 01391 LOCK(); 01392 sendFormated("AT+UDWNFILE=\"%s\",%d\r\n", filename, len); 01393 if (RESP_PROMPT == waitFinalResp()) { 01394 send(buf, len); 01395 ok = (RESP_OK == waitFinalResp()); 01396 } 01397 UNLOCK(); 01398 return ok ? len : -1; 01399 } 01400 01401 int MDMParser::readFile(const char* filename, char* buf, int len) 01402 { 01403 URDFILEparam param; 01404 param.filename = filename; 01405 param.buf = buf; 01406 param.sz = len; 01407 param.len = 0; 01408 LOCK(); 01409 sendFormated("AT+URDFILE=\"%s\"\r\n", filename, len); 01410 if (RESP_OK != waitFinalResp(_cbURDFILE, ¶m)) 01411 param.len = -1; 01412 UNLOCK(); 01413 return param.len; 01414 } 01415 01416 int MDMParser::_cbURDFILE(int type, const char* buf, int len, URDFILEparam* param) 01417 { 01418 if ((type == TYPE_PLUS) && param && param->filename && param->buf) { 01419 char filename[48]; 01420 int sz; 01421 if ((sscanf(buf, "\r\n+URDFILE: \"%[^\"]\",%d,", filename, &sz) == 2) && 01422 (0 == strcmp(param->filename, filename)) && 01423 (buf[len-sz-2] == '\"') && (buf[len-1] == '\"')) { 01424 param->len = (sz < param->sz) ? sz : param->sz; 01425 memcpy(param->buf, &buf[len-1-sz], param->len); 01426 } 01427 } 01428 return WAIT; 01429 } 01430 01431 // ---------------------------------------------------------------- 01432 bool MDMParser::setDebug (int level) 01433 { 01434 #ifdef MDM_DEBUG 01435 _debugLevel = (level < -1) ? -1 : 01436 (level > 3) ? 3 : 01437 level; 01438 #endif 01439 return _debugLevel == level; 01440 } 01441 01442 void MDMParser::dumpDevStatus(MDMParser::DevStatus* status, 01443 _DPRINT dprint, void* param) 01444 { 01445 dprint(param, "Modem::devStatus\r\n"); 01446 const char* txtDev[] = { "Unknown", "SARA-G35", "LISA-U2", "LISA-C2", 01447 "SARA-U2", "LEON-G2", "TOBY-L2", "MPCI-L2" }; 01448 if (status->dev < sizeof(txtDev)/sizeof(*txtDev) && (status->dev != DEV_UNKNOWN)) 01449 dprint(param, " Device: %s\r\n", txtDev[status->dev]); 01450 const char* txtLpm[] = { "Disabled", "Enabled", "Active" }; 01451 if (status->lpm < sizeof(txtLpm)/sizeof(*txtLpm)) 01452 dprint(param, " Power Save: %s\r\n", txtLpm[status->lpm]); 01453 const char* txtSim[] = { "Unknown", "Missing", "Pin", "Ready" }; 01454 if (status->sim < sizeof(txtSim)/sizeof(*txtSim) && (status->sim != SIM_UNKNOWN)) 01455 dprint(param, " SIM: %s\r\n", txtSim[status->sim]); 01456 if (*status->ccid) 01457 dprint(param, " CCID: %s\r\n", status->ccid); 01458 if (*status->imei) 01459 dprint(param, " IMEI: %s\r\n", status->imei); 01460 if (*status->imsi) 01461 dprint(param, " IMSI: %s\r\n", status->imsi); 01462 if (*status->meid) 01463 dprint(param, " MEID: %s\r\n", status->meid); // LISA-C 01464 if (*status->manu) 01465 dprint(param, " Manufacturer: %s\r\n", status->manu); 01466 if (*status->model) 01467 dprint(param, " Model: %s\r\n", status->model); 01468 if (*status->ver) 01469 dprint(param, " Version: %s\r\n", status->ver); 01470 } 01471 01472 void MDMParser::dumpNetStatus(MDMParser::NetStatus *status, 01473 _DPRINT dprint, void* param) 01474 { 01475 dprint(param, "Modem::netStatus\r\n"); 01476 const char* txtReg[] = { "Unknown", "Denied", "None", "Home", "Roaming" }; 01477 if (status->csd < sizeof(txtReg)/sizeof(*txtReg) && (status->csd != REG_UNKNOWN)) 01478 dprint(param, " CSD Registration: %s\r\n", txtReg[status->csd]); 01479 if (status->psd < sizeof(txtReg)/sizeof(*txtReg) && (status->psd != REG_UNKNOWN)) 01480 dprint(param, " PSD Registration: %s\r\n", txtReg[status->psd]); 01481 if (status->eps < sizeof(txtReg)/sizeof(*txtReg) && (status->eps != REG_UNKNOWN)) 01482 dprint(param, " EPS Registration: %s\r\n", txtReg[status->eps]); 01483 const char* txtAct[] = { "Unknown", "GSM", "Edge", "3G", "CDMA", "LTE" }; 01484 if (status->act < sizeof(txtAct)/sizeof(*txtAct) && (status->act != ACT_UNKNOWN)) 01485 dprint(param, " Access Technology: %s\r\n", txtAct[status->act]); 01486 if (status->rssi) 01487 dprint(param, " Signal Strength: %d dBm\r\n", status->rssi); 01488 if (status->ber) 01489 dprint(param, " Bit Error Rate: %d\r\n", status->ber); 01490 if (*status->opr) 01491 dprint(param, " Operator: %s\r\n", status->opr); 01492 if (status->lac != 0xFFFF) 01493 dprint(param, " Location Area Code: %04X\r\n", status->lac); 01494 if (status->ci != 0xFFFFFFFF) 01495 dprint(param, " Cell ID: %08X\r\n", status->ci); 01496 if (*status->num) 01497 dprint(param, " Phone Number: %s\r\n", status->num); 01498 } 01499 01500 void MDMParser::dumpIp(MDMParser::IP ip, 01501 _DPRINT dprint, void* param) 01502 { 01503 if (ip != NOIP) 01504 dprint(param, "Modem:IP " IPSTR "\r\n", IPNUM(ip)); 01505 } 01506 01507 // ---------------------------------------------------------------- 01508 int MDMParser::_parseMatch(Pipe<char> * pipe, int len, const char* sta, const char* end) 01509 { 01510 int o = 0; 01511 if (sta) { 01512 while (*sta) { 01513 if (++o > len) return WAIT; 01514 char ch = pipe->next(); 01515 if (*sta++ != ch) return NOT_FOUND; 01516 } 01517 } 01518 if (!end) return o; // no termination 01519 // at least any char 01520 if (++o > len) return WAIT; 01521 pipe->next(); 01522 // check the end 01523 int x = 0; 01524 while (end[x]) { 01525 if (++o > len) return WAIT; 01526 char ch = pipe->next(); 01527 x = (end[x] == ch) ? x + 1 : 01528 (end[0] == ch) ? 1 : 01529 0; 01530 } 01531 return o; 01532 } 01533 01534 int MDMParser::_parseFormated(Pipe<char> * pipe, int len, const char* fmt) 01535 { 01536 int o = 0; 01537 int num = 0; 01538 if (fmt) { 01539 while (*fmt) { 01540 if (++o > len) return WAIT; 01541 char ch = pipe->next(); 01542 if (*fmt == '%') { 01543 fmt++; 01544 if (*fmt == 'd') { // numeric 01545 fmt ++; 01546 num = 0; 01547 while (ch >= '0' && ch <= '9') { 01548 num = num * 10 + (ch - '0'); 01549 if (++o > len) return WAIT; 01550 ch = pipe->next(); 01551 } 01552 } 01553 else if (*fmt == 'c') { // char buffer (takes last numeric as length) 01554 fmt ++; 01555 while (num --) { 01556 if (++o > len) return WAIT; 01557 ch = pipe->next(); 01558 } 01559 } 01560 else if (*fmt == 's') { 01561 fmt ++; 01562 if (ch != '\"') return NOT_FOUND; 01563 do { 01564 if (++o > len) return WAIT; 01565 ch = pipe->next(); 01566 } while (ch != '\"'); 01567 if (++o > len) return WAIT; 01568 ch = pipe->next(); 01569 } 01570 } 01571 if (*fmt++ != ch) return NOT_FOUND; 01572 } 01573 } 01574 return o; 01575 } 01576 01577 int MDMParser::_getLine(Pipe<char> * pipe, char* buf, int len) 01578 { 01579 int unkn = 0; 01580 int sz = pipe->size(); 01581 int fr = pipe->free(); 01582 if (len > sz) 01583 len = sz; 01584 while (len > 0) 01585 { 01586 static struct { 01587 const char* fmt; int type; 01588 } lutF[] = { 01589 { "\r\n+USORD: %d,%d,\"%c\"", TYPE_PLUS }, 01590 { "\r\n+USORF: %d,\"" IPSTR "\",%d,%d,\"%c\"", TYPE_PLUS }, 01591 { "\r\n+URDFILE: %s,%d,\"%c\"", TYPE_PLUS }, 01592 }; 01593 static struct { 01594 const char* sta; const char* end; int type; 01595 } lut[] = { 01596 { "\r\nOK\r\n", NULL, TYPE_OK }, 01597 { "\r\nERROR\r\n", NULL, TYPE_ERROR }, 01598 { "\r\n+CME ERROR:", "\r\n", TYPE_ERROR }, 01599 { "\r\n+CMS ERROR:", "\r\n", TYPE_ERROR }, 01600 { "\r\nRING\r\n", NULL, TYPE_RING }, 01601 { "\r\nCONNECT\r\n", NULL, TYPE_CONNECT }, 01602 { "\r\nNO CARRIER\r\n", NULL, TYPE_NOCARRIER }, 01603 { "\r\nNO DIALTONE\r\n", NULL, TYPE_NODIALTONE }, 01604 { "\r\nBUSY\r\n", NULL, TYPE_BUSY }, 01605 { "\r\nNO ANSWER\r\n", NULL, TYPE_NOANSWER }, 01606 { "\r\n+", "\r\n", TYPE_PLUS }, 01607 { "\r\n@", NULL, TYPE_PROMPT }, // Sockets 01608 { "\r\n>", NULL, TYPE_PROMPT }, // SMS 01609 { "\n>", NULL, TYPE_PROMPT }, // File 01610 }; 01611 for (int i = 0; i < sizeof(lutF)/sizeof(*lutF); i ++) { 01612 pipe->set(unkn); 01613 int ln = _parseFormated(pipe, len, lutF[i].fmt); 01614 if (ln == WAIT && fr) 01615 return WAIT; 01616 if ((ln != NOT_FOUND) && (unkn > 0)) 01617 return TYPE_UNKNOWN | pipe->get (buf, unkn); 01618 if (ln > 0) 01619 return lutF[i].type | pipe->get (buf, ln); 01620 } 01621 for (int i = 0; i < sizeof(lut)/sizeof(*lut); i ++) { 01622 pipe->set(unkn); 01623 int ln = _parseMatch(pipe, len, lut[i].sta, lut[i].end); 01624 if (ln == WAIT && fr) 01625 return WAIT; 01626 if ((ln != NOT_FOUND) && (unkn > 0)) 01627 return TYPE_UNKNOWN | pipe->get (buf, unkn); 01628 if (ln > 0) 01629 return lut[i].type | pipe->get (buf, ln); 01630 } 01631 // UNKNOWN 01632 unkn ++; 01633 len--; 01634 } 01635 return WAIT; 01636 } 01637 01638 // ---------------------------------------------------------------- 01639 // Serial Implementation 01640 // ---------------------------------------------------------------- 01641 01642 /*! Helper Dev Null Device 01643 Small helper class used to shut off stderr/stdout. Sometimes stdin/stdout 01644 is shared with the serial port of the modem. Having printfs inbetween the 01645 AT commands you cause a failure of the modem. 01646 */ 01647 class DevNull : public Stream { 01648 public: 01649 DevNull() : Stream(_name+1) { } //!< Constructor 01650 void claim(const char* mode, FILE* file) 01651 { freopen(_name, mode, file); } //!< claim a stream 01652 protected: 01653 virtual int _getc() { return EOF; } //!< Nothing 01654 virtual int _putc(int c) { return c; } //!< Discard 01655 static const char* _name; //!< File name 01656 }; 01657 const char* DevNull::_name = "/null"; //!< the null device name 01658 static DevNull null; //!< the null device 01659 01660 MDMSerial::MDMSerial(PinName tx /*= MDMTXD*/, PinName rx /*= MDMRXD*/, 01661 int baudrate /*= MDMBAUD*/, 01662 #if DEVICE_SERIAL_FC 01663 PinName rts /*= MDMRTS*/, PinName cts /*= MDMCTS*/, 01664 #endif 01665 int rxSize /*= 256*/, int txSize /*= 128*/) : 01666 SerialPipe(tx, rx, rxSize, txSize) 01667 { 01668 if (rx == USBRX) 01669 null.claim("r", stdin); 01670 if (tx == USBTX) { 01671 null.claim("w", stdout); 01672 null.claim("w", stderr); 01673 #ifdef MDM_DEBUG 01674 _debugLevel = -1; 01675 #endif 01676 } 01677 #ifdef TARGET_UBLOX_C027 01678 _onboard = (tx == MDMTXD) && (rx == MDMRXD); 01679 if (_onboard) 01680 c027_mdm_powerOn(false); 01681 #endif 01682 baud(baudrate); 01683 #if DEVICE_SERIAL_FC 01684 if ((rts != NC) || (cts != NC)) 01685 { 01686 Flow flow = (cts == NC) ? RTS : 01687 (rts == NC) ? CTS : RTSCTS ; 01688 set_flow_control(flow, rts, cts); 01689 if (cts != NC) _dev.lpm = LPM_ENABLED; 01690 } 01691 #endif 01692 } 01693 01694 MDMSerial::~MDMSerial(void) 01695 { 01696 powerOff(); 01697 #ifdef TARGET_UBLOX_C027 01698 if (_onboard) 01699 c027_mdm_powerOff(); 01700 #endif 01701 } 01702 01703 int MDMSerial::_send(const void* buf, int len) 01704 { 01705 return put((const char*)buf, len, true/*=blocking*/); 01706 } 01707 01708 int MDMSerial::getLine(char* buffer, int length) 01709 { 01710 return _getLine(&_pipeRx, buffer, length); 01711 } 01712 01713 // ---------------------------------------------------------------- 01714 // USB Implementation 01715 // ---------------------------------------------------------------- 01716 01717 #ifdef HAVE_MDMUSB 01718 MDMUsb::MDMUsb(void) 01719 { 01720 #ifdef MDM_DEBUG 01721 _debugLevel = 1; 01722 #endif 01723 #ifdef TARGET_UBLOX_C027 01724 _onboard = true; 01725 c027_mdm_powerOn(true); 01726 #endif 01727 } 01728 01729 MDMUsb::~MDMUsb(void) 01730 { 01731 powerOff(); 01732 #ifdef TARGET_UBLOX_C027 01733 if (_onboard) 01734 c027_mdm_powerOff(); 01735 #endif 01736 } 01737 01738 int MDMUsb::_send(const void* buf, int len) { return 0; } 01739 01740 int MDMUsb::getLine(char* buffer, int length) { return NOT_FOUND; } 01741 01742 #endif
Generated on Fri Jul 15 2022 00:13:34 by
1.7.2
