Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of C027_Support by
MDM.cpp
00001 #include "mbed.h" 00002 #include "MDM.h" 00003 #ifdef TARGET_UBLOX_C027 00004 #include "C027_api.h" 00005 #endif 00006 #include "MDMAPN.h" 00007 00008 #define PROFILE "0" //!< this is the psd profile used 00009 #define MAX_SIZE 128 //!< max expected messages 00010 // num sockets 00011 #define NUMSOCKETS (sizeof(_sockets)/sizeof(*_sockets)) 00012 //! test if it is a socket is ok to use 00013 #define ISSOCKET(s) (((s) >= 0) && ((s) < NUMSOCKETS) && (_sockets[s].handle != SOCKET_ERROR)) 00014 //! check for timeout 00015 #define TIMEOUT(t, ms) ((ms != TIMEOUT_BLOCKING) && (ms < t.read_ms())) 00016 // num HTTP profiles 00017 #define NUMPROFILES (sizeof(_httpProfiles)/sizeof(*_httpProfiles)) 00018 //! test if it is an HTTP profile is ok to use 00019 #define ISPROFILE(p) (((p) >= 0) && ((p) < NUMPROFILES) && (_httpProfiles[p].handle != HTTP_PROF_ERROR)) 00020 //! registration ok check helper 00021 #define REG_OK(r) ((r == REG_HOME) || (r == REG_ROAMING)) 00022 //! registration done check helper (no need to poll further) 00023 #define REG_DONE(r) ((r == REG_HOME) || (r == REG_ROAMING) || (r == REG_DENIED)) 00024 //! helper to make sure that lock unlock pair is always balaced 00025 #define LOCK() { lock() 00026 //! helper to make sure that lock unlock pair is always balaced 00027 #define UNLOCK() } unlock() 00028 00029 #ifdef MDM_DEBUG 00030 #if 1 // colored terminal output using ANSI escape sequences 00031 #define COL(c) "\033[" c 00032 #else 00033 #define COL(c) 00034 #endif 00035 #define DEF COL("39m") 00036 #define BLA COL("30m") 00037 #define RED COL("31m") 00038 #define GRE COL("32m") 00039 #define YEL COL("33m") 00040 #define BLU COL("34m") 00041 #define MAG COL("35m") 00042 #define CYA COL("36m") 00043 #define WHY COL("37m") 00044 00045 void dumpAtCmd(const char* buf, int len) 00046 { 00047 ::printf(" %3d \"", len); 00048 while (len --) { 00049 char ch = *buf++; 00050 if ((ch > 0x1F) && (ch != 0x7F)) { // is printable 00051 if (ch == '%') ::printf("%%"); 00052 else if (ch == '"') ::printf("\\\""); 00053 else if (ch == '\\') ::printf("\\\\"); 00054 else putchar(ch); 00055 } else { 00056 if (ch == '\a') ::printf("\\a"); // BEL (0x07) 00057 else if (ch == '\b') ::printf("\\b"); // Backspace (0x08) 00058 else if (ch == '\t') ::printf("\\t"); // Horizontal Tab (0x09) 00059 else if (ch == '\n') ::printf("\\n"); // Linefeed (0x0A) 00060 else if (ch == '\v') ::printf("\\v"); // Vertical Tab (0x0B) 00061 else if (ch == '\f') ::printf("\\f"); // Formfeed (0x0C) 00062 else if (ch == '\r') ::printf("\\r"); // Carriage Return (0x0D) 00063 else ::printf("\\x%02x", (unsigned char)ch); 00064 } 00065 } 00066 ::printf("\"\r\n"); 00067 } 00068 00069 void MDMParser::_debugPrint(int level, const char* color, const char* format, ...) 00070 { 00071 if (_debugLevel >= level) 00072 { 00073 va_list args; 00074 va_start (args, format); 00075 if (color) ::printf(color); 00076 ::vprintf(format, args); 00077 if (color) ::printf(DEF); 00078 va_end (args); 00079 } 00080 } 00081 00082 #define ERROR(...) _debugPrint(0, RED, __VA_ARGS__) 00083 #define INFO(...) _debugPrint(1, GRE, __VA_ARGS__) 00084 #define TRACE(...) _debugPrint(2, DEF, __VA_ARGS__) 00085 #define TEST(...) _debugPrint(3, CYA, __VA_ARGS__) 00086 00087 #else 00088 00089 #define ERROR(...) (void)0 // no tracing 00090 #define TEST(...) (void)0 // no tracing 00091 #define INFO(...) (void)0 // no tracing 00092 #define TRACE(...) (void)0 // no tracing 00093 00094 #endif 00095 00096 MDMParser* MDMParser::inst; 00097 00098 MDMParser::MDMParser(void) 00099 { 00100 inst = this; 00101 memset(&_dev, 0, sizeof(_dev)); 00102 memset(&_net, 0, sizeof(_net)); 00103 _net.lac = 0xFFFF; 00104 _net.ci = 0xFFFFFFFF; 00105 _ip = NOIP; 00106 _init = false; 00107 memset(_sockets, 0, sizeof(_sockets)); 00108 for (int socket = 0; socket < NUMSOCKETS; socket ++) 00109 _sockets[socket].handle = SOCKET_ERROR; 00110 memset(_httpProfiles, 0, sizeof(_httpProfiles)); 00111 for (int profile = 0; profile < NUMPROFILES; profile ++) 00112 _httpProfiles[profile].handle = HTTP_PROF_ERROR; 00113 #ifdef MDM_DEBUG 00114 _debugLevel = 1; 00115 _debugTime.start(); 00116 #endif 00117 } 00118 00119 int MDMParser::send(const char* buf, int len) 00120 { 00121 #ifdef MDM_DEBUG 00122 if (_debugLevel >= 3) { 00123 ::printf("%10.3f AT send ", _debugTime.read_ms()*0.001); 00124 dumpAtCmd(buf,len); 00125 } 00126 #endif 00127 return _send(buf, len); 00128 } 00129 00130 int MDMParser::sendFormated(const char* format, ...) { 00131 char buf[MAX_SIZE]; 00132 va_list args; 00133 va_start(args, format); 00134 int len = vsnprintf(buf,sizeof(buf), format, args); 00135 va_end(args); 00136 return send(buf, len); 00137 } 00138 00139 int MDMParser::waitFinalResp(_CALLBACKPTR cb /* = NULL*/, 00140 void* param /* = NULL*/, 00141 int timeout_ms /*= 5000*/) 00142 { 00143 char buf[MAX_SIZE + 64 /* add some more space for framing */]; 00144 Timer timer; 00145 timer.start(); 00146 do { 00147 int ret = getLine(buf, sizeof(buf)); 00148 #ifdef MDM_DEBUG 00149 if ((_debugLevel >= 3) && (ret != WAIT) && (ret != NOT_FOUND)) 00150 { 00151 int len = LENGTH(ret); 00152 int type = TYPE(ret); 00153 const char* s = (type == TYPE_UNKNOWN)? YEL "UNK" DEF : 00154 (type == TYPE_TEXT) ? MAG "TXT" DEF : 00155 (type == TYPE_OK ) ? GRE "OK " DEF : 00156 (type == TYPE_ERROR) ? RED "ERR" DEF : 00157 (type == TYPE_PLUS) ? CYA " + " DEF : 00158 (type == TYPE_PROMPT) ? BLU " > " DEF : 00159 "..." ; 00160 ::printf("%10.3f AT read %s", _debugTime.read_ms()*0.001, s); 00161 dumpAtCmd(buf, len); 00162 } 00163 #endif 00164 if ((ret != WAIT) && (ret != NOT_FOUND)) 00165 { 00166 int type = TYPE(ret); 00167 // handle unsolicited commands here 00168 if (type == TYPE_PLUS) { 00169 const char* cmd = buf+3; 00170 int a, b, c, d, r; 00171 char s[32]; 00172 00173 // SMS Command --------------------------------- 00174 // +CNMI: <mem>,<index> 00175 if (sscanf(cmd, "CMTI: \"%*[^\"]\",%d", &a) == 1) { 00176 TRACE("New SMS at index %d\r\n", a); 00177 // Socket Specific Command --------------------------------- 00178 // +UUSORD: <socket>,<length> 00179 } else if ((sscanf(cmd, "UUSORD: %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 // +UUSORF: <socket>,<length> 00185 } else if ((sscanf(cmd, "UUSORF: %d,%d", &a, &b) == 2)) { 00186 int socket = _findSocket(a); 00187 TRACE("Socket %d: handle %d has %d bytes pending\r\n", socket, a, b); 00188 if (socket != SOCKET_ERROR) 00189 _sockets[socket].pending = b; 00190 // +UUSOCL: <socket> 00191 } else if ((sscanf(cmd, "UUSOCL: %d", &a) == 1)) { 00192 int socket = _findSocket(a); 00193 TRACE("Socket %d: handle %d closed by remote host\r\n", socket, a); 00194 if ((socket != SOCKET_ERROR) && _sockets[socket].connected) 00195 _sockets[socket].connected = false; 00196 // +UULOC: <date>,<time>,<lat>,<long>,<alt>,<uncertainty>,<speed>, <direction>,<vertical_acc>,<sensor_used>,<SV_used>,<antenna_status>, <jamming_status> 00197 }else if (sscanf(cmd, "UULOC: %d/%d/%d,%d:%d:%d.%*d,%f,%f,%d,%d,%d,%d,%d,%d,%d,%*d,%*d",\ 00198 &_loc.time.tm_mday, &_loc.time.tm_mon, &_loc.time.tm_year, &_loc.time.tm_hour, &_loc.time.tm_min, &_loc.time.tm_sec,\ 00199 &_loc.latitue, &_loc.longitude, &_loc.altitutude, &_loc.uncertainty, &_loc.speed, &_loc.direction, &_loc.verticalAcc, \ 00200 &_loc.sensorUsed, &_loc.svUsed) == 15) { 00201 _loc.time.tm_mon -= 1; 00202 _loc.time.tm_wday=0; 00203 _loc.time.tm_yday=0; 00204 _loc.validData = true; 00205 TRACE("Parsed UULOC position\r\n"); 00206 // +UHTTPCR: <profile_id>,<op_code>,<param_val> 00207 } else if ((sscanf(cmd, "UUHTTPCR: %d,%d,%d", &a, &b, &c) == 3)) { 00208 _httpProfiles[a].cmd = b; //command 00209 _httpProfiles[a].result = c; //result 00210 TRACE("%s for profile %d: result code is %d\r\n", getHTTPcmd(b), a, c); 00211 } 00212 if (_dev.dev == DEV_LISA_C2) { 00213 // CDMA Specific ------------------------------------------- 00214 // +CREG: <n><SID>,<NID>,<stat> 00215 if (sscanf(cmd, "CREG: %*d,%d,%d,%d",&a,&b,&c) == 3) { 00216 // _net.sid = a; 00217 // _net.nid = b; 00218 if (c == 0) _net.csd = REG_NONE; // not registered, home network 00219 else if (c == 1) _net.csd = REG_HOME; // registered, home network 00220 else if (c == 2) _net.csd = REG_NONE; // not registered, but MT is currently searching a new operator to register to 00221 else if (c == 3) _net.csd = REG_DENIED; // registration denied 00222 else if (c == 5) _net.csd = REG_ROAMING; // registered, roaming 00223 _net.psd = _net.csd; // fake PSD registration (CDMA is always registered) 00224 _net.act = ACT_CDMA; 00225 // +CSS: <mode>[,<format>,<oper>[,<AcT>]] 00226 } else if (sscanf(cmd, "CSS %*c,%2s,%*d",s) == 1) { 00227 //_net.reg = (strcmp("Z", s) == 0) ? REG_UNKNOWN : REG_HOME; 00228 } 00229 } else { 00230 // GSM/UMTS Specific ------------------------------------------- 00231 // +UUPSDD: <profile_id> 00232 if (sscanf(cmd, "UUPSDD: %d",&a) == 1) { 00233 if (*PROFILE == a) _ip = NOIP; 00234 } else { 00235 // +CREG|CGREG: <n>,<stat>[,<lac>,<ci>[,AcT[,<rac>]]] // reply to AT+CREG|AT+CGREG 00236 // +CREG|CGREG: <stat>[,<lac>,<ci>[,AcT[,<rac>]]] // URC 00237 b = 0xFFFF; c = 0xFFFFFFFF; d = -1; 00238 r = sscanf(cmd, "%s %*d,%d,\"%X\",\"%X\",%d",s,&a,&b,&c,&d); 00239 if (r <= 1) 00240 r = sscanf(cmd, "%s %d,\"%X\",\"%X\",%d",s,&a,&b,&c,&d); 00241 if (r >= 2) { 00242 Reg *reg = !strcmp(s, "CREG:") ? &_net.csd : 00243 !strcmp(s, "CGREG:") ? &_net.psd : 00244 !strcmp(s, "CEREG:") ? &_net.eps : NULL; 00245 if (reg) { 00246 // network status 00247 if (a == 0) *reg = REG_NONE; // 0: not registered, home network 00248 else if (a == 1) *reg = REG_HOME; // 1: registered, home network 00249 else if (a == 2) *reg = REG_NONE; // 2: not registered, but MT is currently searching a new operator to register to 00250 else if (a == 3) *reg = REG_DENIED; // 3: registration denied 00251 else if (a == 4) *reg = REG_UNKNOWN; // 4: unknown 00252 else if (a == 5) *reg = REG_ROAMING; // 5: registered, roaming 00253 else if (a == 6) *reg = REG_HOME; // 6: registered, sms only, home 00254 if ((r >= 3) && (b != 0xFFFF)) _net.lac = b; // location area code 00255 if ((r >= 4) && (c != 0xFFFFFFFF)) _net.ci = c; // cell ID 00256 // access technology 00257 if (r >= 5) { 00258 if (d == 0) _net.act = ACT_GSM; // 0: GSM 00259 else if (d == 1) _net.act = ACT_GSM; // 1: GSM COMPACT 00260 else if (d == 2) _net.act = ACT_UTRAN; // 2: UTRAN 00261 else if (d == 3) _net.act = ACT_EDGE; // 3: GSM with EDGE availability 00262 else if (d == 4) _net.act = ACT_UTRAN; // 4: UTRAN with HSDPA availability 00263 else if (d == 5) _net.act = ACT_UTRAN; // 5: UTRAN with HSUPA availability 00264 else if (d == 6) _net.act = ACT_UTRAN; // 6: UTRAN with HSDPA and HSUPA availability 00265 else if (d == 7) _net.act = ACT_LTE; // 7: LTE 00266 } 00267 } 00268 } 00269 } 00270 } 00271 } 00272 if (cb) { 00273 int len = LENGTH(ret); 00274 int ret = cb(type, buf, len, param); 00275 if (WAIT != ret) 00276 return ret; 00277 } 00278 if (type == TYPE_OK) 00279 return RESP_OK; 00280 if (type == TYPE_ERROR) 00281 return RESP_ERROR; 00282 if (type == TYPE_ERROR_CME) 00283 return RESP_ERROR_CME; 00284 if (type == TYPE_PROMPT) 00285 return RESP_PROMPT; 00286 } 00287 // relax a bit 00288 wait_ms(10); 00289 } 00290 while (!TIMEOUT(timer, timeout_ms)); 00291 return WAIT; 00292 } 00293 00294 int MDMParser::_cbString(int type, const char* buf, int len, char* str) 00295 { 00296 if (str && (type == TYPE_UNKNOWN)) { 00297 if (sscanf(buf, "\r\n%s\r\n", str) == 1) 00298 /*nothing*/; 00299 } 00300 return WAIT; 00301 } 00302 00303 int MDMParser::_cbInt(int type, const char* buf, int len, int* val) 00304 { 00305 if (val && (type == TYPE_UNKNOWN)) { 00306 if (sscanf(buf, "\r\n%d\r\n", val) == 1) 00307 /*nothing*/; 00308 } 00309 return WAIT; 00310 } 00311 00312 // ---------------------------------------------------------------- 00313 00314 bool MDMParser::connect( 00315 const char* simpin, 00316 const char* apn, const char* username, 00317 const char* password, Auth auth, 00318 PinName pn) 00319 { 00320 bool ok = init(simpin, NULL, pn); 00321 #ifdef MDM_DEBUG 00322 if (_debugLevel >= 1) dumpDevStatus(&_dev); 00323 #endif 00324 if (!ok) 00325 return false; 00326 ok = registerNet(); 00327 #ifdef MDM_DEBUG 00328 if (_debugLevel >= 1) dumpNetStatus(&_net); 00329 #endif 00330 if (!ok) 00331 return false; 00332 IP ip = join(apn,username,password,auth); 00333 #ifdef MDM_DEBUG 00334 if (_debugLevel >= 1) dumpIp(ip); 00335 #endif 00336 if (ip == NOIP) 00337 return false; 00338 return true; 00339 } 00340 00341 bool MDMParser::init(const char* simpin, DevStatus* status, PinName pn) 00342 { 00343 int i = 10; 00344 LOCK(); 00345 memset(&_dev, 0, sizeof(_dev)); 00346 if (pn != NC) { 00347 INFO("Modem::wakeup\r\n"); 00348 DigitalOut pin(pn, 1); 00349 while (i--) { 00350 // SARA-U2/LISA-U2 50..80us 00351 pin = 0; ::wait_us(50); 00352 pin = 1; ::wait_ms(10); 00353 00354 // SARA-G35 >5ms, LISA-C2 > 150ms, LEON-G2 >5ms 00355 pin = 0; ::wait_ms(150); 00356 pin = 1; ::wait_ms(100); 00357 00358 // purge any messages 00359 purge(); 00360 00361 // check interface 00362 sendFormated("AT\r\n"); 00363 int r = waitFinalResp(NULL,NULL,1000); 00364 if(RESP_OK == r) break; 00365 } 00366 if (i < 0) { 00367 ERROR("No Reply from Modem\r\n"); 00368 goto failure; 00369 } 00370 } 00371 _init = true; 00372 00373 INFO("Modem::init\r\n"); 00374 // echo off 00375 sendFormated("AT E0\r\n"); 00376 if(RESP_OK != waitFinalResp()) 00377 goto failure; 00378 // enable verbose error messages 00379 sendFormated("AT+CMEE=2\r\n"); 00380 if(RESP_OK != waitFinalResp()) 00381 goto failure; 00382 // set baud rate 00383 sendFormated("AT+IPR=115200\r\n"); 00384 if (RESP_OK != waitFinalResp()) 00385 goto failure; 00386 // wait some time until baudrate is applied 00387 wait_ms(200); // SARA-G > 40ms 00388 // identify the module 00389 sendFormated("ATI\r\n"); 00390 if (RESP_OK != waitFinalResp(_cbATI, &_dev.dev)) 00391 goto failure; 00392 if (_dev.dev == DEV_UNKNOWN) 00393 goto failure; 00394 // device specific init 00395 if (_dev.dev == DEV_LISA_C2) { 00396 // get the manufacturer 00397 sendFormated("AT+GMI\r\n"); 00398 if (RESP_OK != waitFinalResp(_cbString, _dev.manu)) 00399 goto failure; 00400 // get the model identification 00401 sendFormated("AT+GMM\r\n"); 00402 if (RESP_OK != waitFinalResp(_cbString, _dev.model)) 00403 goto failure; 00404 // get the sw version 00405 sendFormated("AT+GMR\r\n"); 00406 if (RESP_OK != waitFinalResp(_cbString, _dev.ver)) 00407 goto failure; 00408 // get the pseudo ESN or MEID 00409 sendFormated("AT+GSN\r\n"); 00410 if (RESP_OK != waitFinalResp(_cbString, _dev.meid)) 00411 goto failure; 00412 #if 0 00413 // enable power saving 00414 if (_dev.lpm != LPM_DISABLED) { 00415 // enable power saving (requires flow control, cts at least) 00416 sendFormated("AT+UPSV=1,1280\r\n"); 00417 if (RESP_OK != waitFinalResp()) 00418 goto failure; 00419 _dev.lpm = LPM_ACTIVE; 00420 } 00421 #endif 00422 } else { 00423 if ((_dev.dev == DEV_LISA_U2) || (_dev.dev == DEV_LEON_G2) || 00424 (_dev.dev == DEV_TOBY_L2)) { 00425 // enable the network identification feature 00426 sendFormated("AT+UGPIOC=20,2\r\n"); 00427 if (RESP_OK != waitFinalResp()) 00428 goto failure; 00429 } else if ((_dev.dev == DEV_SARA_U2) || (_dev.dev == DEV_SARA_G35)) { 00430 // enable the network identification feature 00431 sendFormated("AT+UGPIOC=16,2\r\n"); 00432 if (RESP_OK != waitFinalResp()) 00433 goto failure; 00434 } 00435 // check the sim card 00436 for (int i = 0; (i < 5) && (_dev.sim != SIM_READY); i++) { 00437 sendFormated("AT+CPIN?\r\n"); 00438 int ret = waitFinalResp(_cbCPIN, &_dev.sim); 00439 // having an error here is ok (sim may still be initializing) 00440 if ((RESP_OK != ret) && (RESP_ERROR != ret)) 00441 goto failure; 00442 // Enter PIN if needed 00443 if (_dev.sim == SIM_PIN) { 00444 if (!simpin) { 00445 ERROR("SIM PIN not available\r\n"); 00446 goto failure; 00447 } 00448 sendFormated("AT+CPIN=\"%s\"\r\n", simpin); 00449 if (RESP_OK != waitFinalResp(_cbCPIN, &_dev.sim)) 00450 goto failure; 00451 } else if (_dev.sim != SIM_READY) { 00452 wait_ms(1000); 00453 } 00454 } 00455 if (_dev.sim != SIM_READY) { 00456 if (_dev.sim == SIM_MISSING) 00457 ERROR("SIM not inserted\r\n"); 00458 goto failure; 00459 } 00460 // get the manufacturer 00461 sendFormated("AT+CGMI\r\n"); 00462 if (RESP_OK != waitFinalResp(_cbString, _dev.manu)) 00463 goto failure; 00464 // get the model identification 00465 sendFormated("AT+CGMM\r\n"); 00466 if (RESP_OK != waitFinalResp(_cbString, _dev.model)) 00467 goto failure; 00468 // get the version 00469 sendFormated("ATI9\r\n"); 00470 if (RESP_OK != waitFinalResp(_cbString, _dev.ver)) 00471 goto failure; 00472 // Returns the ICCID (Integrated Circuit Card ID) of the SIM-card. 00473 // ICCID is a serial number identifying the SIM. 00474 sendFormated("AT+CCID\r\n"); 00475 if (RESP_OK != waitFinalResp(_cbCCID, _dev.ccid)) 00476 goto failure; 00477 // Returns the product serial number, IMEI (International Mobile Equipment Identity) 00478 sendFormated("AT+CGSN\r\n"); 00479 if (RESP_OK != waitFinalResp(_cbString, _dev.imei)) 00480 goto failure; 00481 // enable power saving 00482 if (_dev.lpm != LPM_DISABLED) { 00483 // enable power saving (requires flow control, cts at least) 00484 sendFormated("AT+UPSV=1\r\n"); 00485 if (RESP_OK != waitFinalResp()) 00486 goto failure; 00487 _dev.lpm = LPM_ACTIVE; 00488 } 00489 // enable the psd registration unsolicited result code 00490 sendFormated("AT+CGREG=2\r\n"); 00491 if (RESP_OK != waitFinalResp()) 00492 goto failure; 00493 } 00494 // enable the network registration unsolicited result code 00495 sendFormated("AT+CREG=%d\r\n", (_dev.dev == DEV_LISA_C2) ? 1 : 2); 00496 if (RESP_OK != waitFinalResp()) 00497 goto failure; 00498 // Setup SMS in text mode 00499 sendFormated("AT+CMGF=1\r\n"); 00500 if (RESP_OK != waitFinalResp()) 00501 goto failure; 00502 // setup new message indication 00503 sendFormated("AT+CNMI=2,1\r\n"); 00504 if (RESP_OK != waitFinalResp()) 00505 goto failure; 00506 // Request IMSI (International Mobile Subscriber Identification) 00507 sendFormated("AT+CIMI\r\n"); 00508 if (RESP_OK != waitFinalResp(_cbString, _dev.imsi)) 00509 goto failure; 00510 if (status) 00511 memcpy(status, &_dev, sizeof(DevStatus)); 00512 UNLOCK(); 00513 return true; 00514 failure: 00515 unlock(); 00516 return false; 00517 } 00518 00519 bool MDMParser::powerOff(void) 00520 { 00521 bool ok = false; 00522 if (_init) { 00523 LOCK(); 00524 INFO("Modem::powerOff\r\n"); 00525 sendFormated("AT+CPWROFF\r\n"); 00526 if (RESP_OK == waitFinalResp(NULL,NULL,120*1000)) { 00527 _init = false; 00528 ok = true; 00529 } 00530 UNLOCK(); 00531 } 00532 return ok; 00533 } 00534 00535 int MDMParser::_cbATI(int type, const char* buf, int len, Dev* dev) 00536 { 00537 if ((type == TYPE_UNKNOWN) && dev) { 00538 if (strstr(buf, "SARA-G35")) *dev = DEV_SARA_G35; 00539 else if (strstr(buf, "LISA-U200-03S")) *dev = DEV_LISA_U2_03S; 00540 else if (strstr(buf, "LISA-U2")) *dev = DEV_LISA_U2; 00541 else if (strstr(buf, "LISA-C2")) *dev = DEV_LISA_C2; 00542 else if (strstr(buf, "SARA-U2")) *dev = DEV_SARA_U2; 00543 else if (strstr(buf, "LEON-G2")) *dev = DEV_LEON_G2; 00544 else if (strstr(buf, "TOBY-L2")) *dev = DEV_TOBY_L2; 00545 else if (strstr(buf, "MPCI-L2")) *dev = DEV_MPCI_L2; 00546 } 00547 return WAIT; 00548 } 00549 00550 int MDMParser::_cbCPIN(int type, const char* buf, int len, Sim* sim) 00551 { 00552 if (sim) { 00553 if (type == TYPE_PLUS){ 00554 char s[16]; 00555 if (sscanf(buf, "\r\n+CPIN: %[^\r]\r\n", s) >= 1) 00556 *sim = (0 == strcmp("READY", s)) ? SIM_READY : SIM_PIN; 00557 } else if (type == TYPE_ERROR) { 00558 if (strstr(buf, "+CME ERROR: SIM not inserted")) 00559 *sim = SIM_MISSING; 00560 } 00561 } 00562 return WAIT; 00563 } 00564 00565 int MDMParser::_cbCCID(int type, const char* buf, int len, char* ccid) 00566 { 00567 if ((type == TYPE_PLUS) && ccid){ 00568 if (sscanf(buf, "\r\n+CCID: %[^\r]\r\n", ccid) == 1) 00569 /*TRACE("Got CCID: %s\r\n", ccid)*/; 00570 } 00571 return WAIT; 00572 } 00573 00574 bool MDMParser::registerNet(NetStatus* status /*= NULL*/, int timeout_ms /*= 180000*/) 00575 { 00576 Timer timer; 00577 timer.start(); 00578 INFO("Modem::register\r\n"); 00579 while (!checkNetStatus(status) && !TIMEOUT(timer, timeout_ms)) 00580 wait_ms(1000); 00581 if (_net.csd == REG_DENIED) ERROR("CSD Registration Denied\r\n"); 00582 if (_net.psd == REG_DENIED) ERROR("PSD Registration Denied\r\n"); 00583 if (_net.eps == REG_DENIED) ERROR("EPS Registration Denied\r\n"); 00584 return REG_OK(_net.csd) || REG_OK(_net.psd) || REG_OK(_net.eps); 00585 } 00586 00587 bool MDMParser::checkNetStatus(NetStatus* status /*= NULL*/) 00588 { 00589 bool ok = false; 00590 LOCK(); 00591 memset(&_net, 0, sizeof(_net)); 00592 _net.lac = 0xFFFF; 00593 _net.ci = 0xFFFFFFFF; 00594 // check registration 00595 sendFormated("AT+CREG?\r\n"); 00596 waitFinalResp(); // don't fail as service could be not subscribed 00597 if (_dev.dev != DEV_LISA_C2) { 00598 // check PSD registration 00599 sendFormated("AT+CGREG?\r\n"); 00600 waitFinalResp(); // don't fail as service could be not subscribed 00601 if ((_dev.dev == DEV_TOBY_L2) || (_dev.dev == DEV_MPCI_L2)) { 00602 // check EPS network registration 00603 sendFormated("AT+CEREG?\r\n"); 00604 waitFinalResp(); // don't fail as service could be not subscribed 00605 } 00606 } 00607 if (REG_OK(_net.csd) || REG_OK(_net.psd) || REG_OK(_net.eps)) 00608 { 00609 // check modem specific status messages 00610 if (_dev.dev == DEV_LISA_C2) { 00611 sendFormated("AT+CSS?\r\n"); 00612 if (RESP_OK != waitFinalResp()) 00613 goto failure; 00614 while (1) { 00615 // get the Telephone number 00616 sendFormated("AT$MDN?\r\n"); 00617 if (RESP_OK != waitFinalResp(_cbString, _net.num)) 00618 goto failure; 00619 // check if we have a Mobile Directory Number 00620 if (*_net.num && (memcmp(_net.num, "000000", 6) != 0)) 00621 break; 00622 00623 INFO("Device not yet activated\r\n"); 00624 INFO("Make sure you have a valid contract with the network operator for this device.\r\n"); 00625 // Check if the the version contains a V for Verizon 00626 // Verizon: E0.V.xx.00.xxR, 00627 // Sprint E0.S.xx.00.xxR 00628 if (_dev.ver[3] == 'V') { 00629 int i; 00630 INFO("Start device over-the-air activation (this can take a few minutes)\r\n"); 00631 sendFormated("AT+CDV=*22899\r\n"); 00632 i = 1; 00633 if ((RESP_OK != waitFinalResp(_cbUACTIND, &i, 120*1000)) || (i == 1)) { 00634 ERROR("Device over-the-air activation failed\r\n"); 00635 goto failure; 00636 } 00637 INFO("Device over-the-air activation successful\r\n"); 00638 00639 INFO("Start PRL over-the-air update (this can take a few minutes)\r\n"); 00640 sendFormated("AT+CDV=*22891\r\n"); 00641 i = 1; 00642 if ((RESP_OK != waitFinalResp(_cbUACTIND, &i, 120*1000)) || (i == 1)) { 00643 ERROR("PRL over-the-air update failed\r\n"); 00644 goto failure; 00645 } 00646 INFO("PRL over-the-air update successful\r\n"); 00647 00648 } else { 00649 // Sprint or Aeris 00650 INFO("Wait for OMA-DM over-the-air activation (this can take a few minutes)\r\n"); 00651 wait_ms(120*1000); 00652 } 00653 } 00654 // get the the Network access identifier string 00655 char nai[64]; 00656 sendFormated("AT$QCMIPNAI?\r\n"); 00657 if (RESP_OK != waitFinalResp(_cbString, nai)) 00658 goto failure; 00659 } else { 00660 sendFormated("AT+COPS?\r\n"); 00661 if (RESP_OK != waitFinalResp(_cbCOPS, &_net)) 00662 goto failure; 00663 // get the MSISDNs related to this subscriber 00664 sendFormated("AT+CNUM\r\n"); 00665 if (RESP_OK != waitFinalResp(_cbCNUM, _net.num)) 00666 goto failure; 00667 } 00668 // get the signal strength indication 00669 sendFormated("AT+CSQ\r\n"); 00670 if (RESP_OK != waitFinalResp(_cbCSQ, &_net)) 00671 goto failure; 00672 } 00673 if (status) { 00674 memcpy(status, &_net, sizeof(NetStatus)); 00675 } 00676 ok = REG_DONE(_net.csd) && 00677 (REG_DONE(_net.psd) || REG_DONE(_net.eps)); 00678 UNLOCK(); 00679 return ok; 00680 failure: 00681 unlock(); 00682 return false; 00683 } 00684 00685 int MDMParser::_cbCOPS(int type, const char* buf, int len, NetStatus* status) 00686 { 00687 if ((type == TYPE_PLUS) && status){ 00688 int act = 99; 00689 int mode = 99; 00690 // +COPS: <mode>[,<format>,<oper>[,<AcT>]] 00691 if (sscanf(buf, "\r\n+COPS: %d,%*d,\"%[^\"]\",%d",&mode,status->opr,&act) >= 1) { 00692 if (act == 0) status->act = ACT_GSM; // 0: GSM, 00693 else if (act == 2) status->act = ACT_UTRAN; // 2: UTRAN 00694 else if (act == 7) status->act = ACT_LTE; // 2: UTRAN 00695 if (mode == 0) status->regStatus = COPS_AUTOMATIC_REG; 00696 else if (mode == 1) status->regStatus = COPS_MANUAL_REG; 00697 else if (mode == 2) status->regStatus = COPS_DISABLED_REG; 00698 } 00699 } 00700 return WAIT; 00701 } 00702 00703 int MDMParser::_cbCNUM(int type, const char* buf, int len, char* num) 00704 { 00705 if ((type == TYPE_PLUS) && num){ 00706 int a; 00707 if ((sscanf(buf, "\r\n+CNUM: \"My Number\",\"%31[^\"]\",%d", num, &a) == 2) && 00708 ((a == 129) || (a == 145))) { 00709 } 00710 } 00711 return WAIT; 00712 } 00713 00714 int MDMParser::_cbCSQ(int type, const char* buf, int len, NetStatus* status) 00715 { 00716 if ((type == TYPE_PLUS) && status){ 00717 int a,b; 00718 char _ber[] = { 49, 43, 37, 25, 19, 13, 7, 0 }; // see 3GPP TS 45.008 [20] subclause 8.2.4 00719 // +CSQ: <rssi>,<qual> 00720 if (sscanf(buf, "\r\n+CSQ: %d,%d",&a,&b) == 2) { 00721 if (a != 99) status->rssi = -113 + 2*a; // 0: -113 1: -111 ... 30: -53 dBm with 2 dBm steps, 31: >-51 dBm 00722 if ((b != 99) && (b < sizeof(_ber))) status->ber = _ber[b]; // 00723 } 00724 } 00725 return WAIT; 00726 } 00727 00728 00729 int MDMParser::_cbUACTIND(int type, const char* buf, int len, int* i) 00730 { 00731 if ((type == TYPE_PLUS) && i){ 00732 int a; 00733 if (sscanf(buf, "\r\n+UACTIND: %d", &a) == 1) { 00734 *i = a; 00735 } 00736 } 00737 return WAIT; 00738 } 00739 00740 // ---------------------------------------------------------------- 00741 // internet connection 00742 00743 bool MDMParser::_activateProfile(const char* apn, const char* username, const char* password, Auth auth) 00744 { 00745 // Set up the APN 00746 if (*apn) { 00747 sendFormated("AT+UPSD=" PROFILE ",1,\"%s\"\r\n", apn); 00748 if (RESP_OK != waitFinalResp()) 00749 return false; 00750 } 00751 if (*username) { 00752 sendFormated("AT+UPSD=" PROFILE ",2,\"%s\"\r\n", username); 00753 if (RESP_OK != waitFinalResp()) 00754 return false; 00755 } 00756 if (*password) { 00757 sendFormated("AT+UPSD=" PROFILE ",3,\"%s\"\r\n", password); 00758 if (RESP_OK != waitFinalResp()) 00759 return false; 00760 } 00761 // Set up the dynamic IP address assignment. 00762 sendFormated("AT+UPSD=" PROFILE ",7,\"0.0.0.0\"\r\n"); 00763 if (RESP_OK != waitFinalResp()) 00764 return false; 00765 // try different Authentication Protocols 00766 // 0 = none 00767 // 1 = PAP (Password Authentication Protocol) 00768 // 2 = CHAP (Challenge Handshake Authentication Protocol) 00769 for (int i = AUTH_NONE; i <= AUTH_CHAP; i ++) { 00770 if ((auth == AUTH_DETECT) || (auth == i)) { 00771 // Set up the Authentication Protocol 00772 sendFormated("AT+UPSD=" PROFILE ",6,%d\r\n",i); 00773 if (RESP_OK != waitFinalResp()) 00774 return false; 00775 // Activate the profile and make connection 00776 sendFormated("AT+UPSDA=" PROFILE ",3\r\n"); 00777 if (RESP_OK == waitFinalResp(NULL,NULL,150*1000)) 00778 return true; 00779 } 00780 } 00781 return false; 00782 } 00783 00784 bool MDMParser::_activateProfileReuseExternal(void) 00785 { 00786 int cid = -1; 00787 sendFormated("AT+CGDCONT?\r\n"); 00788 if (RESP_OK != waitFinalResp(_cbCGDCONT, &cid)) 00789 return false; 00790 if (cid == -1) 00791 return false; 00792 // we found a context that provides us a valid IP so lets reuse it for the internal IP stack 00793 sendFormated("AT+UPSD=" PROFILE ",100,%d\r\n", cid); 00794 if (RESP_OK != waitFinalResp()) 00795 return false; 00796 // Activate the profile and make connection 00797 sendFormated("AT+UPSDA=" PROFILE ",3\r\n"); 00798 return (RESP_OK == waitFinalResp(NULL,NULL,150*1000)); 00799 } 00800 00801 bool MDMParser::_activateProfileByCid(int cid, const char* apn, const char* username, const char* password, Auth auth) 00802 { 00803 sendFormated("AT+CGDCONT=%d,\"IP\",\"%s\"\r\n", cid, apn); 00804 if (RESP_OK != waitFinalResp()) 00805 return false; 00806 sendFormated("AT+UAUTHREQ=%d,%d,\"%s\",\"%s\"\r\n", cid, auth, username, password); 00807 if (RESP_OK != waitFinalResp()) 00808 return false; 00809 sendFormated("AT+UPSD=" PROFILE ",100,%d\r\n", cid); 00810 if (RESP_OK != waitFinalResp()) 00811 return false; 00812 // Activate the profile and make connection 00813 sendFormated("AT+UPSDA=" PROFILE ",3\r\n"); 00814 return (RESP_OK == waitFinalResp(NULL,NULL,150*1000)); 00815 } 00816 00817 int MDMParser::_cbCGDCONT(int type, const char* buf, int len, int* cid) 00818 { 00819 // accept with and without leading \r\n in +CGDCONT: 00820 if ((type == TYPE_PLUS) && (buf[0] == '\r') && (buf[1] == '\n') && (len >= 2)) 00821 buf += 2, len -= 2, type = TYPE_UNKNOWN; 00822 if (type == TYPE_UNKNOWN) { 00823 int a,b,c,d,t; 00824 //+CGDCONT: <cid>,"IP","<apn name>","<ip adr>",0,0,0,0,0,0 00825 if (sscanf(buf, "+CGDCONT: %d,\"IP\",\"%*[^\"]\",\"" IPSTR "\",%*d,%*d,%*d,%*d,%*d,%*d", &t, &a,&b,&c,&d) == 5) { 00826 if (IPADR(a,b,c,d) != NOIP) 00827 *cid = t; 00828 } 00829 } 00830 return WAIT; 00831 } 00832 00833 MDMParser::IP MDMParser::join(const char* apn /*= NULL*/, const char* username /*= NULL*/, 00834 const char* password /*= NULL*/, Auth auth /*= AUTH_DETECT*/) 00835 { 00836 LOCK(); 00837 INFO("Modem::join\r\n"); 00838 _ip = NOIP; 00839 if (_dev.dev == DEV_LISA_C2) { 00840 // make a dumy dns lookup (which will fail, so ignore the result) 00841 sendFormated("AT+UDNSRN=0,\"u-blox.com\"\r\n"); 00842 waitFinalResp(); 00843 // This fake lookup will enable the IP connection and we 00844 // should have an IP after this, so we check it 00845 00846 //Get local IP address 00847 sendFormated("AT+CMIP?\r\n"); 00848 if (RESP_OK != waitFinalResp(_cbCMIP, &_ip)) 00849 goto failure; 00850 00851 } else { 00852 // check gprs attach status 00853 sendFormated("AT+CGATT=1\r\n"); 00854 if (RESP_OK != waitFinalResp(NULL,NULL,3*60*1000)) 00855 goto failure; 00856 // Check the profile 00857 int a = 0; 00858 bool force = true; 00859 sendFormated("AT+UPSND=" PROFILE ",8\r\n"); 00860 if (RESP_OK != waitFinalResp(_cbUPSND, &a)) 00861 goto failure; 00862 if (a == 1 && force) { 00863 // disconnect the profile already if it is connected 00864 sendFormated("AT+UPSDA=" PROFILE ",4\r\n"); 00865 if (RESP_OK != waitFinalResp(NULL,NULL,40*1000)) 00866 goto failure; 00867 a = 0; 00868 } 00869 if (a == 0) { 00870 bool ok = false; 00871 // try to lookup the apn settings from our local database by mccmnc 00872 const char* config = NULL; 00873 if (!apn && !username && !password) 00874 config = apnconfig(_dev.imsi); 00875 do { 00876 if (config) { 00877 apn = _APN_GET(config); 00878 username = _APN_GET(config); 00879 password = _APN_GET(config); 00880 } 00881 // convert pointer to empty strings 00882 apn = apn ? apn : ""; 00883 username = username ? username : ""; 00884 password = password ? password : ""; 00885 auth = (*username && *password) ? auth : AUTH_NONE; 00886 TRACE("Testing APN Settings(\"%s\",\"%s\",\"%s\",%d)\r\n", apn, username, password, auth); 00887 if ((_dev.dev != DEV_TOBY_L2) && (_dev.dev != DEV_MPCI_L2)) 00888 ok = _activateProfile(apn, username, password, auth); 00889 else { 00890 ok = _activateProfileReuseExternal(); 00891 if (ok) 00892 TRACE("Reusing External Context\r\n"); 00893 else 00894 ok = _activateProfileByCid(1, apn, username, password, auth); 00895 } 00896 } while (!ok && config && *config); // maybe use next setting ? 00897 if (!ok) { 00898 ERROR("Your modem APN/password/username may be wrong\r\n"); 00899 goto failure; 00900 } 00901 } 00902 //Get local IP address 00903 sendFormated("AT+UPSND=" PROFILE ",0\r\n"); 00904 if (RESP_OK != waitFinalResp(_cbUPSND, &_ip)) 00905 goto failure; 00906 } 00907 UNLOCK(); 00908 return _ip; 00909 failure: 00910 unlock(); 00911 return NOIP; 00912 } 00913 00914 int MDMParser::_cbUDOPN(int type, const char* buf, int len, char* mccmnc) 00915 { 00916 if ((type == TYPE_PLUS) && mccmnc) { 00917 if (sscanf(buf, "\r\n+UDOPN: 0,\"%[^\"]\"", mccmnc) == 1) 00918 ; 00919 } 00920 return WAIT; 00921 } 00922 00923 int MDMParser::_cbCMIP(int type, const char* buf, int len, IP* ip) 00924 { 00925 if ((type == TYPE_UNKNOWN) && ip) { 00926 int a,b,c,d; 00927 if (sscanf(buf, "\r\n" IPSTR, &a,&b,&c,&d) == 4) 00928 *ip = IPADR(a,b,c,d); 00929 } 00930 return WAIT; 00931 } 00932 00933 int MDMParser::_cbUPSND(int type, const char* buf, int len, int* act) 00934 { 00935 if ((type == TYPE_PLUS) && act) { 00936 if (sscanf(buf, "\r\n+UPSND: %*d,%*d,%d", act) == 1) 00937 /*nothing*/; 00938 } 00939 return WAIT; 00940 } 00941 00942 int MDMParser::_cbUPSND(int type, const char* buf, int len, IP* ip) 00943 { 00944 if ((type == TYPE_PLUS) && ip) { 00945 int a,b,c,d; 00946 // +UPSND=<profile_id>,<param_tag>[,<dynamic_param_val>] 00947 if (sscanf(buf, "\r\n+UPSND: " PROFILE ",0,\"" IPSTR "\"", &a,&b,&c,&d) == 4) 00948 *ip = IPADR(a,b,c,d); 00949 } 00950 return WAIT; 00951 } 00952 00953 int MDMParser::_cbUDNSRN(int type, const char* buf, int len, IP* ip) 00954 { 00955 if ((type == TYPE_PLUS) && ip) { 00956 int a,b,c,d; 00957 if (sscanf(buf, "\r\n+UDNSRN: \"" IPSTR "\"", &a,&b,&c,&d) == 4) 00958 *ip = IPADR(a,b,c,d); 00959 } 00960 return WAIT; 00961 } 00962 00963 bool MDMParser::disconnect(void) 00964 { 00965 bool ok = false; 00966 LOCK(); 00967 INFO("Modem::disconnect\r\n"); 00968 if (_ip != NOIP) { 00969 if (_dev.dev == DEV_LISA_C2) { 00970 // There something to do here 00971 _ip = NOIP; 00972 ok = true; 00973 } else { 00974 sendFormated("AT+UPSDA=" PROFILE ",4\r\n"); 00975 if (RESP_OK != waitFinalResp()) { 00976 _ip = NOIP; 00977 ok = true; 00978 } 00979 } 00980 } 00981 UNLOCK(); 00982 return ok; 00983 } 00984 00985 MDMParser::IP MDMParser::gethostbyname(const char* host) 00986 { 00987 IP ip = NOIP; 00988 int a,b,c,d; 00989 if (sscanf(host, IPSTR, &a,&b,&c,&d) == 4) 00990 ip = IPADR(a,b,c,d); 00991 else { 00992 LOCK(); 00993 sendFormated("AT+UDNSRN=0,\"%s\"\r\n", host); 00994 if (RESP_OK != waitFinalResp(_cbUDNSRN, &ip)) 00995 ip = NOIP; 00996 UNLOCK(); 00997 } 00998 return ip; 00999 } 01000 01001 // ---------------------------------------------------------------- 01002 // sockets 01003 01004 int MDMParser::_cbUSOCR(int type, const char* buf, int len, int* handle) 01005 { 01006 if ((type == TYPE_PLUS) && handle) { 01007 // +USOCR: socket 01008 if (sscanf(buf, "\r\n+USOCR: %d", handle) == 1) 01009 /*nothing*/; 01010 } 01011 return WAIT; 01012 } 01013 01014 int MDMParser::socketSocket(IpProtocol ipproto, int port) 01015 { 01016 int socket; 01017 LOCK(); 01018 // find an free socket 01019 socket = _findSocket(); 01020 TRACE("socketSocket(%d)\r\n", ipproto); 01021 if (socket != SOCKET_ERROR) { 01022 if (ipproto == IPPROTO_UDP) { 01023 // sending port can only be set on 2G/3G modules 01024 if ((port != -1) && (_dev.dev != DEV_LISA_C2)) { 01025 sendFormated("AT+USOCR=17,%d\r\n", port); 01026 } else { 01027 sendFormated("AT+USOCR=17\r\n"); 01028 } 01029 } else /*(ipproto == IPPROTO_TCP)*/ { 01030 sendFormated("AT+USOCR=6\r\n"); 01031 } 01032 int handle = SOCKET_ERROR; 01033 if ((RESP_OK == waitFinalResp(_cbUSOCR, &handle)) && 01034 (handle != SOCKET_ERROR)) { 01035 TRACE("Socket %d: handle %d was created\r\n", socket, handle); 01036 _sockets[socket].handle = handle; 01037 _sockets[socket].timeout_ms = TIMEOUT_BLOCKING; 01038 _sockets[socket].connected = false; 01039 _sockets[socket].pending = 0; 01040 } 01041 else 01042 socket = SOCKET_ERROR; 01043 } 01044 UNLOCK(); 01045 return socket; 01046 } 01047 01048 bool MDMParser::socketConnect(int socket, const char * host, int port) 01049 { 01050 IP ip = gethostbyname(host); 01051 if (ip == NOIP) 01052 return false; 01053 // connect to socket 01054 bool ok = false; 01055 LOCK(); 01056 if (ISSOCKET(socket) && (!_sockets[socket].connected)) { 01057 TRACE("socketConnect(%d,%s,%d)\r\n", socket,host,port); 01058 sendFormated("AT+USOCO=%d,\"" IPSTR "\",%d\r\n", _sockets[socket].handle, IPNUM(ip), port); 01059 if (RESP_OK == waitFinalResp()) 01060 ok = _sockets[socket].connected = true; 01061 } 01062 UNLOCK(); 01063 return ok; 01064 } 01065 01066 bool MDMParser::socketIsConnected(int socket) 01067 { 01068 bool ok = false; 01069 LOCK(); 01070 ok = ISSOCKET(socket) && _sockets[socket].connected; 01071 TRACE("socketIsConnected(%d) %s\r\n", socket, ok?"yes":"no"); 01072 UNLOCK(); 01073 return ok; 01074 } 01075 01076 bool MDMParser::socketSetBlocking(int socket, int timeout_ms) 01077 { 01078 bool ok = false; 01079 LOCK(); 01080 TRACE("socketSetBlocking(%d,%d)\r\n", socket,timeout_ms); 01081 if (ISSOCKET(socket)) { 01082 _sockets[socket].timeout_ms = timeout_ms; 01083 ok = true; 01084 } 01085 UNLOCK(); 01086 return ok; 01087 } 01088 01089 bool MDMParser::socketClose(int socket) 01090 { 01091 bool ok = false; 01092 LOCK(); 01093 if (ISSOCKET(socket) && _sockets[socket].connected) { 01094 TRACE("socketClose(%d)\r\n", socket); 01095 sendFormated("AT+USOCL=%d\r\n", _sockets[socket].handle); 01096 if (RESP_OK == waitFinalResp()) { 01097 _sockets[socket].connected = false; 01098 ok = true; 01099 } 01100 } 01101 UNLOCK(); 01102 return ok; 01103 } 01104 01105 bool MDMParser::socketFree(int socket) 01106 { 01107 // make sure it is closed 01108 socketClose(socket); 01109 bool ok = true; 01110 LOCK(); 01111 if (ISSOCKET(socket)) { 01112 TRACE("socketFree(%d)\r\n", socket); 01113 _sockets[socket].handle = SOCKET_ERROR; 01114 _sockets[socket].timeout_ms = TIMEOUT_BLOCKING; 01115 _sockets[socket].connected = false; 01116 _sockets[socket].pending = 0; 01117 ok = true; 01118 } 01119 UNLOCK(); 01120 return ok; 01121 } 01122 01123 #define USO_MAX_WRITE 1024 //!< maximum number of bytes to write to socket 01124 01125 int MDMParser::socketSend(int socket, const char * buf, int len) 01126 { 01127 TRACE("socketSend(%d,,%d)\r\n", socket,len); 01128 int cnt = len; 01129 while (cnt > 0) { 01130 int blk = USO_MAX_WRITE; 01131 if (cnt < blk) 01132 blk = cnt; 01133 bool ok = false; 01134 LOCK(); 01135 if (ISSOCKET(socket)) { 01136 sendFormated("AT+USOWR=%d,%d\r\n",_sockets[socket].handle,blk); 01137 if (RESP_PROMPT == waitFinalResp()) { 01138 wait_ms(50); 01139 send(buf, blk); 01140 if (RESP_OK == waitFinalResp()) 01141 ok = true; 01142 } 01143 } 01144 UNLOCK(); 01145 if (!ok) 01146 return SOCKET_ERROR; 01147 buf += blk; 01148 cnt -= blk; 01149 } 01150 return (len - cnt); 01151 } 01152 01153 int MDMParser::socketSendTo(int socket, IP ip, int port, const char * buf, int len) 01154 { 01155 TRACE("socketSendTo(%d," IPSTR ",%d,,%d)\r\n", socket,IPNUM(ip),port,len); 01156 int cnt = len; 01157 while (cnt > 0) { 01158 int blk = USO_MAX_WRITE; 01159 if (cnt < blk) 01160 blk = cnt; 01161 bool ok = false; 01162 LOCK(); 01163 if (ISSOCKET(socket)) { 01164 sendFormated("AT+USOST=%d,\"" IPSTR "\",%d,%d\r\n",_sockets[socket].handle,IPNUM(ip),port,blk); 01165 if (RESP_PROMPT == waitFinalResp()) { 01166 wait_ms(50); 01167 send(buf, blk); 01168 if (RESP_OK == waitFinalResp()) 01169 ok = true; 01170 } 01171 } 01172 UNLOCK(); 01173 if (!ok) 01174 return SOCKET_ERROR; 01175 buf += blk; 01176 cnt -= blk; 01177 } 01178 return (len - cnt); 01179 } 01180 01181 int MDMParser::socketReadable(int socket) 01182 { 01183 int pending = SOCKET_ERROR; 01184 LOCK(); 01185 if (ISSOCKET(socket) && _sockets[socket].connected) { 01186 TRACE("socketReadable(%d)\r\n", socket); 01187 // allow to receive unsolicited commands 01188 waitFinalResp(NULL, NULL, 0); 01189 if (_sockets[socket].connected) 01190 pending = _sockets[socket].pending; 01191 } 01192 UNLOCK(); 01193 return pending; 01194 } 01195 01196 int MDMParser::_cbUSORD(int type, const char* buf, int len, char* out) 01197 { 01198 if ((type == TYPE_PLUS) && out) { 01199 int sz, sk; 01200 if ((sscanf(buf, "\r\n+USORD: %d,%d,", &sk, &sz) == 2) && 01201 (buf[len-sz-2] == '\"') && (buf[len-1] == '\"')) { 01202 memcpy(out, &buf[len-1-sz], sz); 01203 } 01204 } 01205 return WAIT; 01206 } 01207 01208 int MDMParser::socketRecv(int socket, char* buf, int len) 01209 { 01210 int cnt = 0; 01211 TRACE("socketRecv(%d,,%d)\r\n", socket, len); 01212 #ifdef MDM_DEBUG 01213 memset(buf, '\0', len); 01214 #endif 01215 Timer timer; 01216 timer.start(); 01217 while (len) { 01218 int blk = MAX_SIZE; // still need space for headers and unsolicited commands 01219 if (len < blk) blk = len; 01220 bool ok = false; 01221 LOCK(); 01222 if (ISSOCKET(socket)) { 01223 if (_sockets[socket].connected) { 01224 if (_sockets[socket].pending < blk) 01225 blk = _sockets[socket].pending; 01226 if (blk > 0) { 01227 sendFormated("AT+USORD=%d,%d\r\n",_sockets[socket].handle, blk); 01228 if (RESP_OK == waitFinalResp(_cbUSORD, buf)) { 01229 _sockets[socket].pending -= blk; 01230 len -= blk; 01231 cnt += blk; 01232 buf += blk; 01233 ok = true; 01234 } 01235 } else if (!TIMEOUT(timer, _sockets[socket].timeout_ms)) { 01236 ok = (WAIT == waitFinalResp(NULL,NULL,0)); // wait for URCs 01237 } else { 01238 len = 0; 01239 ok = true; 01240 } 01241 } else { 01242 len = 0; 01243 ok = true; 01244 } 01245 } 01246 UNLOCK(); 01247 if (!ok) { 01248 TRACE("socketRecv: ERROR\r\n"); 01249 return SOCKET_ERROR; 01250 } 01251 } 01252 TRACE("socketRecv: %d \"%*s\"\r\n", cnt, cnt, buf-cnt); 01253 return cnt; 01254 } 01255 01256 int MDMParser::_cbUSORF(int type, const char* buf, int len, USORFparam* param) 01257 { 01258 if ((type == TYPE_PLUS) && param) { 01259 int sz, sk, p, a,b,c,d; 01260 int r = sscanf(buf, "\r\n+USORF: %d,\"" IPSTR "\",%d,%d,", 01261 &sk,&a,&b,&c,&d,&p,&sz); 01262 if ((r == 7) && (buf[len-sz-2] == '\"') && (buf[len-1] == '\"')) { 01263 memcpy(param->buf, &buf[len-1-sz], sz); 01264 param->ip = IPADR(a,b,c,d); 01265 param->port = p; 01266 } 01267 } 01268 return WAIT; 01269 } 01270 01271 int MDMParser::socketRecvFrom(int socket, IP* ip, int* port, char* buf, int len) 01272 { 01273 int cnt = 0; 01274 TRACE("socketRecvFrom(%d,,%d)\r\n", socket, len); 01275 #ifdef MDM_DEBUG 01276 memset(buf, '\0', len); 01277 #endif 01278 Timer timer; 01279 timer.start(); 01280 while (len) { 01281 int blk = MAX_SIZE; // still need space for headers and unsolicited commands 01282 if (len < blk) blk = len; 01283 bool ok = false; 01284 LOCK(); 01285 if (ISSOCKET(socket)) { 01286 if (_sockets[socket].pending < blk) 01287 blk = _sockets[socket].pending; 01288 if (blk > 0) { 01289 sendFormated("AT+USORF=%d,%d\r\n",_sockets[socket].handle, blk); 01290 USORFparam param; 01291 param.buf = buf; 01292 if (RESP_OK == waitFinalResp(_cbUSORF, ¶m)) { 01293 _sockets[socket].pending -= blk; 01294 *ip = param.ip; 01295 *port = param.port; 01296 len -= blk; 01297 cnt += blk; 01298 buf += blk; 01299 len = 0; // done 01300 ok = true; 01301 } 01302 } else if (!TIMEOUT(timer, _sockets[socket].timeout_ms)) { 01303 ok = (WAIT == waitFinalResp(NULL,NULL,0)); // wait for URCs 01304 } else { 01305 len = 0; // no more data and socket closed or timed-out 01306 ok = true; 01307 } 01308 } 01309 UNLOCK(); 01310 if (!ok) { 01311 TRACE("socketRecv: ERROR\r\n"); 01312 return SOCKET_ERROR; 01313 } 01314 } 01315 timer.stop(); 01316 timer.reset(); 01317 TRACE("socketRecv: %d \"%*s\"\r\n", cnt, cnt, buf-cnt); 01318 return cnt; 01319 } 01320 01321 int MDMParser::_findSocket(int handle) { 01322 for (int socket = 0; socket < NUMSOCKETS; socket ++) { 01323 if (_sockets[socket].handle == handle) 01324 return socket; 01325 } 01326 return SOCKET_ERROR; 01327 } 01328 01329 // ---------------------------------------------------------------- 01330 // HTTP 01331 01332 int MDMParser::httpFindProfile() 01333 { 01334 int profile = HTTP_PROF_ERROR; //default value 01335 LOCK(); 01336 // find a free HTTP profile 01337 profile = _findProfile(); 01338 TRACE("httpFindProfile: profile is %d\r\n", profile); 01339 if (profile != HTTP_PROF_ERROR) { 01340 _httpProfiles[profile].handle = 1; 01341 _httpProfiles[profile].timeout_ms = TIMEOUT_BLOCKING; 01342 _httpProfiles[profile].pending = false; 01343 _httpProfiles[profile].cmd = -1; 01344 _httpProfiles[profile].result = -1; 01345 } 01346 UNLOCK(); 01347 return profile; 01348 } 01349 01350 int MDMParser::_findProfile(int handle) { 01351 for (int profile = 0; profile < NUMPROFILES; profile++) { 01352 if (_httpProfiles[profile].handle == handle) 01353 return profile; 01354 } 01355 return HTTP_PROF_ERROR; 01356 } 01357 01358 bool MDMParser::httpSetBlocking(int profile, int timeout_ms) 01359 { 01360 bool ok = false; 01361 LOCK(); 01362 TRACE("httpSetBlocking(%d,%d)\r\n", profile, timeout_ms); 01363 if (ISPROFILE(profile)) { 01364 _httpProfiles[profile].timeout_ms = timeout_ms; 01365 ok = true; 01366 } 01367 UNLOCK(); 01368 return ok; 01369 } 01370 01371 bool MDMParser::httpSetProfileForCmdMng(int profile) 01372 { 01373 bool ok = false; 01374 LOCK(); 01375 TRACE("httpSetProfileForCmdMng(%d)\r\n", profile); 01376 if (ISPROFILE(profile)) { 01377 _httpProfiles[profile].pending = true; 01378 _httpProfiles[profile].result = -1; 01379 ok = true; 01380 } 01381 UNLOCK(); 01382 return ok; 01383 } 01384 01385 bool MDMParser::httpFreeProfile(int profile) 01386 { 01387 bool ok = true; 01388 LOCK(); 01389 if (ISPROFILE(profile)) { 01390 TRACE("httpFreeProfile(%d)\r\n", profile); 01391 _httpProfiles[profile].handle = HTTP_PROF_ERROR; 01392 _httpProfiles[profile].timeout_ms = TIMEOUT_BLOCKING; 01393 _httpProfiles[profile].pending = false; 01394 _httpProfiles[profile].cmd = -1; 01395 _httpProfiles[profile].result = -1; 01396 ok = true; 01397 } 01398 UNLOCK(); 01399 return ok; 01400 } 01401 01402 bool MDMParser::httpResetProfile(int httpProfile) 01403 { 01404 bool ok = false; 01405 01406 LOCK(); 01407 TRACE("httpResetProfile(%d)\r\n", httpProfile); 01408 sendFormated("AT+UHTTP=%d\r\n", httpProfile); 01409 if (RESP_OK == waitFinalResp()) 01410 ok = true; 01411 UNLOCK(); 01412 01413 return ok; 01414 } 01415 01416 bool MDMParser::httpSetPar(int httpProfile, HttpOpCode httpOpCode, const char * httpInPar) 01417 { 01418 bool ok = false; 01419 IP ip = NOIP; 01420 int httpInParNum = 0; 01421 01422 LOCK(); 01423 TRACE("httpSetPar(%d,%d,\"%s\")\r\n", httpProfile, httpOpCode, httpInPar); 01424 switch(httpOpCode){ 01425 case HTTP_IP_ADDRESS: //0 01426 ip = gethostbyname(httpInPar); 01427 if (ip == NOIP) 01428 return false; 01429 01430 sendFormated("AT+UHTTP=%d,%d,\"" IPSTR "\"\r\n", httpProfile, httpOpCode, IPNUM(ip)); 01431 if (RESP_OK == waitFinalResp()) 01432 ok = true; 01433 break; 01434 01435 case HTTP_SERVER_NAME: //1 01436 case HTTP_USER_NAME: //2 01437 case HTTP_PASSWORD: //3 01438 sendFormated("AT+UHTTP=%d,%d,\"%s\"\r\n", httpProfile, httpOpCode, httpInPar); 01439 if (RESP_OK == waitFinalResp()) 01440 ok = true; 01441 break; 01442 01443 case HTTP_AUTH_TYPE: //4 01444 case HTTP_PORT: //5 01445 httpInParNum = atoi(httpInPar); 01446 sendFormated("AT+UHTTP=%d,%d,%d\r\n", httpProfile, httpOpCode, httpInParNum); 01447 if (RESP_OK == waitFinalResp()) 01448 ok = true; 01449 break; 01450 01451 case HTTP_SECURE: //6 01452 if(_dev.dev != DEV_LISA_C2) 01453 { 01454 httpInParNum = atoi(httpInPar); 01455 sendFormated("AT+UHTTP=%d,%d,%d\r\n", httpProfile, httpOpCode, httpInParNum); 01456 if (RESP_OK == waitFinalResp()) 01457 ok = true; 01458 } else { 01459 TRACE("httpSetPar: HTTP secure option not supported by module\r\n"); 01460 ok = false; 01461 } 01462 break; 01463 01464 default: 01465 TRACE("httpSetPar: unknown httpOpCode %s\r\n", httpOpCode); 01466 ok = false; 01467 break; 01468 } 01469 UNLOCK(); 01470 return ok; 01471 } 01472 01473 bool MDMParser::httpCommand(int httpProfile, HttpCmd httpCmdCode, const char* httpPath, const char* httpOut, \ 01474 const char* httpIn, int httpContentType, const char* httpCustomPar, char* buf, int len) 01475 { 01476 bool ok = false; 01477 #ifdef MDM_DEBUG 01478 memset(buf, '\0', len); 01479 #endif 01480 LOCK(); 01481 TRACE("%s\r\n", getHTTPcmd(httpCmdCode)); 01482 switch (httpCmdCode) 01483 { 01484 case HTTP_HEAD: 01485 sendFormated("AT+UHTTPC=%d,%d,\"%s\",\"%s\"\r\n", httpProfile, HTTP_HEAD, httpPath, httpOut); 01486 break; 01487 01488 case HTTP_GET: 01489 sendFormated("AT+UHTTPC=%d,%d,\"%s\",\"%s\"\r\n", httpProfile, HTTP_GET, httpPath, httpOut); 01490 break; 01491 01492 case HTTP_DELETE: 01493 sendFormated("AT+UHTTPC=%d,%d,\"%s\",\"%s\"\r\n", httpProfile, HTTP_DELETE, httpPath, httpOut); 01494 break; 01495 01496 case HTTP_PUT: 01497 //in this case the parameter httpIn is a filename 01498 sendFormated("AT+UHTTPC=%d,%d,\"%s\",\"%s\",\"%s\"\r\n", httpProfile, HTTP_PUT, httpPath, httpOut, httpIn); 01499 break; 01500 01501 case HTTP_POST_FILE: 01502 //in this case the parameter httpIn is a filename 01503 if(_dev.dev != DEV_LISA_C2) 01504 { 01505 if(httpContentType != 6) 01506 sendFormated("AT+UHTTPC=%d,%d,\"%s\",\"%s\",\"%s\",%d\r\n", \ 01507 httpProfile, HTTP_POST_FILE, httpPath, httpOut, httpIn, httpContentType); 01508 else 01509 sendFormated("AT+UHTTPC=%d,%d,\"%s\",\"%s\",\"%s\",%d,%d\r\n", \ 01510 httpProfile, HTTP_POST_FILE, httpPath, httpOut, httpIn, httpContentType, httpCustomPar); 01511 } 01512 else{ 01513 if((httpContentType != 5) && (httpContentType != 6) && (httpCustomPar == NULL)) 01514 { 01515 //parameters values consistent with the AT commands specs of LISA-C200 01516 //(in particular httpCustomPar has to be not defined) 01517 sendFormated("AT+UHTTPC=%d,%d,\"%s\",\"%s\",\"%s\",%d\r\n", \ 01518 httpProfile, HTTP_POST_FILE, httpPath, httpOut, httpIn, httpContentType); 01519 } else { 01520 TRACE("httpCommand: command not supported by module"); 01521 return ok; //error 01522 } 01523 } 01524 break; 01525 01526 case HTTP_POST_DATA: 01527 //in this case the parameter httpIn is a string containing data 01528 if(_dev.dev != DEV_LISA_C2) 01529 { 01530 if(httpContentType != 6) 01531 sendFormated("AT+UHTTPC=%d,%d,\"%s\",\"%s\",\"%s\",%d\r\n", \ 01532 httpProfile, HTTP_POST_DATA, httpPath, httpOut, httpIn, httpContentType); 01533 else 01534 sendFormated("AT+UHTTPC=%d,%d,\"%s\",\"%s\",\"%s\",%d,%d\r\n", \ 01535 httpProfile, HTTP_POST_DATA, httpPath, httpOut, httpIn, httpContentType, httpCustomPar); 01536 } else { 01537 if((httpContentType != 5) && (httpContentType != 6) && (httpCustomPar == NULL)) 01538 { 01539 //parameters values consistent with the AT commands specs of LISA-C200 01540 //(in particular httpCustomPar has to be not defined) 01541 sendFormated("AT+UHTTPC=%d,%d,\"%s\",\"%s\",\"%s\",%d\r\n", \ 01542 httpProfile, HTTP_POST_DATA, httpPath, httpOut, httpIn, httpContentType); 01543 } else { 01544 TRACE("httpCommand: command not supported by module"); 01545 return ok; //error 01546 } 01547 } 01548 break; 01549 01550 default: 01551 TRACE("HTTP command not recognized\r\n"); 01552 return ok; //error 01553 } 01554 01555 if (RESP_OK == waitFinalResp()) 01556 { 01557 Timer timer; 01558 timer.start(); 01559 httpSetProfileForCmdMng(httpProfile); 01560 while (_httpProfiles[httpProfile].pending) //waiting for unsolicited 01561 { 01562 ok = false; //reset variable 01563 if(_httpProfiles[httpProfile].result != -1) 01564 { 01565 //received unsolicited: starting its analysis 01566 _httpProfiles[httpProfile].pending = false; 01567 if(_httpProfiles[httpProfile].result == 1) 01568 { 01569 //HTTP command successfully executed 01570 if(_dev.dev != DEV_LISA_C2) 01571 { 01572 TRACE("httpCommand: reading files with a dimension " \ 01573 "also greater than MAX_SIZE bytes\r\n"); 01574 if(readFileNew(httpOut,buf,len) >=0 ) 01575 ok = true; 01576 } else { 01577 TRACE("httpCommand: reading files with a dimension " \ 01578 "less than MAX_SIZE bytes, otherwise error\r\n"); 01579 if(readFile(httpOut,buf,len) >=0 ) 01580 ok = true; 01581 } 01582 } else { 01583 //HTTP command not successfully executed 01584 ok = false; 01585 } 01586 } else if (!TIMEOUT(timer, _httpProfiles[httpProfile].timeout_ms)) { 01587 ok = (WAIT == waitFinalResp(NULL,NULL,0)); // wait for URCs 01588 } else { 01589 //not received unsolicited and expired timer 01590 TRACE("httpCommand: not received unsolicited and expired timer\r\n"); 01591 ok = false; 01592 } 01593 if (!ok) { 01594 TRACE("%s: ERROR\r\n", getHTTPcmd(httpCmdCode)); 01595 _httpProfiles[httpProfile].pending = false; //no more while loops 01596 } 01597 } 01598 } 01599 UNLOCK(); 01600 return ok; 01601 } 01602 01603 const char* MDMParser::getHTTPcmd(int httpCmdCode) 01604 { 01605 switch (httpCmdCode) 01606 { 01607 case HTTP_HEAD: 01608 return "HTTP HEAD command"; 01609 case HTTP_GET: 01610 return "HTTP GET command"; 01611 case HTTP_DELETE: 01612 return "HTTP DELETE command"; 01613 case HTTP_PUT: 01614 return "HTTP PUT command"; 01615 case HTTP_POST_FILE: 01616 return "HTTP POST file command"; 01617 case HTTP_POST_DATA: 01618 return "HTTP POST data command"; 01619 default: 01620 return "HTTP command not recognized"; 01621 } 01622 } 01623 01624 // ---------------------------------------------------------------- 01625 01626 int MDMParser::_cbCMGL(int type, const char* buf, int len, CMGLparam* param) 01627 { 01628 if ((type == TYPE_PLUS) && param && param->num) { 01629 // +CMGL: <ix>,... 01630 int ix; 01631 if (sscanf(buf, "\r\n+CMGL: %d,", &ix) == 1) 01632 { 01633 *param->ix++ = ix; 01634 param->num--; 01635 } 01636 } 01637 return WAIT; 01638 } 01639 01640 int MDMParser::smsList(const char* stat /*= "ALL"*/, int* ix /*=NULL*/, int num /*= 0*/) { 01641 int ret = -1; 01642 LOCK(); 01643 sendFormated("AT+CMGL=\"%s\"\r\n", stat); 01644 CMGLparam param; 01645 param.ix = ix; 01646 param.num = num; 01647 if (RESP_OK == waitFinalResp(_cbCMGL, ¶m)) 01648 ret = num - param.num; 01649 UNLOCK(); 01650 return ret; 01651 } 01652 01653 bool MDMParser::smsSend(const char* num, const char* buf) 01654 { 01655 bool ok = false; 01656 LOCK(); 01657 sendFormated("AT+CMGS=\"%s\"\r\n",num); 01658 if (RESP_PROMPT == waitFinalResp(NULL,NULL,150*1000)) { 01659 send(buf, strlen(buf)); 01660 const char ctrlZ = 0x1A; 01661 send(&ctrlZ, sizeof(ctrlZ)); 01662 ok = (RESP_OK == waitFinalResp()); 01663 } 01664 UNLOCK(); 01665 return ok; 01666 } 01667 01668 bool MDMParser::smsDelete(int ix) 01669 { 01670 bool ok = false; 01671 LOCK(); 01672 sendFormated("AT+CMGD=%d\r\n",ix); 01673 ok = (RESP_OK == waitFinalResp()); 01674 UNLOCK(); 01675 return ok; 01676 } 01677 01678 int MDMParser::_cbCMGR(int type, const char* buf, int len, CMGRparam* param) 01679 { 01680 if (param) { 01681 if (type == TYPE_PLUS) { 01682 if (sscanf(buf, "\r\n+CMGR: \"%*[^\"]\",\"%[^\"]", param->num) == 1) { 01683 } 01684 } else if ((type == TYPE_UNKNOWN) && (buf[len-2] == '\r') && (buf[len-1] == '\n')) { 01685 memcpy(param->buf, buf, len-2); 01686 param->buf[len-2] = '\0'; 01687 } 01688 } 01689 return WAIT; 01690 } 01691 01692 bool MDMParser::smsRead(int ix, char* num, char* buf, int len) 01693 { 01694 bool ok = false; 01695 LOCK(); 01696 CMGRparam param; 01697 param.num = num; 01698 param.buf = buf; 01699 sendFormated("AT+CMGR=%d\r\n",ix); 01700 ok = (RESP_OK == waitFinalResp(_cbCMGR, ¶m)); 01701 UNLOCK(); 01702 return ok; 01703 } 01704 01705 // ---------------------------------------------------------------- 01706 01707 int MDMParser::_cbCUSD(int type, const char* buf, int len, char* resp) 01708 { 01709 if ((type == TYPE_PLUS) && resp) { 01710 // +USD: \"%*[^\"]\",\"%[^\"]\",,\"%*[^\"]\",%d,%d,%d,%d,\"*[^\"]\",%d,%d"..); 01711 if (sscanf(buf, "\r\n+CUSD: %*d,\"%[^\"]\",%*d", resp) == 1) { 01712 /*nothing*/ 01713 } 01714 } 01715 return WAIT; 01716 } 01717 01718 bool MDMParser::ussdCommand(const char* cmd, char* buf) 01719 { 01720 bool ok = false; 01721 LOCK(); 01722 *buf = '\0'; 01723 if (_dev.dev != DEV_LISA_C2) { 01724 sendFormated("AT+CUSD=1,\"%s\"\r\n",cmd); 01725 ok = (RESP_OK == waitFinalResp(_cbCUSD, buf)); 01726 } 01727 UNLOCK(); 01728 return ok; 01729 } 01730 01731 // ---------------------------------------------------------------- 01732 01733 int MDMParser::_cbUDELFILE(int type, const char* buf, int len, void*) 01734 { 01735 if ((type == TYPE_ERROR) && strstr(buf, "+CME ERROR: FILE NOT FOUND")) 01736 return RESP_OK; // file does not exist, so all ok... 01737 return WAIT; 01738 } 01739 01740 bool MDMParser::delFile(const char* filename) 01741 { 01742 bool ok = false; 01743 LOCK(); 01744 sendFormated("AT+UDELFILE=\"%s\"\r\n", filename); 01745 ok = (RESP_OK == waitFinalResp(_cbUDELFILE)); 01746 UNLOCK(); 01747 return ok; 01748 } 01749 01750 int MDMParser::writeFile(const char* filename, const char* buf, int len) 01751 { 01752 bool ok = false; 01753 LOCK(); 01754 sendFormated("AT+UDWNFILE=\"%s\",%d\r\n", filename, len); 01755 if (RESP_PROMPT == waitFinalResp()) { 01756 send(buf, len); 01757 ok = (RESP_OK == waitFinalResp()); 01758 } 01759 UNLOCK(); 01760 return ok ? len : -1; 01761 } 01762 01763 int MDMParser::readFile(const char* filename, char* buf, int len) 01764 { 01765 URDFILEparam param; 01766 param.filename = filename; 01767 param.buf = buf; 01768 param.sz = len; 01769 param.len = 0; 01770 LOCK(); 01771 sendFormated("AT+URDFILE=\"%s\"\r\n", filename, len); 01772 if (RESP_OK != waitFinalResp(_cbURDFILE, ¶m)) 01773 param.len = -1; 01774 UNLOCK(); 01775 return param.len; 01776 } 01777 01778 int MDMParser::_cbURDFILE(int type, const char* buf, int len, URDFILEparam* param) 01779 { 01780 if ((type == TYPE_PLUS) && param && param->filename && param->buf) { 01781 char filename[48]; 01782 int sz; 01783 if ((sscanf(buf, "\r\n+URDFILE: \"%[^\"]\",%d,", filename, &sz) == 2) && 01784 (0 == strcmp(param->filename, filename)) && 01785 (buf[len-sz-2] == '\"') && (buf[len-1] == '\"')) { 01786 param->len = (sz < param->sz) ? sz : param->sz; 01787 memcpy(param->buf, &buf[len-1-sz], param->len); 01788 } 01789 } 01790 return WAIT; 01791 } 01792 01793 //The following function is useful for reading files with a dimension greater than MAX_SIZE bytes 01794 int MDMParser::readFileNew(const char* filename, char* buf, int len) 01795 { 01796 int countBytes = -1; //counter for file reading (default value) 01797 01798 if(_dev.dev != DEV_LISA_C2) 01799 { 01800 //retrieve information about the file, in particular its size 01801 int filesize = infoFile(filename); 01802 TRACE("readFileNew: filename is %s; filesize is %d\r\n", filename, filesize); 01803 01804 if (len < filesize) 01805 TRACE("readFileNew: WARNING. Buffer dimension is %d bytes," \ 01806 "while file size is %d bytes\r\n", len, filesize); 01807 01808 if (filesize > 0) 01809 { 01810 #ifdef MDM_DEBUG 01811 memset(buf, '\0', len); 01812 #endif 01813 int offset = 0; //start reading from 0 01814 int blockSize = MAX_SIZE; //still need space for headers and unsolicited commands 01815 int bytesToRead = filesize; //bytes to read 01816 01817 while (bytesToRead) 01818 { 01819 bool ok = false; 01820 01821 if (bytesToRead < blockSize) 01822 blockSize = bytesToRead; 01823 01824 LOCK(); 01825 if (blockSize > 0) { 01826 01827 sendFormated("AT+URDBLOCK=\"%s\",%d,%d\r\n", filename, offset, blockSize); 01828 01829 if (RESP_OK == waitFinalResp(_cbURDBLOCK, buf)) { 01830 bytesToRead -= blockSize; 01831 offset += blockSize; 01832 buf += blockSize; 01833 ok = true; 01834 } else { 01835 //error condition 01836 countBytes = -1; 01837 ok = false; 01838 } 01839 } 01840 UNLOCK(); 01841 01842 if (!ok) { 01843 TRACE("readFileNew: ERROR\r\n"); 01844 return countBytes; //in this case countBytes is -1 01845 } 01846 } 01847 01848 countBytes = offset; //total read bytes 01849 return countBytes; 01850 } 01851 } else { 01852 TRACE("httpCommand: command not supported by module"); 01853 } 01854 return countBytes; //it could be 0 or -1 (possible error) 01855 } 01856 01857 int MDMParser::_cbURDBLOCK(int type, const char* buf, int len, char* out) 01858 { 01859 char fileNameRes[48]; 01860 int sizeRes; 01861 01862 if ((type == TYPE_PLUS) && out) { 01863 if ((sscanf(buf, "\r\n+URDBLOCK: \"%[^\"]\",%d,", fileNameRes, &sizeRes) == 2) && 01864 (buf[len-sizeRes-2] == '\"') && (buf[len-1] == '\"')) { 01865 memcpy(out, &buf[len-1-sizeRes], sizeRes); 01866 } 01867 } 01868 01869 return WAIT; 01870 } 01871 01872 int MDMParser::infoFile(const char* filename) 01873 { 01874 int infoFile = 0; //default value 01875 01876 LOCK(); 01877 sendFormated("AT+ULSTFILE=2,\"%s\"\r\n", filename); 01878 if (RESP_OK != waitFinalResp(_cbULSTFILE, &infoFile)) 01879 infoFile = -1; //error condition 01880 UNLOCK(); 01881 01882 return infoFile; 01883 } 01884 01885 int MDMParser::_cbULSTFILE(int type, const char* buf, int len, int* infoFile) 01886 { 01887 if (infoFile) { 01888 if (type == TYPE_PLUS) { 01889 if (sscanf(buf, "\r\n+ULSTFILE: %d\r\n", infoFile) == 1) { 01890 } 01891 } 01892 } 01893 return WAIT; 01894 } 01895 01896 // ---------------------------------------------------------------- 01897 01898 int MDMParser::cellLocSrvHttp (const char* token, const char* server_1, const char* server_2, int days/* = 14*/, \ 01899 int period/* = 4*/, int resolution/* = 1*/) 01900 { 01901 bool ok = false; 01902 LOCK(); 01903 if (_dev.dev == DEV_LISA_U2_03S || _dev.dev == DEV_SARA_U2 ){ 01904 sendFormated("AT+UGSRV=\"%s\",\"%s\",\"%s\"\r\n", server_1, server_2, token, days, period, resolution); 01905 ok = (RESP_OK == waitFinalResp()); 01906 } else 01907 ok = false; //command not supported by module 01908 UNLOCK(); 01909 return ok; 01910 } 01911 01912 int MDMParser::cellLocSrvUdp(const char* server_1 /*= "cell-live1.services.u-blox.com"*/, int port /*= 46434*/, \ 01913 int latency/* = 1000*/, int mode/* = 0*/) 01914 { 01915 bool ok = false; 01916 LOCK(); 01917 if (_dev.dev != DEV_TOBY_L2){ 01918 sendFormated("AT+UGAOP=\"%s\",%d,%d,%d\r\n", server_1, port, latency, mode); 01919 ok = (RESP_OK == waitFinalResp()); 01920 } else 01921 ok = false; //command not supported by module 01922 UNLOCK(); 01923 return ok; 01924 } 01925 01926 int MDMParser::cellLocUnsolIndication(int mode) 01927 { 01928 bool ok = false; 01929 LOCK(); 01930 if (_dev.dev == DEV_LISA_U2_03S){ 01931 sendFormated("AT+ULOCIND=%d\r\n", mode); 01932 ok = (RESP_OK == waitFinalResp()); 01933 } else 01934 ok = false; //command not supported by module 01935 UNLOCK(); 01936 return ok; 01937 } 01938 01939 int MDMParser::cellLocConfigSensor(int scanMode) 01940 { 01941 bool ok = false; 01942 LOCK(); 01943 if (_dev.dev != DEV_TOBY_L2){ 01944 sendFormated("AT+ULOCCELL=%d\r\n", scanMode); 01945 ok = (RESP_OK == waitFinalResp()); 01946 }else 01947 ok = false; //command not supported by module 01948 UNLOCK(); 01949 return ok; 01950 } 01951 01952 int MDMParser::cellLocRequest(int sensor, int timeout, int accuracy, int numHypotesis /* =1*/) 01953 { 01954 bool ok = false; 01955 01956 LOCK(); 01957 _loc.validData = false; 01958 if (_dev.dev == DEV_LISA_U2_03S){ 01959 sendFormated("AT+ULOC=2,%d,1,%d,%d,%d\r\n", sensor, timeout, accuracy, numHypotesis); 01960 ok = (RESP_OK == waitFinalResp()); 01961 } else if (_dev.dev != DEV_TOBY_L2){ 01962 sendFormated("AT+ULOC=2,%d,1,%d,%d\r\n", sensor, timeout, accuracy); 01963 ok = (RESP_OK == waitFinalResp()); 01964 } 01965 else ok = false; //command not supported by module 01966 01967 01968 UNLOCK(); 01969 return ok; 01970 } 01971 01972 int MDMParser::cellLocGet(CellLocData *data){ 01973 waitFinalResp(NULL,NULL,0); 01974 if (_loc.validData){ 01975 memcpy(data, &_loc, sizeof(_loc)); 01976 _loc.validData = false; 01977 return true; 01978 } 01979 return false; 01980 } 01981 01982 // ---------------------------------------------------------------- 01983 bool MDMParser::setDebug (int level) 01984 { 01985 #ifdef MDM_DEBUG 01986 _debugLevel = (level < -1) ? -1 : 01987 (level > 3) ? 3 : 01988 level; 01989 #endif 01990 return _debugLevel == level; 01991 } 01992 01993 void MDMParser::dumpDevStatus(MDMParser::DevStatus* status, 01994 _DPRINT dprint, void* param) 01995 { 01996 dprint(param, "Modem::devStatus\r\n"); 01997 const char* txtDev[] = { "Unknown", "SARA-G35", "LISA-U2", "LISA-U2-03S", "LISA-C2", 01998 "SARA-U2", "LEON-G2", "TOBY-L2", "MPCI-L2" }; 01999 if (status->dev < sizeof(txtDev)/sizeof(*txtDev) && (status->dev != DEV_UNKNOWN)) 02000 dprint(param, " Device: %s\r\n", txtDev[status->dev]); 02001 const char* txtLpm[] = { "Disabled", "Enabled", "Active" }; 02002 if (status->lpm < sizeof(txtLpm)/sizeof(*txtLpm)) 02003 dprint(param, " Power Save: %s\r\n", txtLpm[status->lpm]); 02004 const char* txtSim[] = { "Unknown", "Missing", "Pin", "Ready" }; 02005 if (status->sim < sizeof(txtSim)/sizeof(*txtSim) && (status->sim != SIM_UNKNOWN)) 02006 dprint(param, " SIM: %s\r\n", txtSim[status->sim]); 02007 if (*status->ccid) 02008 dprint(param, " CCID: %s\r\n", status->ccid); 02009 if (*status->imei) 02010 dprint(param, " IMEI: %s\r\n", status->imei); 02011 if (*status->imsi) 02012 dprint(param, " IMSI: %s\r\n", status->imsi); 02013 if (*status->meid) 02014 dprint(param, " MEID: %s\r\n", status->meid); // LISA-C 02015 if (*status->manu) 02016 dprint(param, " Manufacturer: %s\r\n", status->manu); 02017 if (*status->model) 02018 dprint(param, " Model: %s\r\n", status->model); 02019 if (*status->ver) 02020 dprint(param, " Version: %s\r\n", status->ver); 02021 } 02022 02023 void MDMParser::dumpNetStatus(MDMParser::NetStatus *status, 02024 _DPRINT dprint, void* param) 02025 { 02026 dprint(param, "Modem::netStatus\r\n"); 02027 const char* txtReg[] = { "Unknown", "Denied", "None", "Home", "Roaming" }; 02028 if (status->csd < sizeof(txtReg)/sizeof(*txtReg) && (status->csd != REG_UNKNOWN)) 02029 dprint(param, " CSD Registration: %s\r\n", txtReg[status->csd]); 02030 if (status->psd < sizeof(txtReg)/sizeof(*txtReg) && (status->psd != REG_UNKNOWN)) 02031 dprint(param, " PSD Registration: %s\r\n", txtReg[status->psd]); 02032 if (status->eps < sizeof(txtReg)/sizeof(*txtReg) && (status->eps != REG_UNKNOWN)) 02033 dprint(param, " EPS Registration: %s\r\n", txtReg[status->eps]); 02034 const char* txtAct[] = { "Unknown", "GSM", "Edge", "3G", "CDMA", "LTE" }; 02035 if (status->act < sizeof(txtAct)/sizeof(*txtAct) && (status->act != ACT_UNKNOWN)) 02036 dprint(param, " Access Technology: %s\r\n", txtAct[status->act]); 02037 if (status->rssi) 02038 dprint(param, " Signal Strength: %d dBm\r\n", status->rssi); 02039 if (status->ber) 02040 dprint(param, " Bit Error Rate: %d\r\n", status->ber); 02041 if (*status->opr) 02042 dprint(param, " Operator: %s\r\n", status->opr); 02043 if (status->lac != 0xFFFF) 02044 dprint(param, " Location Area Code: %04X\r\n", status->lac); 02045 if (status->ci != 0xFFFFFFFF) 02046 dprint(param, " Cell ID: %08X\r\n", status->ci); 02047 if (*status->num) 02048 dprint(param, " Phone Number: %s\r\n", status->num); 02049 } 02050 02051 void MDMParser::dumpIp(MDMParser::IP ip, 02052 _DPRINT dprint, void* param) 02053 { 02054 if (ip != NOIP) 02055 dprint(param, "Modem:IP " IPSTR "\r\n", IPNUM(ip)); 02056 } 02057 02058 // ---------------------------------------------------------------- 02059 int MDMParser::_parseMatch(Pipe<char> * pipe, int len, const char* sta, const char* end) 02060 { 02061 int o = 0; 02062 if (sta) { 02063 while (*sta) { 02064 if (++o > len) return WAIT; 02065 char ch = pipe->next(); 02066 if (*sta++ != ch) return NOT_FOUND; 02067 } 02068 } 02069 if (!end) return o; // no termination 02070 // at least any char 02071 if (++o > len) return WAIT; 02072 pipe->next(); 02073 // check the end 02074 int x = 0; 02075 while (end[x]) { 02076 if (++o > len) return WAIT; 02077 char ch = pipe->next(); 02078 x = (end[x] == ch) ? x + 1 : 02079 (end[0] == ch) ? 1 : 02080 0; 02081 } 02082 return o; 02083 } 02084 02085 int MDMParser::_parseFormated(Pipe<char> * pipe, int len, const char* fmt) 02086 { 02087 int o = 0; 02088 int num = 0; 02089 if (fmt) { 02090 while (*fmt) { 02091 if (++o > len) return WAIT; 02092 char ch = pipe->next(); 02093 if (*fmt == '%') { 02094 fmt++; 02095 if (*fmt == 'd') { // numeric 02096 fmt ++; 02097 num = 0; 02098 while (ch >= '0' && ch <= '9') { 02099 num = num * 10 + (ch - '0'); 02100 if (++o > len) return WAIT; 02101 ch = pipe->next(); 02102 } 02103 } 02104 else if (*fmt == 'c') { // char buffer (takes last numeric as length) 02105 fmt ++; 02106 while (num --) { 02107 if (++o > len) return WAIT; 02108 ch = pipe->next(); 02109 } 02110 } 02111 else if (*fmt == 's') { 02112 fmt ++; 02113 if (ch != '\"') return NOT_FOUND; 02114 do { 02115 if (++o > len) return WAIT; 02116 ch = pipe->next(); 02117 } while (ch != '\"'); 02118 if (++o > len) return WAIT; 02119 ch = pipe->next(); 02120 } 02121 } 02122 if (*fmt++ != ch) return NOT_FOUND; 02123 } 02124 } 02125 return o; 02126 } 02127 02128 int MDMParser::_getLine(Pipe<char> * pipe, char* buf, int len) 02129 { 02130 int unkn = 0; 02131 int sz = pipe->size(); 02132 int fr = pipe->free(); 02133 if (len > sz) 02134 len = sz; 02135 while (len > 0) 02136 { 02137 static struct { 02138 const char* fmt; int type; 02139 } lutF[] = { 02140 { "\r\n+USORD: %d,%d,\"%c\"", TYPE_PLUS }, 02141 { "\r\n+USORF: %d,\"" IPSTR "\",%d,%d,\"%c\"", TYPE_PLUS }, 02142 { "\r\n+URDFILE: %s,%d,\"%c\"", TYPE_PLUS }, 02143 { "\r\n+URDBLOCK: %s,%d,\"%c\"", TYPE_PLUS }, 02144 }; 02145 static struct { 02146 const char* sta; const char* end; int type; 02147 } lut[] = { 02148 { "\r\nOK\r\n", NULL, TYPE_OK }, 02149 { "\r\nERROR\r\n", NULL, TYPE_ERROR }, 02150 { "\r\n+CME ERROR:", "\r\n", TYPE_ERROR_CME }, 02151 { "\r\n+CMS ERROR:", "\r\n", TYPE_ERROR }, 02152 { "\r\nRING\r\n", NULL, TYPE_RING }, 02153 { "\r\nCONNECT\r\n", NULL, TYPE_CONNECT }, 02154 { "\r\nNO CARRIER\r\n", NULL, TYPE_NOCARRIER }, 02155 { "\r\nNO DIALTONE\r\n", NULL, TYPE_NODIALTONE }, 02156 { "\r\nBUSY\r\n", NULL, TYPE_BUSY }, 02157 { "\r\nNO ANSWER\r\n", NULL, TYPE_NOANSWER }, 02158 { "\r\n+", "\r\n", TYPE_PLUS }, 02159 { "\r\n@", NULL, TYPE_PROMPT }, // Sockets 02160 { "\r\n>", NULL, TYPE_PROMPT }, // SMS 02161 { "\n>", NULL, TYPE_PROMPT }, // File 02162 }; 02163 for (int i = 0; i < sizeof(lutF)/sizeof(*lutF); i ++) { 02164 pipe->set(unkn); 02165 int ln = _parseFormated(pipe, len, lutF[i].fmt); 02166 if (ln == WAIT && fr) 02167 return WAIT; 02168 if ((ln != NOT_FOUND) && (unkn > 0)) 02169 return TYPE_UNKNOWN | pipe->get (buf, unkn); 02170 if (ln > 0) 02171 return lutF[i].type | pipe->get (buf, ln); 02172 } 02173 for (int i = 0; i < sizeof(lut)/sizeof(*lut); i ++) { 02174 pipe->set(unkn); 02175 int ln = _parseMatch(pipe, len, lut[i].sta, lut[i].end); 02176 if (ln == WAIT && fr) 02177 return WAIT; 02178 if ((ln != NOT_FOUND) && (unkn > 0)) 02179 return TYPE_UNKNOWN | pipe->get (buf, unkn); 02180 if (ln > 0) 02181 return lut[i].type | pipe->get (buf, ln); 02182 } 02183 // UNKNOWN 02184 unkn ++; 02185 len--; 02186 } 02187 return WAIT; 02188 } 02189 02190 // ---------------------------------------------------------------- 02191 // Serial Implementation 02192 // ---------------------------------------------------------------- 02193 02194 /*! Helper Dev Null Device 02195 Small helper class used to shut off stderr/stdout. Sometimes stdin/stdout 02196 is shared with the serial port of the modem. Having printfs inbetween the 02197 AT commands you cause a failure of the modem. 02198 */ 02199 class DevNull : public Stream { 02200 public: 02201 DevNull() : Stream(_name+1) { } //!< Constructor 02202 void claim(const char* mode, FILE* file) 02203 { freopen(_name, mode, file); } //!< claim a stream 02204 protected: 02205 virtual int _getc() { return EOF; } //!< Nothing 02206 virtual int _putc(int c) { return c; } //!< Discard 02207 static const char* _name; //!< File name 02208 }; 02209 const char* DevNull::_name = "/null"; //!< the null device name 02210 static DevNull null; //!< the null device 02211 02212 MDMSerial::MDMSerial(PinName tx /*= MDMTXD*/, PinName rx /*= MDMRXD*/, 02213 int baudrate /*= MDMBAUD*/, 02214 #if DEVICE_SERIAL_FC 02215 PinName rts /*= MDMRTS*/, PinName cts /*= MDMCTS*/, 02216 #endif 02217 int rxSize /*= 256*/, int txSize /*= 128*/) : 02218 SerialPipe(tx, rx, rxSize, txSize) 02219 { 02220 if (rx == USBRX) 02221 null.claim("r", stdin); 02222 if (tx == USBTX) { 02223 null.claim("w", stdout); 02224 null.claim("w", stderr); 02225 #ifdef MDM_DEBUG 02226 _debugLevel = -1; 02227 #endif 02228 } 02229 #ifdef TARGET_UBLOX_C027 02230 _onboard = (tx == MDMTXD) && (rx == MDMRXD); 02231 if (_onboard) 02232 c027_mdm_powerOn(false); 02233 #endif 02234 baud(baudrate); 02235 #if DEVICE_SERIAL_FC 02236 if ((rts != NC) || (cts != NC)) 02237 { 02238 Flow flow = (cts == NC) ? RTS : 02239 (rts == NC) ? CTS : RTSCTS ; 02240 set_flow_control(flow, rts, cts); 02241 if (cts != NC) _dev.lpm = LPM_ENABLED; 02242 } 02243 #endif 02244 } 02245 02246 MDMSerial::~MDMSerial(void) 02247 { 02248 powerOff(); 02249 #ifdef TARGET_UBLOX_C027 02250 if (_onboard) 02251 c027_mdm_powerOff(); 02252 #endif 02253 } 02254 02255 int MDMSerial::_send(const void* buf, int len) 02256 { 02257 return put((const char*)buf, len, true/*=blocking*/); 02258 } 02259 02260 int MDMSerial::getLine(char* buffer, int length) 02261 { 02262 return _getLine(&_pipeRx, buffer, length); 02263 } 02264 02265 // ---------------------------------------------------------------- 02266 // USB Implementation 02267 // ---------------------------------------------------------------- 02268 02269 #ifdef HAVE_MDMUSB 02270 MDMUsb::MDMUsb(void) 02271 { 02272 #ifdef MDM_DEBUG 02273 _debugLevel = 1; 02274 #endif 02275 #ifdef TARGET_UBLOX_C027 02276 _onboard = true; 02277 c027_mdm_powerOn(true); 02278 #endif 02279 } 02280 02281 MDMUsb::~MDMUsb(void) 02282 { 02283 powerOff(); 02284 #ifdef TARGET_UBLOX_C027 02285 if (_onboard) 02286 c027_mdm_powerOff(); 02287 #endif 02288 } 02289 02290 int MDMUsb::_send(const void* buf, int len) { return 0; } 02291 02292 int MDMUsb::getLine(char* buffer, int length) { return NOT_FOUND; } 02293 02294 #endif
Generated on Tue Jul 12 2022 14:13:15 by
1.7.2
