Own fork of C027_Support
Dependents: MbedSmartRestMain MbedSmartRestMain
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 Tue Jul 12 2022 22:55:17 by 1.7.2