Support for LISA-N101
Fork of C027_Support by
This is a variant of the C027 driver code for the C027N version, i.e. the one with the Neul/Huawei/u-blox Cellular Internet of Things module on board. The AT command interface for this module is entirely different to the AT interface for the other u-blox modules, hence this fork of the driver. Work is underway to rearchitect the original C027 driver so that a merge can be done.
Diff: MDM.cpp
- Revision:
- 126:76b578ec2912
- Parent:
- 125:72ca0c9a5a06
- Child:
- 127:4df82b52f834
--- a/MDM.cpp Thu Apr 23 12:05:40 2015 +0000 +++ b/MDM.cpp Fri May 22 08:54:47 2015 +0000 @@ -1,4 +1,3 @@ -#include "mbed.h" #include "MDM.h" #ifdef TARGET_UBLOX_C027 #include "C027_api.h" @@ -6,7 +5,7 @@ #include "MDMAPN.h" #define PROFILE "0" //!< this is the psd profile used -#define MAX_SIZE 128 //!< max expected messages +#define MAX_SIZE 256 //!< max expected messages // num sockets #define NUMSOCKETS (sizeof(_sockets)/sizeof(*_sockets)) //! test if it is a socket is ok to use @@ -106,6 +105,7 @@ memset(_sockets, 0, sizeof(_sockets)); for (int socket = 0; socket < NUMSOCKETS; socket ++) _sockets[socket].handle = SOCKET_ERROR; + _useNMI = false; _outstandingNMI = 0; #ifdef MDM_DEBUG _debugLevel = 1; @@ -211,19 +211,21 @@ } else if (_dev.dev == DEV_LISA_N100) { // Neul unsolicited responses ---------------------------- // New Message Indication - // +NMI:<length>,<data> - if (sscanf(buf, "\r\n+NMI:%d,%s", &a, s) == 2) { + // +NMI (alone, no data following, i.e. NMI=2 mode, not NMI=1 mode) + if (strstr(cmd, "NMI\r\n") == cmd) { _outstandingNMI++; - TRACE("New Message Indication, length: %d\r\n", a); + TRACE("New Message Indication, %d ready.\r\n", _outstandingNMI); } // Send Message Indication // +SMI:<status> if (sscanf(cmd, "SMI:%s", s) == 1) { - TRACE("Send message status: %s\r\n", s); + TRACE("Send message indication: %s\r\n", s); } // +GSN:<UUID> - if (sscanf(cmd, "GSN:%s", s) == 1) { - TRACE("Serial number is: %s\r\n", s); + memset (s, 0, sizeof (s)); + // Don't use %s as it doesn't go beyond a space character and <NOT SET> is a possible value + if (sscanf(cmd, "GSN:%[^\r\n]", s) == 1) { + TRACE("UUID is: %s\r\n", s); } // +MGS:<status> if (sscanf(cmd, "MGS:%s", s) == 1) { @@ -259,7 +261,23 @@ } // +DI:<string> if (sscanf(cmd, "DI:%s", s) == 1) { - // Do nothing, this will be spat out when debug is on anyway + // Do nothing, these will be spat out at debug level 3 + } + // +DEVELOPER_DCI_MCS: <2 or 4> + memset (s, 0, sizeof (s)); + // Don't use %s as it doesn't go beyond a space character and NOT SET is a possible value + if (sscanf(cmd, "DEVELOPER_DCI_MCS:%[^\r\n]", s) == 1) { + TRACE("DEVELOPER_DCI_MCS: %s\r\n", s); + } + // +DEVELOPER_CHANNELS: <string> + memset (s, 0, sizeof (s)); + // This is more complex to parse-out as sometimes the string is preceded with \r\n and + // sometimes it isn't, also the portion we want to pick up includes spaces + char * pStr = strstr (buf, "DEVELOPER_CHANNELS:"); + if (pStr != NULL) { + if (sscanf(pStr + strlen ("DEVELOPER_CHANNELS:"), "%[^\r\n]", s) == 1) { + TRACE("DEVELOPER_CHANNELS: %s\r\n", s); + } } } else { // GSM/UMTS Specific ------------------------------------------- @@ -353,8 +371,8 @@ int MDMParser::_cbGmmString(int type, const char* buf, int len, char* str) { if (str && (type == TYPE_PLUS)) { - if (sscanf(buf, "\r\n+GMM:%s\r\n", str) == 1) - /*nothing*/; + if (sscanf(buf, "\r\n+GMM:%[^\r\n]", str) == 1) // Don't use %s as it doesn't go beyond a space character + /*nothing*/; // However, note that this means no null terminator is added } return WAIT; } @@ -434,6 +452,7 @@ INFO("Modem::init\r\n"); // Attempt to get the manufacturer model string + memset (_dev.model, 0, sizeof (_dev.model)); // Necessary since the _cbGmmString call doesn't insert a terminator sendFormated("AT+GMM\r\n"); if ((RESP_OK == waitFinalResp(_cbGmmString, _dev.model)) && (strstr (_dev.model, "Neul") == _dev.model)) { _dev.dev = DEV_LISA_N100; @@ -443,12 +462,9 @@ sendFormated("AT+GMI\r\n"); if (RESP_OK != waitFinalResp(_cbGmiString, _dev.manu)) goto failure; -#ifndef DISABLE_NEUL_TEST_COMMANDS - /* In a phase 1 deployment special initialisation command should be inserted here, for example: */ - /* sendFormated ("AT+DI=0\r\n"); - if (RESP_OK != waitFinalResp()) - goto failure; */ -#endif + sendFormated ("AT+DI=0\r\n"); + if (RESP_OK != waitFinalResp()) + goto failure; // get the sw version sendFormated("AT+GMR\r\n"); if (RESP_OK != waitFinalResp(_cbGmrString, _dev.ver)) @@ -456,20 +472,27 @@ // Don't set an error if this fails as it's not set on some modules sendFormated("AT+GSN\r\n"); waitFinalResp(NULL, NULL, 1000); -#ifdef C027N_USE_NMI + // Try to switch on NMI=2 (supported by phase 2 modules and beyond) // Switch on new message indications sendFormated("AT+NMI=2\r\n"); - if (RESP_OK != waitFinalResp()) - goto failure; -#else - sendFormated("AT+NMI=0\r\n"); - if (RESP_OK != waitFinalResp()) - goto failure; -#endif + if (RESP_OK == waitFinalResp()) { + _useNMI = true; + } else { // If not OK, make sure it's switched off + sendFormated("AT+NMI=0\r\n"); + if (RESP_OK != waitFinalResp()) + goto failure; + } // Switch on send message indications sendFormated("AT+SMI=1\r\n"); if (RESP_OK != waitFinalResp()) goto failure; + // Query the scan range + sendFormated("AT+DEVELOPER_CHANNELS?\r\n"); + // Don't set an error if this fails as it's not on phase 1 modules + waitFinalResp( NULL, NULL, 1000); + sendFormated("AT+DEVELOPER_DCI_MCS?\r\n"); + // Don't set an error if this fails as it's not on phase 1 modules + waitFinalResp( NULL, NULL, 1000); } else { // 3GPP/CDMA modem init // echo off @@ -696,10 +719,11 @@ sendFormated("AT+RAS\r\n"); if (RESP_OK != waitFinalResp(_cbRAS, &ok)) goto failure; - _net.psd = REG_HOME; - sendFormated("AT+CSQ\r\n"); - if (RESP_OK != waitFinalResp(_cbCSQN, &(_net.rssi))) - goto failure; + if (ok) { + _net.psd = REG_HOME; + if (!getRssi (&(_net.rssi))) + goto failure; + } } else { sendFormated("AT+CREG?\r\n"); waitFinalResp(); // don't fail as service could be not subscribed @@ -779,7 +803,7 @@ memcpy(status, &_net, sizeof(NetStatus)); } if (_dev.dev == DEV_LISA_N100) { - ok = REG_DONE(_net.psd); // No CSD for the Neul modem + ok = REG_OK(_net.psd); // No CSD for the Neul modem } else { ok = REG_DONE(_net.csd) && REG_DONE(_net.psd); } @@ -847,7 +871,7 @@ if ((type == TYPE_PLUS) && connected) { // +RAS: <status> if (sscanf(buf, "\r\n+RAS:%s", status) == 1) { - if (strcmp ("CONNECTED\r\n", status) == 0) { + if (strcmp ("CONNECTED", status) == 0) { *connected = true; } return RESP_OK; @@ -1488,6 +1512,33 @@ // ---------------------------------------------------------------- // Neul AT command handling functions +char * MDMParser::getVersion(void) +{ + return _dev.model; +} + +bool MDMParser::sendMactest (int size, const char* buf) +{ + bool ok = false; + int sizeToSend; + char bufToSend[MAX_SIZE]; + + LOCK(); + + if (size <= (int) (sizeof(bufToSend) / 2)) + { + sizeToSend = bytesToHexString (buf, size, bufToSend, sizeof(bufToSend)); + sendFormated ("AT+MACTEST=%d,%.*s\r\n", size, sizeToSend, bufToSend); + if (RESP_OK == waitFinalResp()) { + ok = true; + } + } + + UNLOCK(); + + return ok; +} + int MDMParser::_cbMGS (int type, const char* buf, int len, bool* ok) { *ok = false; @@ -1528,7 +1579,7 @@ if (ok) { ok = (RESP_OK == waitFinalResp(NULL)); if (ok) { - ok = (RESP_OK == waitFinalResp(_cbSMI, &ok, 30000)) && ok; + ok = (RESP_OK == waitFinalResp(_cbSMI, &ok, 60000)) && ok; } } } @@ -1572,75 +1623,61 @@ return ok; } -#ifdef C027N_USE_NMI - bool MDMParser::datagramRecv(int* size, char* buf, int timeoutMs /* 10000 */) { - bool gotDatagram = false; + bool ok = false; MGRparam param; param.buf = buf; param.maxlen = *size; param.outlen = 0; LOCK(); - if (_outstandingNMI == 0) - { - waitFinalResp(NULL, NULL, timeoutMs); - } - if (_outstandingNMI > 0) + + if (_useNMI) { - gotDatagram = doMGR (size, buf, ¶m); - if (gotDatagram) { - _outstandingNMI--; - if (param.outlen > 0) { - gotDatagram = true; + // If NMI type 2 is supported (so NMI doesn't destroy the datagram), + // use the _outstandingNMI count and read the messages from the queue + if (_outstandingNMI == 0) + { + waitFinalResp(NULL, NULL, timeoutMs); + } + if (_outstandingNMI > 0) + { + ok = doMGR (size, buf, ¶m); + if (ok) { + _outstandingNMI--; + if (param.outlen > 0) { + ok = true; + } + } else { + *size = 0; } - } else { + } + } + else + { + // If NMI type 2 is not supported, poll with MGR instead + Timer timer; + + timer.start(); + ok = true; + while (ok && (param.outlen == 0) && (timer.read_ms() < timeoutMs)) { + ok = doMGR (size, buf, ¶m); + if (ok && param.outlen == 0) { + wait_ms (500); + } + } + if (param.outlen == 0) { + ok = false; *size = 0; } } - UNLOCK(); - return gotDatagram; -} - -#else - -bool MDMParser::datagramRecv(int* size, char* buf, int timeoutMs /* 10000 */) -{ - bool ok = false; - MGRparam param; - Timer timer; - param.buf = buf; - param.maxlen = *size; - param.outlen = 0; - -// The correct way to do this would be to switch on NMI and wait, however -// the NMI carries all the data with it, it's not just a flag, and so -// the parser here would have to handle queues of data, which it can't. -// So instead, just poll with AT+MGR until a mode of NMI comes along -// which leaves the data in the buffer. - - LOCK(); - timer.start(); - ok = true; - while (ok && (param.outlen == 0) && (timer.read_ms() < timeoutMs)) { - ok = doMGR (size, buf, ¶m); - if (ok && param.outlen == 0) { - wait_ms (500); - } - } - if (param.outlen == 0) { - ok = false; - *size = 0; - } UNLOCK(); return ok; } -#endif - int MDMParser::_cbCSQN(int type, const char* buf, int len, int* rssi) { if ((type == TYPE_PLUS) && rssi) { @@ -1986,6 +2023,7 @@ { "\r\nBUSY\r\n", NULL, TYPE_BUSY }, { "\r\nNO ANSWER\r\n", NULL, TYPE_NOANSWER }, { "\r\n+", "\r\n", TYPE_PLUS }, + { "+", "\r\n", TYPE_PLUS }, // Special for Neul modem as they sometimes drop off the \r\n at the start { "\r\n@", NULL, TYPE_PROMPT }, // Sockets { "\r\n>", NULL, TYPE_PROMPT }, // SMS { "\n>", NULL, TYPE_PROMPT }, // File @@ -2121,4 +2159,4 @@ int MDMUsb::getLine(char* buffer, int length) { return NOT_FOUND; } -#endif \ No newline at end of file +#endif