Coap
Fork of C027_Support by
Diff: MDM.cpp
- Revision:
- 21:c4d64830bf02
- Parent:
- 19:2b5d097ca15d
- Child:
- 22:29322c22577e
--- a/MDM.cpp Mon Mar 24 07:38:05 2014 +0000 +++ b/MDM.cpp Tue Apr 08 09:15:37 2014 +0000 @@ -2,68 +2,847 @@ #include <ctype.h> #include "MDM.h" +#define TRACE (1)?:printf +//#define DEBUG +#define PROFILE "0" // this is the psd profile used +#define MAX_SIZE 256 // max expected messages +// some helper +#define ISSOCKET(s) (((s) >= 0) && ((s) < (sizeof(_sockets)/sizeof(*_sockets)))) +#define IPSTR "%d.%d.%d.%d" +#define IPNUM(addr) (addr>>24)&0xff, (addr>>16)&0xff, (addr>>8)&0xff, addr&0xff +#define IPADR(a,b,c,d) ((a<<24) | (b<<16) | (c<<8) | d) + +#ifdef DEBUG +void dump(const char* buf, int len) +{ + while (len --) { + char ch = *buf++; + if (ch == '\r') printf("\\r"); + else if (ch == '\n') printf("\\n"); + else if (ch >= 0x20) printf("%c", ch); + else printf("\\x%02x", ch); + } +} +#endif + +MDMParser::MDMParser(void) +{ + _model = MODEL_UNKNOWN; + _sim = SIM_UNKNOWN; + _net = NET_UNKNOWN; + _ip = 0; + _rssi = 0; + for (int socket = 0; socket < sizeof(_sockets)/sizeof(*_sockets); socket++) { + _sockets[socket].state = SOCK_FREE; + _sockets[socket].pending = 0; + } +} int MDMParser::send(const char* buf, int len) { +#ifdef DEBUG + printf(" send \""); + dump(buf,len); + printf("\"\n"); +#endif return _send(buf, len); } -int MDMParser::_getLine(Pipe<char>* pipe, char* buffer, int length) -{ - int o = 0; - int i = 0; - int l = pipe->start(); - while ((i < l) && (o < length)) - { - int t = pipe->next(); - i ++; - if (t == '\r') // terminate commands with carriage return +int MDMParser::sendFormated(const char* format, ...) { + char buf[MAX_SIZE]; + va_list args; + va_start(args, format); + int len = vsnprintf(buf,sizeof(buf), format, args); + va_end(args); + return send(buf, len); +} + +int MDMParser::waitFinalResp(_CB cb /*= NULL*/, void* param /*= NULL*/, int timeout_ms /*= 5000*/) { + char buf[MAX_SIZE]; + Timer timer; + timer.start(); + do { + int ret = getLine(buf, sizeof(buf)); +#ifdef DEBUG + if ((ret != WAIT) && (ret != NOT_FOUND)) + { + printf(" line %06X \"", ret); + dump(buf, LENGTH(ret)); + printf("\"\n"); + } +#endif + if ((ret != WAIT) && (ret != NOT_FOUND)) { - pipe->done(); - if (length > o) - buffer[o] = '\0'; - return o; // if enter send the zero char + int type = TYPE(ret); + if (type == TYPE_OK) return OK; + if (type == TYPE_ERROR) return ERROR; + if (type == TYPE_PROMPT) return PROMPT; + // handle unsolicited commands here + if (type == TYPE_PLUS) { + const char* cmd = buf+3; + int a, b, c, d; + char s[8]; + + // +CSQ: <rssi>,<qual> + if (sscanf(cmd, "CSQ: %d,%d",&a,&b) == 2) { + if (a != 99) _rssi = -113 - 2*a; // 0: -113 1: -111 ... 30: -53 dBm with 2 dBm steps + //if (b != 99) int qual = b; // + // Socket Specific Command --------------------------------- + // +UUSORD: <socket>,<length> + } else if ((sscanf(cmd, "UUSORD: %d,%d", &a, &b) == 2) && + ISSOCKET(a) && (_sockets[a].state == SOCK_CONNECTED)) { + TRACE("Socket %d: %d bytes pending\n", a, b); + _sockets[a].pending = b; + // +UUSORF: <socket>,<length> + } else if ((sscanf(cmd, "UUSORF: %d,%d", &a, &b) == 2) && + ISSOCKET(a) && (_sockets[a].state == SOCK_CONNECTED)) { + TRACE("Socket %d: %d bytes pending\n", a, b); + _sockets[a].pending = b; + // +UUSOCL: <socket> + } else if ((sscanf(cmd, "UUSOCL: %d", &a) == 1) && + ISSOCKET(a) && (_sockets[a].state == SOCK_CONNECTED)) { + TRACE("Socket %d: closed by remote host\n", a); + _sockets[a].state = SOCK_CREATED/*=CLOSED*/; + } + if (_model == MODEL_LISA_C200) { + // CDMA Specific ------------------------------------------- + // +CREG: <n><SID>,<NID>,<stat> + if (sscanf(cmd, "CREG: %*d,%*d,%*d,%d",&a) == 1) { + if (a == 0) _net = NET_NONE; // not registered, home network + else if (a == 1) _net = NET_HOME; // registered, home network + else if (a == 2) _net = NET_NONE; // not registered, but MT is currently searching a new operator to register to + else if (a == 3) _net = NET_DENIED; // registration denied + else if (a == 5) _net = NET_ROAMING; // registered, roaming + // +CSS: <mode>[,<format>,<oper>[,<AcT>]] + } else if (sscanf(cmd, "CSS %*c,%2s,%*d",s) == 1) { + //_net = (strcmp("Z", s) == 0) ? NET_UNKNOWN : NET_HOME; + // +CMIP: xxx.xxx.xxx.xxx + } else if (sscanf(cmd, "CMIP: " IPSTR, &a,&b,&c,&d) == 4) { + _ip = IPADR(a,b,c,d); + } + } else { + // GSM/UMTS Specific ------------------------------------------- + // +CREG: <n>, <stat>[,<lac>,<ci>[,AcT]] + b = 255; + if (sscanf(cmd, "CREG: %*d,%d,%*d,%d",&a,&b) >= 1) { + // network status + if (a == 0) _net = NET_NONE; // 0: not registered, home network + else if (a == 1) _net = NET_HOME; // 1: registered, home network + else if (a == 2) _net = NET_NONE; // 2: not registered, but MT is currently searching a new operator to register to + else if (a == 3) _net = NET_DENIED; // 3: registration denied + else if (a == 4) _net = NET_UNKNOWN; // 4: unknown + else if (a == 5) _net = NET_ROAMING; // 5: registered, roaming + // access technology + if (b == 0) ; // 0: GSM + else if (b == 1) ; // 1: GSM COMPACT + else if (b == 2) ; // 2: UTRAN + else if (b == 3) ; // 3: GSM with EDGE availability + else if (b == 4) ; // 4: UTRAN with HSDPA availability + else if (b == 5) ; // 5: UTRAN with HSUPA availability + else if (b == 6) ; // 6: UTRAN with HSDPA and HSUPA availability + // +COPS: <mode>[,<format>,<oper>[,<AcT>]] + } else if (sscanf(cmd, "COPS: %*d,%*d,\"%*[^\"]\",%d",&a) == 1) { + // if (a == 0) ; // 0: GSM, + // else if (a == 2) ; // 2: UTRAN + // +CPIN: <code> + } else if (sscanf(cmd, "CPIN: %8s",s) == 1) { + _sim = (strcmp("READY", s) == 0) ? SIM_READY : SIM_UNKNOWN; + // +UPSND=<profile_id>,<param_tag>[,<dynamic_param_val>] + } else if (sscanf(cmd, "UPSND: " PROFILE ",0,\"" IPSTR "\"", &a,&b,&c,&d) == 4) { + _ip = IPADR(a,b,c,d); + // +UUPSDD: <profile_id> + } else if (sscanf(cmd, "UUPSDD: %d",&a) == 1) { + if (*PROFILE == a) _ip = 0; + } + } + } + if (cb) { + int len = LENGTH(ret); + int ret = cb(type, buf, len, param); + if (WAIT != ret) + return ret; + } + } + // relax a bit + wait_ms(10); + } + while (timer.read_ms() < timeout_ms); + timer.stop(); + timer.reset(); + return WAIT; +} + +// ---------------------------------------------------------------- + +int MDMParser::_cbATI(int type, const char* buf, int len, Model* model) +{ + if ((type == TYPE_UNKNOWN) && model) { + if (strstr(buf, "SARA-G350")) { + *model = MODEL_SARA_G350; + } else if (strstr(buf, "LISA-U200")) { + *model = MODEL_LISA_U200; + } else if (strstr(buf, "LISA-C200")) { + *model= MODEL_LISA_C200; + } + } + return WAIT; +} + +bool MDMParser::init(const char* pin) +{ + for(int i = 0; i < 5; i++) { + // check interface and disable local echo + sendFormated("AT\r\n"); + if(OK == waitFinalResp()) + break; + } + // echo off + sendFormated("AT E0\r\n"); + if(OK != waitFinalResp()) + return false; + // enable verbose error messages + sendFormated("AT+CMEE=2\r\n"); + if(OK != waitFinalResp()) + return false; + // set baud rate + sendFormated("AT+IPR=115200\r\n"); + if (OK != waitFinalResp()) + return false; + wait_ms(40); + // disable flow control + sendFormated("AT&K0\r\n"); + if (OK != waitFinalResp()) + return false; + // identify the module + sendFormated("ATI\r\n"); + if (OK != waitFinalResp((_CB)_cbATI, &_model)) + return false; + if (_model == MODEL_UNKNOWN) + return false; + // model specific init + if (_model == MODEL_LISA_C200) { + // Return the pseudo ESN or MEID + sendFormated("AT+GSN\r\n"); + if (OK != waitFinalResp()) + return false; + } else { + // enable power saving + sendFormated("AT+UPSV=1\r\n"); + if (OK != waitFinalResp()) + return false; + // enable the network identification feature + if (_model == MODEL_LISA_U200) { + sendFormated("AT+UGPIOC=20,2\r\n"); + if (OK != waitFinalResp()) + return false; + } else { + sendFormated("AT+UGPIOC=16,2\r\n"); + if (OK != waitFinalResp()) + return false; + } + // Enter PIN if needed + if (pin) { + sendFormated("AT+CPIN=%s\r\n", pin); + if (OK != waitFinalResp()) + return false; } - else if (t == '\n') // skip/filter new line - /* skip */; - else if (t != '\b') // normal char (no backspace) - buffer[o++] = t; - else if (o > 0) // backspace - o --; // remove it + // check the sim card + for (int i = 0; i < 5; i++) { + sendFormated("AT+CPIN?\r\n"); + int ret = waitFinalResp(); + if ((OK != ret) && (ERROR != ret)) + return false; + if (_sim != SIM_UNKNOWN) + break; + wait_ms(1000); + } + if (_sim != SIM_READY) + return false; + // Returns the ICCID (Integrated Circuit Card ID) of the SIM-card. + // ICCID is a serial number identifying the SIM. + sendFormated("AT+CCID\r\n"); + if (OK != waitFinalResp()) + return false; + // Returns the product serial number, IMEI (International Mobile Equipment Identity) + sendFormated("AT+CGSN\r\n"); + if (OK != waitFinalResp()) + return false; + // Setup SMS in text mode + sendFormated("AT+CMGF=1\r\n"); + if (OK != waitFinalResp()) + return false; + // Configure New message indication + //sendFormated("AT+CNMI=2,1,0,0,0\r\n"); + //if (OK != waitFinalResp()) + // return false; + + } + // Request IMSI (International Mobile Subscriber Identification) + sendFormated("AT+CIMI\r\n"); + if (OK != waitFinalResp()) + return false; + return true; +} + +bool MDMParser::checkNetStatus(void) +{ + // check registration + sendFormated("AT+CREG?\r\n"); + if (OK != waitFinalResp()) + return false; + if ((_net != NET_ROAMING) && (_net != NET_HOME)) + return false; + // check modem specific status messages + if (_model == MODEL_LISA_C200) { + sendFormated("AT+CSS?\r\n"); + if (OK != waitFinalResp()) + return false; + if ((_net != NET_ROAMING) && (_net != NET_HOME)) + return false; + } else { + // check operator selection + sendFormated("AT+COPS?\r\n"); + if (OK != waitFinalResp()) + return false; + // Returns the MSISDNs related to this subscriber + sendFormated("AT+CNUM\r\n"); + if (OK != waitFinalResp()) + return false; + } + // Returns the signal strength indication + sendFormated("AT+CSQ\r\n"); + if (OK != waitFinalResp()) + return false; + return true; +} + +bool MDMParser::powerOff(void) +{ + sendFormated("AT+CPWROFF\r\n"); + if (OK != waitFinalResp(NULL,NULL,120)) + return false; + return true; +} + +// ---------------------------------------------------------------- +// internet connection + +IP MDMParser::strToIp(const char* str) +{ + IP ip = 0; + char* p = (char*)str; + for(int i = 0; i < 4; i++) { + ip |= atoi(p); + p = strchr(p, '.'); + if (p == NULL) { + break; + } + ip <<= 8; + p++; } - o = 0; - if (length > 0) - buffer[0] = '\0'; + return ip; +} + +bool MDMParser::join(const char* apn, const char* user /*= NULL*/, const char* password /*= NULL*/) +{ + if (_model == MODEL_LISA_C200) { +#ifdef TODO // TODO implement + // enable the + sendFormated("AT$QCMIPEP=1\r\n"); + if (OK != waitFinalResp()) + return false; + //Get local IP address + sendFormated("AT+CMIP?\r\n"); + if (OK != waitFinalResp()) + return false; +#endif + } else { + // check gprs attach status + sendFormated("AT+CGATT?\r\n"); + if (OK != waitFinalResp()) + return false; + // Set up the APN + if (apn) { + sendFormated("AT+UPSD=" PROFILE ",1,\"%s\"\r\n", apn); + if (OK != waitFinalResp()) + return false; + } + if (user) { + sendFormated("AT+UPSD=" PROFILE ",2,\"%s\"\r\n", user); + if (OK != waitFinalResp()) + return false; + } + if (password) { + sendFormated("AT+UPSD=" PROFILE ",3,\"%s\"\r\n", password); + if (OK != waitFinalResp()) + return false; + } + // Set up the dynamic IP address assignment. + sendFormated("AT+UPSD=" PROFILE ",7,\"0.0.0.0\"\r\n"); + if (OK != waitFinalResp()) + return false; + // Activate the profile and make connection + sendFormated("AT+UPSDA=" PROFILE ",3\r\n"); + if (OK != waitFinalResp()) + return false; + //Get local IP address + sendFormated("AT+UPSND=" PROFILE ",0\r\n"); + if (OK != waitFinalResp()) + return false; + } + if (!_ip) + return false; + printf("Got IP address: " IPSTR "\n", IPNUM(_ip)); + return true; +} + +bool MDMParser::disconnect(void) +{ + if (_ip == 0) + return true; + if (_model == MODEL_LISA_C200) { +#ifdef TODO // TODO implement + sendFormated("AT$QCMIPEP=0\r\n"); +#endif + } else { + sendFormated("AT+UPSDA=" PROFILE ",4\r\n"); + } + if (OK != waitFinalResp()) + return false; + _ip = 0; + return true; +} + +int MDMParser::_cbUDNSRN(int type, const char* buf, int len, IP* ip) +{ + if ((type == TYPE_PLUS) && ip) { + buf += 3; + int a,b,c,d; + if (sscanf(buf, "UDNSRN: \""IPSTR"\"", &a,&b,&c,&d) == 4) + *ip = IPADR(a,b,c,d); + } return WAIT; } -int MDMParser::_getResp(Pipe<char>* pipe, char* buffer, int length) +bool MDMParser::gethostbyname(const char* host, IP* ip) +{ + char ipstr[16]; + IP addr = strToIp(host); + *ip = 0; + snprintf(ipstr, sizeof(ipstr), IPSTR, IPNUM(addr)); + if (strcmp(ipstr, host) == 0) { + *ip = addr; + return true; + } + sendFormated("AT+UDNSRN=0,\"%s\"\r\n", host); + if (OK != waitFinalResp((_CB)_cbUDNSRN, ip)) + return false; + return *ip != 0; +} + +// ---------------------------------------------------------------- +// sockets + +int MDMParser::_cbUSOCR(int type, const char* buf, int len, int* socket) +{ + if ((type == TYPE_PLUS) && socket) { + const char* p = strstr(buf,"+USOCR: "); + if (p) + *socket = atoi(p+8); + } + return WAIT; +} + +int MDMParser::socketSocket(IpProtocol ipproto) +{ + const char* cmd; + if(ipproto == IPPROTO_TCP) { + cmd = "AT+USOCR=6\r\n"; + } else if(ipproto == IPPROTO_UDP) { + cmd = "AT+USOCR=17\r\n"; + } else { // other types not supported + return SOCKET_ERROR; + } + sendFormated(cmd); + int socket = -1; + if (OK != waitFinalResp((_CB)_cbUSOCR, &socket)) + return SOCKET_ERROR; + if (!ISSOCKET(socket) || (_sockets[socket].state != SOCK_FREE)) + return SOCKET_ERROR; + // successfull + _sockets[socket].state = SOCK_CREATED; + _sockets[socket].pending = 0; + return socket; +} + +bool MDMParser::socketConnect(int socket, const char * host, int port) +{ + IP ip; + if (!gethostbyname(host, &ip)) + return false; + // connect to socket + if (!ISSOCKET(socket) || (_sockets[socket].state != SOCK_CREATED)) + return false; + sendFormated("AT+USOCO=%d,\"" IPSTR "\",%d\r\n", socket, IPNUM(ip), port); + if (OK != waitFinalResp()) + return false; + _sockets[socket].state = SOCK_CONNECTED; + return true; +} + +bool MDMParser::socketClose(int socket) +{ + if (!ISSOCKET(socket) || (_sockets[socket].state != SOCK_CONNECTED)) + return false; + sendFormated("AT+USOCL=%d\r\n", socket); + if (OK != waitFinalResp()) + return false; + return true; +} + +bool MDMParser::socketFree(int socket) +{ + socketClose(socket); + if (!ISSOCKET(socket) || (_sockets[socket].state != SOCK_CREATED)) + return false; + _sockets[socket].state = SOCK_FREE; + return true; +} + +int MDMParser::socketSend(int socket, const char * buf, int len) +{ + if(len > 0) { + sendFormated("AT+USOWR=%d,%d\r\n",socket,len); + if (PROMPT != waitFinalResp()) + return SOCKET_ERROR; + wait_ms(50); + send(buf, len); + if (OK != waitFinalResp()) + return SOCKET_ERROR; + } + return len; +} + +int MDMParser::socketSendTo(int socket, IP ip, int port, const char * buf, int len) +{ + if(len > 0) { + sendFormated("AT+USOWR=%d,\"" IPSTR "\",%d,%d\r\n",socket,IPNUM(ip),port,len); + if (PROMPT != waitFinalResp()) + return SOCKET_ERROR; + wait_ms(50); + send(buf, len); + if (OK != waitFinalResp()) + return SOCKET_ERROR; + } + return len; +} + +int MDMParser::socketReadable(int socket) +{ + if (!ISSOCKET(socket) || (_sockets[socket].state != SOCK_CONNECTED)) + return SOCKET_ERROR; + // allow to receive unsolicited commands + waitFinalResp(NULL, NULL, 0); + if (_sockets[socket].state != SOCK_CONNECTED) + return SOCKET_ERROR; + return _sockets[socket].pending; +} + +int MDMParser::_cbUSORD(int type, const char* buf, int len, char* out) +{ + if ((type == TYPE_PLUS) && out) { + int sz, sk; + if ((sscanf(buf, "\r\n+USORD: %d,%d,", &sk, &sz) == 2) && + (buf[len-sz-2] == '\"') && (buf[len-1] == '\"')) { + memcpy(out, &buf[len-1-sz], sz); + } + } + return WAIT; +} + +int MDMParser::socketRecv(int socket, char* buf, int len) +{ + int cnt = 0; + if (!ISSOCKET(socket)) + return SOCKET_ERROR; + memset(buf, '\0', len); + while (len) { + int blk = MAX_SIZE - 64; // still need space for headers and unsolicited commands + if (_sockets[socket].state != SOCK_CONNECTED) + return cnt ? cnt : SOCKET_ERROR; + if (_sockets[socket].pending < blk) + blk = _sockets[socket].pending; + if (len < blk) blk = len; + if (blk) { + sendFormated("AT+USORD=%d,%d\r\n",socket, blk); + if (OK != waitFinalResp((_CB)_cbUSORD, buf)) { + return cnt ? cnt : SOCKET_ERROR; + } + len -= blk; + cnt += blk; + buf += blk; + _sockets[socket].pending -= blk; + } else { + // allow to receive unsolicited commands + waitFinalResp(NULL, NULL, 10); + } + } + return cnt; +} + +int MDMParser::_cbUSORF(int type, const char* buf, int len, USORFparam* param) +{ + if ((type == TYPE_PLUS) && param) { + int sz, sk, p, a,b,c,d; + if ((sscanf(buf, "\r\n+USORF: %d,\""IPSTR"\",%d,%d,", + &sk,&a,&b,&c,&d,&p,&sz) == 7) && + (buf[len-sz-2] == '\"') && (buf[len-1] == '\"')) { + memcpy(param->buf, &buf[len-1-sz], sz); + param->ip = IPADR(a,b,c,d); + param->port = p; + } + } + return WAIT; +} + +int MDMParser::socketRecvFrom(int socket, char* buf, int len, IP* ip) +{ + int cnt = 0; + if (!ISSOCKET(socket)) + return SOCKET_ERROR; + memset(buf, '\0', len); + while (len) { + int blk = MAX_SIZE - 64; // still need space for headers and unsolicited commands + if (_sockets[socket].state != SOCK_CONNECTED) + return cnt ? cnt : SOCKET_ERROR; + if (_sockets[socket].pending < blk) + blk = _sockets[socket].pending; + if (len < blk) blk = len; + if (blk) { + sendFormated("AT+USORF=%d,%d\r\n",socket, blk); + USORFparam param; + param.buf = buf; + if (OK != waitFinalResp((_CB)_cbUSORF, ¶m)) { + return cnt ? cnt : SOCKET_ERROR; + } + *ip = param.ip; + //*port = param.port; + len -= blk; + cnt += blk; + buf += blk; + _sockets[socket].pending -= blk; + } else { + // allow to receive unsolicited commands + waitFinalResp(NULL, NULL, 10); + } + } + return cnt; +} + +// ---------------------------------------------------------------- +#if 0 +void _cbCMGL() +{ + // +} + +int MDMParser::smsCount(void) +{ + int num = 0; + sendFormated("AT+CMGL=ALL\r\n"); + if (OK != waitFinalResp((_CB)_cbCMGL,&num)) { + return false; + } + return true; +} +#endif + +bool MDMParser::smsSend(const char* num, const char* buf) +{ + sendFormated("AT+CMGS=\"%s\"\r",num); + if (PROMPT != waitFinalResp()) { + return false; + } + send(buf, strlen(buf)); + const char ctrlZ = 0x1A; + send(&ctrlZ, sizeof(ctrlZ)); + if (OK != waitFinalResp()) { + return false; + } + return true; +} + +bool MDMParser::smsDelete(int ix) +{ + sendFormated("AT+CMGD=%d\r\n",ix); + if (OK != waitFinalResp()) { + return false; + } + return true; +} + +int MDMParser::_cbCMGR(int type, const char* buf, int len, CMGRparam* param) +{ + if (param) { + if (type == TYPE_PLUS) { + if (sscanf(buf, "\r\n+CMGR: \"%*[^\"]\",\"%[^\"]", param->num) == 1) { + } + } else if ((type == TYPE_UNKNOWN) && (buf[len-2] == '\r') && (buf[len-1] == '\n')) { + memcpy(param->buf, buf, len-2); + param->buf[len-2] = '\0'; + } + } + return WAIT; +} + +bool MDMParser::smsRead(int ix, char* num, char* buf, int len) +{ + CMGRparam param; + param.num = num; + param.buf = buf; + sendFormated("AT+CMGR=%d\r\n",ix); + if (OK != waitFinalResp((_CB)_cbCMGR, ¶m)) { + return false; + } + return true; +} + +// ---------------------------------------------------------------- + +int MDMParser::_cbCUSD(int type, const char* buf, int len, char* resp) +{ + if ((type == TYPE_PLUS) && resp) { + // +USD: \"%*[^\"]\",\"%[^\"]\",,\"%*[^\"]\",%d,%d,%d,%d,\"*[^\"]\",%d,%d"..); + if (sscanf(buf, "\r\n+CUSD: %*d,\"%[^\"]\",%*d", resp) == 1) { + /*nothing*/ + } + } + return WAIT; +} +int MDMParser::ussdCommand(const char* cmd, char* buf, int len) +{ + *buf = '\0'; + sendFormated("AT+CUSD=1,\"%s\"\r\n",cmd); + if (OK != waitFinalResp((_CB)_cbCUSD, buf)) { + return -1; + } + return strlen(buf); +} + + +// ---------------------------------------------------------------- +int MDMParser::_parseMatch(Pipe<char>* pipe, int len, const char* sta, const char* end) { int o = 0; - int i = 0; - int l = pipe->start(); - static const char erTxt[] = "ERROR\r\n"; - static const char okTxt[] = "OK\r\n"; - int er = 0; - int ok = 0; - while ((i < pipe->size()) && (o < length)) - { - int t = pipe->next(); - i ++; - buffer[o++] = t; - ok = (t == okTxt[ok]) ? ok + 1 : 0; - er = (t == erTxt[er]) ? er + 1 : 0; - if ((okTxt[ok] == '\0') || (erTxt[er] == '\0')) - { - pipe->done(); - if (length > o) - buffer[o] = '\0'; - return o; + if (sta) { + while (*sta) { + if (++o > len) return WAIT; + char ch = pipe->next(); + if (*sta++ != ch) return NOT_FOUND; + } + } + if (!end) return o; // no termination + int x = 0; + while (end[x]) { + if (++o > len) return WAIT; + char ch = pipe->next(); + x = (end[x] == ch) ? x + 1 : + (end[0] == ch) ? 1 : + 0; + } + return o; +} + +int MDMParser::_parseFormated(Pipe<char>* pipe, int len, const char* fmt) +{ + int o = 0; + int num = 0; + if (fmt) { + while (*fmt) { + if (++o > len) return WAIT; + char ch = pipe->next(); + if (*fmt == '%') { + fmt++; + if (*fmt == 'd') { // numeric + fmt ++; + num = 0; + while (ch >= '0' && ch <= '9') { + num = num * 10 + (ch - '0'); + if (++o > len) return WAIT; + ch = pipe->next(); + } + } + else if (*fmt == 'c') { // char buffer (takes last numeric as length) + fmt ++; + while (num --) { + if (++o > len) return WAIT; + ch = pipe->next(); + } + } + } + if (*fmt++ != ch) return NOT_FOUND; } } - o = 0; - if (length > 0) - buffer[0] = '\0'; + return o; +} + + +int MDMParser::_getLine(Pipe<char>* pipe, char* buf, int len) +{ + int unkn = 0; + int sz = pipe->size(); + int fr = pipe->free(); + if (len > sz) + len = sz; + while (len > 0) + { + static struct { + const char* fmt; int type; + } lutF[] = { + { "\r\n+USORD: %d,%d,\"%c\"", TYPE_PLUS }, + { "\r\n+USORF: %d,\""IPSTR"\",%d,%d,\"%c\"", TYPE_PLUS }, + }; + static struct { + const char* sta; const char* end; int type; + } lut[] = { + { "\r\nOK\r\n", NULL, TYPE_OK }, + { "\r\nERROR\r\n", NULL, TYPE_ERROR }, + { "\r\n+CME ERROR:", "\r\n", TYPE_ERROR }, + { "\r\n+CMS ERROR:", "\r\n", TYPE_ERROR }, + { "\r\nRING\r\n", NULL, TYPE_RING }, + { "\r\nCONNECT\r\n", NULL, TYPE_CONNECT }, + { "\r\nNO CARRIER\r\n", NULL, TYPE_NOCARRIER }, + { "\r\nNO DIALTONE\r\n", NULL, TYPE_NODIALTONE }, + { "\r\nBUSY\r\n", NULL, TYPE_BUSY }, + { "\r\nNO ANSWER\r\n", NULL, TYPE_NOANSWER }, + { "\r\n+", "\r\n", TYPE_PLUS }, + { "\r\n@", NULL, TYPE_PROMPT }, // Sockets + { "\r\n>", NULL, TYPE_PROMPT }, // SMS + }; + for (int i = 0; i < sizeof(lutF)/sizeof(*lutF); i ++) { + pipe->set(unkn); + int ln = _parseFormated(pipe, len, lutF[i].fmt); + if (ln == WAIT && fr) + return WAIT; + if ((ln != NOT_FOUND) && (unkn > 0)) + return pipe->get(buf, unkn); + if (ln > 0) + return lutF[i].type | pipe->get(buf, ln); + } + for (int i = 0; i < sizeof(lut)/sizeof(*lut); i ++) { + pipe->set(unkn); + int ln = _parseMatch(pipe, len, lut[i].sta, lut[i].end); + if (ln == WAIT && fr) + return WAIT; + if ((ln != NOT_FOUND) && (unkn > 0)) + return pipe->get(buf, unkn); + if (ln > 0) + return lut[i].type | pipe->get(buf, ln); + } + // UNKNOWN + unkn ++; + len--; + } return WAIT; } @@ -96,11 +875,6 @@ return _getLine(&_pipeRx, buffer, length); } -int MDMSerial::getResp(char* buffer, int length) -{ - return _getResp(&_pipeRx, buffer, length); -} - // ---------------------------------------------------------------- // USB Implementation // ---------------------------------------------------------------- @@ -110,5 +884,4 @@ MDMUsb::MDMUsb(void) { } int MDMUsb::_send(const void* buf, int len) { return len; } int MDMUsb::getLine(char* buffer, int length) { return NOT_FOUND; } -int MDMUsb::getResp(char* buffer, int length) { return NOT_FOUND; } #endif \ No newline at end of file