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