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