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