Support for LISA-N101

Fork of C027_Support by u-blox

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.

Committer:
RobMeades
Date:
Wed Jun 17 12:51:56 2015 +0000
Revision:
127:4df82b52f834
Parent:
126:76b578ec2912
Update handling of RAS AT command to wait for the OK at the end.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
mazgch 18:e5697801df29 1 #include "MDM.h"
mazgch 74:208e3e32d263 2 #ifdef TARGET_UBLOX_C027
mazgch 74:208e3e32d263 3 #include "C027_api.h"
mazgch 74:208e3e32d263 4 #endif
mazgch 85:dd8f4f0d0ca9 5 #include "MDMAPN.h"
mazgch 84:a05edb010176 6
mazgch 74:208e3e32d263 7 #define PROFILE "0" //!< this is the psd profile used
RobMeades 126:76b578ec2912 8 #define MAX_SIZE 256 //!< max expected messages
mazgch 103:197fa7920ad8 9 // num sockets
mazgch 104:c64ba749a422 10 #define NUMSOCKETS (sizeof(_sockets)/sizeof(*_sockets))
mazgch 104:c64ba749a422 11 //! test if it is a socket is ok to use
mazgch 104:c64ba749a422 12 #define ISSOCKET(s) (((s) >= 0) && ((s) < NUMSOCKETS) && (_sockets[s].handle != SOCKET_ERROR))
mazgch 75:ce6e12067d0c 13 //! check for timeout
mazgch 75:ce6e12067d0c 14 #define TIMEOUT(t, ms) ((ms != TIMEOUT_BLOCKING) && (ms < t.read_ms()))
mazgch 80:34985b4d821e 15 //! registration ok check helper
mazgch 79:291df065e345 16 #define REG_OK(r) ((r == REG_HOME) || (r == REG_ROAMING))
mazgch 80:34985b4d821e 17 //! registration done check helper (no need to poll further)
mazgch 79:291df065e345 18 #define REG_DONE(r) ((r == REG_HOME) || (r == REG_ROAMING) || (r == REG_DENIED))
mazgch 95:8282dbbe1492 19 //! helper to make sure that lock unlock pair is always balaced
mazgch 95:8282dbbe1492 20 #define LOCK() { lock()
mazgch 95:8282dbbe1492 21 //! helper to make sure that lock unlock pair is always balaced
mazgch 95:8282dbbe1492 22 #define UNLOCK() } unlock()
mazgch 79:291df065e345 23
mazgch 74:208e3e32d263 24 #ifdef MDM_DEBUG
mazgch 95:8282dbbe1492 25 #if 1 // colored terminal output using ANSI escape sequences
mazgch 95:8282dbbe1492 26 #define COL(c) "\033[" c
mazgch 95:8282dbbe1492 27 #else
mazgch 95:8282dbbe1492 28 #define COL(c)
mazgch 95:8282dbbe1492 29 #endif
mazgch 95:8282dbbe1492 30 #define DEF COL("39m")
mazgch 95:8282dbbe1492 31 #define BLA COL("30m")
mazgch 95:8282dbbe1492 32 #define RED COL("31m")
mazgch 95:8282dbbe1492 33 #define GRE COL("32m")
mazgch 95:8282dbbe1492 34 #define YEL COL("33m")
mazgch 95:8282dbbe1492 35 #define BLU COL("34m")
mazgch 95:8282dbbe1492 36 #define MAG COL("35m")
mazgch 95:8282dbbe1492 37 #define CYA COL("36m")
mazgch 95:8282dbbe1492 38 #define WHY COL("37m")
mazgch 95:8282dbbe1492 39
RobMeades 124:a58c1a7c5e18 40 const char hexTable[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', \
RobMeades 124:a58c1a7c5e18 41 '9', 'a', 'b', 'c', 'd', 'e', 'f'};
RobMeades 124:a58c1a7c5e18 42
mazgch 74:208e3e32d263 43 void dumpAtCmd(const char* buf, int len)
mazgch 21:c4d64830bf02 44 {
mazgch 75:ce6e12067d0c 45 ::printf(" %3d \"", len);
mazgch 21:c4d64830bf02 46 while (len --) {
mazgch 21:c4d64830bf02 47 char ch = *buf++;
mazgch 75:ce6e12067d0c 48 if ((ch > 0x1F) && (ch != 0x7F)) { // is printable
mazgch 75:ce6e12067d0c 49 if (ch == '%') ::printf("%%");
mazgch 75:ce6e12067d0c 50 else if (ch == '"') ::printf("\\\"");
mazgch 75:ce6e12067d0c 51 else if (ch == '\\') ::printf("\\\\");
mazgch 75:ce6e12067d0c 52 else putchar(ch);
mazgch 75:ce6e12067d0c 53 } else {
mazgch 75:ce6e12067d0c 54 if (ch == '\a') ::printf("\\a"); // BEL (0x07)
mazgch 75:ce6e12067d0c 55 else if (ch == '\b') ::printf("\\b"); // Backspace (0x08)
mazgch 75:ce6e12067d0c 56 else if (ch == '\t') ::printf("\\t"); // Horizontal Tab (0x09)
mazgch 75:ce6e12067d0c 57 else if (ch == '\n') ::printf("\\n"); // Linefeed (0x0A)
mazgch 75:ce6e12067d0c 58 else if (ch == '\v') ::printf("\\v"); // Vertical Tab (0x0B)
mazgch 75:ce6e12067d0c 59 else if (ch == '\f') ::printf("\\f"); // Formfeed (0x0C)
mazgch 75:ce6e12067d0c 60 else if (ch == '\r') ::printf("\\r"); // Carriage Return (0x0D)
mazgch 76:f7c3dd568dae 61 else ::printf("\\x%02x", (unsigned char)ch);
mazgch 75:ce6e12067d0c 62 }
mazgch 21:c4d64830bf02 63 }
mazgch 75:ce6e12067d0c 64 ::printf("\"\r\n");
mazgch 21:c4d64830bf02 65 }
mazgch 74:208e3e32d263 66
mazgch 117:74e4e0109a9e 67 void MDMParser::_debugPrint(int level, const char* color, const char* format, ...)
mazgch 117:74e4e0109a9e 68 {
mazgch 117:74e4e0109a9e 69 if (_debugLevel >= level)
mazgch 117:74e4e0109a9e 70 {
mazgch 117:74e4e0109a9e 71 va_list args;
mazgch 117:74e4e0109a9e 72 va_start (args, format);
mazgch 117:74e4e0109a9e 73 if (color) ::printf(color);
mazgch 117:74e4e0109a9e 74 ::vprintf(format, args);
mazgch 117:74e4e0109a9e 75 if (color) ::printf(DEF);
mazgch 117:74e4e0109a9e 76 va_end (args);
mazgch 117:74e4e0109a9e 77 }
mazgch 117:74e4e0109a9e 78 }
mazgch 117:74e4e0109a9e 79
mazgch 117:74e4e0109a9e 80 #define ERROR(...) _debugPrint(0, RED, __VA_ARGS__)
mazgch 117:74e4e0109a9e 81 #define INFO(...) _debugPrint(1, GRE, __VA_ARGS__)
mazgch 117:74e4e0109a9e 82 #define TRACE(...) _debugPrint(2, DEF, __VA_ARGS__)
mazgch 117:74e4e0109a9e 83 #define TEST(...) _debugPrint(3, CYA, __VA_ARGS__)
mazgch 74:208e3e32d263 84
mazgch 74:208e3e32d263 85 #else
mazgch 74:208e3e32d263 86
mazgch 75:ce6e12067d0c 87 #define ERROR(...) (void)0 // no tracing
mazgch 95:8282dbbe1492 88 #define TEST(...) (void)0 // no tracing
mazgch 74:208e3e32d263 89 #define INFO(...) (void)0 // no tracing
mazgch 74:208e3e32d263 90 #define TRACE(...) (void)0 // no tracing
mazgch 74:208e3e32d263 91
mazgch 31:a0bed6c1e05d 92 #endif
mazgch 21:c4d64830bf02 93
mazgch 44:9d12223b78ff 94 MDMParser* MDMParser::inst;
mazgch 44:9d12223b78ff 95
mazgch 21:c4d64830bf02 96 MDMParser::MDMParser(void)
mazgch 21:c4d64830bf02 97 {
mazgch 44:9d12223b78ff 98 inst = this;
mazgch 31:a0bed6c1e05d 99 memset(&_dev, 0, sizeof(_dev));
mazgch 31:a0bed6c1e05d 100 memset(&_net, 0, sizeof(_net));
mazgch 54:7ba8e4c218e2 101 _net.lac = 0xFFFF;
mazgch 54:7ba8e4c218e2 102 _net.ci = 0xFFFFFFFF;
mazgch 35:9275215a3a5b 103 _ip = NOIP;
mazgch 76:f7c3dd568dae 104 _init = false;
mazgch 31:a0bed6c1e05d 105 memset(_sockets, 0, sizeof(_sockets));
mazgch 104:c64ba749a422 106 for (int socket = 0; socket < NUMSOCKETS; socket ++)
mazgch 103:197fa7920ad8 107 _sockets[socket].handle = SOCKET_ERROR;
RobMeades 126:76b578ec2912 108 _useNMI = false;
RobMeades 118:f3fd6c30dc19 109 _outstandingNMI = 0;
mazgch 74:208e3e32d263 110 #ifdef MDM_DEBUG
mazgch 76:f7c3dd568dae 111 _debugLevel = 1;
mazgch 74:208e3e32d263 112 _debugTime.start();
mazgch 74:208e3e32d263 113 #endif
mazgch 74:208e3e32d263 114 }
mazgch 74:208e3e32d263 115
mazgch 18:e5697801df29 116 int MDMParser::send(const char* buf, int len)
mazgch 18:e5697801df29 117 {
mazgch 74:208e3e32d263 118 #ifdef MDM_DEBUG
mazgch 74:208e3e32d263 119 if (_debugLevel >= 3) {
mazgch 75:ce6e12067d0c 120 ::printf("%10.3f AT send ", _debugTime.read_ms()*0.001);
mazgch 74:208e3e32d263 121 dumpAtCmd(buf,len);
mazgch 74:208e3e32d263 122 }
mazgch 21:c4d64830bf02 123 #endif
mazgch 18:e5697801df29 124 return _send(buf, len);
mazgch 18:e5697801df29 125 }
mazgch 18:e5697801df29 126
mazgch 21:c4d64830bf02 127 int MDMParser::sendFormated(const char* format, ...) {
mazgch 21:c4d64830bf02 128 char buf[MAX_SIZE];
mazgch 21:c4d64830bf02 129 va_list args;
mazgch 21:c4d64830bf02 130 va_start(args, format);
mazgch 21:c4d64830bf02 131 int len = vsnprintf(buf,sizeof(buf), format, args);
mazgch 21:c4d64830bf02 132 va_end(args);
mazgch 21:c4d64830bf02 133 return send(buf, len);
mazgch 21:c4d64830bf02 134 }
mazgch 21:c4d64830bf02 135
mazgch 26:07be5faf8925 136 int MDMParser::waitFinalResp(_CALLBACKPTR cb /* = NULL*/,
mazgch 26:07be5faf8925 137 void* param /* = NULL*/,
mazgch 26:07be5faf8925 138 int timeout_ms /*= 5000*/)
mazgch 26:07be5faf8925 139 {
mazgch 69:4d6fa520dfca 140 char buf[MAX_SIZE + 64 /* add some more space for framing */];
mazgch 21:c4d64830bf02 141 Timer timer;
mazgch 21:c4d64830bf02 142 timer.start();
mazgch 21:c4d64830bf02 143 do {
mazgch 21:c4d64830bf02 144 int ret = getLine(buf, sizeof(buf));
mazgch 74:208e3e32d263 145 #ifdef MDM_DEBUG
mazgch 74:208e3e32d263 146 if ((_debugLevel >= 3) && (ret != WAIT) && (ret != NOT_FOUND))
mazgch 21:c4d64830bf02 147 {
mazgch 31:a0bed6c1e05d 148 int len = LENGTH(ret);
mazgch 31:a0bed6c1e05d 149 int type = TYPE(ret);
mazgch 95:8282dbbe1492 150 const char* s = (type == TYPE_UNKNOWN)? YEL "UNK" DEF :
mazgch 95:8282dbbe1492 151 (type == TYPE_TEXT) ? MAG "TXT" DEF :
mazgch 95:8282dbbe1492 152 (type == TYPE_OK ) ? GRE "OK " DEF :
mazgch 95:8282dbbe1492 153 (type == TYPE_ERROR) ? RED "ERR" DEF :
mazgch 95:8282dbbe1492 154 (type == TYPE_PLUS) ? CYA " + " DEF :
mazgch 95:8282dbbe1492 155 (type == TYPE_PROMPT) ? BLU " > " DEF :
mazgch 95:8282dbbe1492 156 "..." ;
mazgch 75:ce6e12067d0c 157 ::printf("%10.3f AT read %s", _debugTime.read_ms()*0.001, s);
mazgch 74:208e3e32d263 158 dumpAtCmd(buf, len);
mazgch 21:c4d64830bf02 159 }
mazgch 21:c4d64830bf02 160 #endif
mazgch 21:c4d64830bf02 161 if ((ret != WAIT) && (ret != NOT_FOUND))
mazgch 18:e5697801df29 162 {
mazgch 21:c4d64830bf02 163 int type = TYPE(ret);
mazgch 21:c4d64830bf02 164 // handle unsolicited commands here
mazgch 21:c4d64830bf02 165 if (type == TYPE_PLUS) {
mazgch 21:c4d64830bf02 166 const char* cmd = buf+3;
mazgch 54:7ba8e4c218e2 167 int a, b, c, d, r;
mazgch 23:05a1aeeb5fd9 168 char s[32];
mazgch 21:c4d64830bf02 169
mazgch 31:a0bed6c1e05d 170 // SMS Command ---------------------------------
mazgch 31:a0bed6c1e05d 171 // +CNMI: <mem>,<index>
mazgch 31:a0bed6c1e05d 172 if (sscanf(cmd, "CMTI: \"%*[^\"]\",%d", &a) == 1) {
mazgch 31:a0bed6c1e05d 173 TRACE("New SMS at index %d\r\n", a);
mazgch 21:c4d64830bf02 174 // Socket Specific Command ---------------------------------
mazgch 21:c4d64830bf02 175 // +UUSORD: <socket>,<length>
mazgch 103:197fa7920ad8 176 } else if ((sscanf(cmd, "UUSORD: %d,%d", &a, &b) == 2)) {
mazgch 103:197fa7920ad8 177 int socket = _findSocket(a);
mazgch 103:197fa7920ad8 178 TRACE("Socket %d: handle %d has %d bytes pending\r\n", socket, a, b);
mazgch 103:197fa7920ad8 179 if (socket != SOCKET_ERROR)
mazgch 103:197fa7920ad8 180 _sockets[socket].pending = b;
mazgch 69:4d6fa520dfca 181 // +UUSORF: <socket>,<length>
mazgch 103:197fa7920ad8 182 } else if ((sscanf(cmd, "UUSORF: %d,%d", &a, &b) == 2)) {
mazgch 103:197fa7920ad8 183 int socket = _findSocket(a);
mazgch 103:197fa7920ad8 184 TRACE("Socket %d: handle %d has %d bytes pending\r\n", socket, a, b);
mazgch 103:197fa7920ad8 185 if (socket != SOCKET_ERROR)
mazgch 103:197fa7920ad8 186 _sockets[socket].pending = b;
mazgch 21:c4d64830bf02 187 // +UUSOCL: <socket>
mazgch 103:197fa7920ad8 188 } else if ((sscanf(cmd, "UUSOCL: %d", &a) == 1)) {
mazgch 103:197fa7920ad8 189 int socket = _findSocket(a);
mazgch 103:197fa7920ad8 190 TRACE("Socket %d: handle %d closed by remote host\r\n", socket, a);
mazgch 103:197fa7920ad8 191 if ((socket != SOCKET_ERROR) && _sockets[socket].connected)
mazgch 103:197fa7920ad8 192 _sockets[socket].connected = false;
mazgch 103:197fa7920ad8 193 }
mazgch 32:8f12ac182bbb 194 if (_dev.dev == DEV_LISA_C200) {
mazgch 21:c4d64830bf02 195 // CDMA Specific -------------------------------------------
mazgch 21:c4d64830bf02 196 // +CREG: <n><SID>,<NID>,<stat>
mazgch 54:7ba8e4c218e2 197 if (sscanf(cmd, "CREG: %*d,%d,%d,%d",&a,&b,&c) == 3) {
mazgch 54:7ba8e4c218e2 198 // _net.sid = a;
mazgch 54:7ba8e4c218e2 199 // _net.nid = b;
mazgch 79:291df065e345 200 if (c == 0) _net.csd = REG_NONE; // not registered, home network
mazgch 79:291df065e345 201 else if (c == 1) _net.csd = REG_HOME; // registered, home network
mazgch 79:291df065e345 202 else if (c == 2) _net.csd = REG_NONE; // not registered, but MT is currently searching a new operator to register to
mazgch 79:291df065e345 203 else if (c == 3) _net.csd = REG_DENIED; // registration denied
mazgch 79:291df065e345 204 else if (c == 5) _net.csd = REG_ROAMING; // registered, roaming
mazgch 79:291df065e345 205 _net.psd = _net.csd; // fake PSD registration (CDMA is always registered)
mazgch 31:a0bed6c1e05d 206 _net.act = ACT_CDMA;
mazgch 84:a05edb010176 207 // +CSS: <mode>[,<format>,<oper>[,<AcT>]]
mazgch 21:c4d64830bf02 208 } else if (sscanf(cmd, "CSS %*c,%2s,%*d",s) == 1) {
mazgch 31:a0bed6c1e05d 209 //_net.reg = (strcmp("Z", s) == 0) ? REG_UNKNOWN : REG_HOME;
mazgch 21:c4d64830bf02 210 }
RobMeades 122:c6b2fa1928f2 211 } else if (_dev.dev == DEV_LISA_N100) {
RobMeades 118:f3fd6c30dc19 212 // Neul unsolicited responses ----------------------------
RobMeades 118:f3fd6c30dc19 213 // New Message Indication
RobMeades 126:76b578ec2912 214 // +NMI (alone, no data following, i.e. NMI=2 mode, not NMI=1 mode)
RobMeades 126:76b578ec2912 215 if (strstr(cmd, "NMI\r\n") == cmd) {
RobMeades 118:f3fd6c30dc19 216 _outstandingNMI++;
RobMeades 126:76b578ec2912 217 TRACE("New Message Indication, %d ready.\r\n", _outstandingNMI);
RobMeades 118:f3fd6c30dc19 218 }
RobMeades 118:f3fd6c30dc19 219 // Send Message Indication
RobMeades 118:f3fd6c30dc19 220 // +SMI:<status>
RobMeades 118:f3fd6c30dc19 221 if (sscanf(cmd, "SMI:%s", s) == 1) {
RobMeades 126:76b578ec2912 222 TRACE("Send message indication: %s\r\n", s);
RobMeades 118:f3fd6c30dc19 223 }
RobMeades 118:f3fd6c30dc19 224 // +GSN:<UUID>
RobMeades 126:76b578ec2912 225 memset (s, 0, sizeof (s));
RobMeades 126:76b578ec2912 226 // Don't use %s as it doesn't go beyond a space character and <NOT SET> is a possible value
RobMeades 126:76b578ec2912 227 if (sscanf(cmd, "GSN:%[^\r\n]", s) == 1) {
RobMeades 126:76b578ec2912 228 TRACE("UUID is: %s\r\n", s);
RobMeades 118:f3fd6c30dc19 229 }
RobMeades 118:f3fd6c30dc19 230 // +MGS:<status>
RobMeades 118:f3fd6c30dc19 231 if (sscanf(cmd, "MGS:%s", s) == 1) {
RobMeades 118:f3fd6c30dc19 232 TRACE("Message Send returned: %s\r\n", s);
RobMeades 118:f3fd6c30dc19 233 }
RobMeades 118:f3fd6c30dc19 234 // +MGR:<length>,<data>
RobMeades 118:f3fd6c30dc19 235 if (sscanf(cmd, "MGR:%s", s) == 1) {
RobMeades 118:f3fd6c30dc19 236 TRACE("Message Receive returned: %s\r\n", s);
RobMeades 118:f3fd6c30dc19 237 }
RobMeades 118:f3fd6c30dc19 238 // +RAS:<status>
RobMeades 118:f3fd6c30dc19 239 if (sscanf(cmd, "RAS:%s", s) == 1) {
RobMeades 118:f3fd6c30dc19 240 TRACE("Radio Activity Status returned: %s\r\n", s);
RobMeades 118:f3fd6c30dc19 241 }
RobMeades 118:f3fd6c30dc19 242 // +QMGR:<status>
RobMeades 118:f3fd6c30dc19 243 if (sscanf(cmd, "QMGR:%s", s) == 1) {
RobMeades 118:f3fd6c30dc19 244 TRACE("Query Messages Received returned: %s\r\n", s);
RobMeades 118:f3fd6c30dc19 245 }
RobMeades 118:f3fd6c30dc19 246 // +QMGS:<status>
RobMeades 118:f3fd6c30dc19 247 if (sscanf(cmd, "QMGS:%s", s) == 1) {
RobMeades 118:f3fd6c30dc19 248 TRACE("Query Messages Sent returned: %s\r\n", s);
RobMeades 118:f3fd6c30dc19 249 }
RobMeades 118:f3fd6c30dc19 250 // +RB:<status>
RobMeades 118:f3fd6c30dc19 251 if (sscanf(cmd, "RB:%s", s) == 1) {
RobMeades 118:f3fd6c30dc19 252 TRACE("Rebooting returned: %s\r\n", s);
RobMeades 118:f3fd6c30dc19 253 }
RobMeades 118:f3fd6c30dc19 254 // +CSQ: <0-255>
RobMeades 118:f3fd6c30dc19 255 if (sscanf(cmd, "CSQ: %d", &a) == 1) {
RobMeades 118:f3fd6c30dc19 256 TRACE("Signal strength is: %d\r\n", a);
RobMeades 118:f3fd6c30dc19 257 }
RobMeades 118:f3fd6c30dc19 258 // +LAC:<commandname>
RobMeades 118:f3fd6c30dc19 259 if (sscanf(cmd, "LAC:%s", s) == 1) {
RobMeades 118:f3fd6c30dc19 260 TRACE("An available command is: %s\r\n", s);
RobMeades 118:f3fd6c30dc19 261 }
RobMeades 118:f3fd6c30dc19 262 // +DI:<string>
RobMeades 118:f3fd6c30dc19 263 if (sscanf(cmd, "DI:%s", s) == 1) {
RobMeades 126:76b578ec2912 264 // Do nothing, these will be spat out at debug level 3
RobMeades 126:76b578ec2912 265 }
RobMeades 126:76b578ec2912 266 // +DEVELOPER_DCI_MCS: <2 or 4>
RobMeades 126:76b578ec2912 267 memset (s, 0, sizeof (s));
RobMeades 126:76b578ec2912 268 // Don't use %s as it doesn't go beyond a space character and NOT SET is a possible value
RobMeades 126:76b578ec2912 269 if (sscanf(cmd, "DEVELOPER_DCI_MCS:%[^\r\n]", s) == 1) {
RobMeades 126:76b578ec2912 270 TRACE("DEVELOPER_DCI_MCS: %s\r\n", s);
RobMeades 126:76b578ec2912 271 }
RobMeades 126:76b578ec2912 272 // +DEVELOPER_CHANNELS: <string>
RobMeades 126:76b578ec2912 273 memset (s, 0, sizeof (s));
RobMeades 126:76b578ec2912 274 // This is more complex to parse-out as sometimes the string is preceded with \r\n and
RobMeades 126:76b578ec2912 275 // sometimes it isn't, also the portion we want to pick up includes spaces
RobMeades 126:76b578ec2912 276 char * pStr = strstr (buf, "DEVELOPER_CHANNELS:");
RobMeades 126:76b578ec2912 277 if (pStr != NULL) {
RobMeades 126:76b578ec2912 278 if (sscanf(pStr + strlen ("DEVELOPER_CHANNELS:"), "%[^\r\n]", s) == 1) {
RobMeades 126:76b578ec2912 279 TRACE("DEVELOPER_CHANNELS: %s\r\n", s);
RobMeades 126:76b578ec2912 280 }
RobMeades 118:f3fd6c30dc19 281 }
mazgch 21:c4d64830bf02 282 } else {
mazgch 21:c4d64830bf02 283 // GSM/UMTS Specific -------------------------------------------
mazgch 79:291df065e345 284 // +UUPSDD: <profile_id>
mazgch 79:291df065e345 285 if (sscanf(cmd, "UUPSDD: %d",&a) == 1) {
mazgch 79:291df065e345 286 if (*PROFILE == a) _ip = NOIP;
mazgch 79:291df065e345 287 } else {
mazgch 79:291df065e345 288 // +CREG|CGREG: <n>,<stat>[,<lac>,<ci>[,AcT[,<rac>]]] // reply to AT+CREG|AT+CGREG
mazgch 79:291df065e345 289 // +CREG|CGREG: <stat>[,<lac>,<ci>[,AcT[,<rac>]]] // URC
mazgch 79:291df065e345 290 b = 0xFFFF; c = 0xFFFFFFFF; d = -1;
mazgch 79:291df065e345 291 r = sscanf(cmd, "%s %*d,%d,\"%X\",\"%X\",%d",s,&a,&b,&c,&d);
mazgch 79:291df065e345 292 if (r <= 1)
mazgch 79:291df065e345 293 r = sscanf(cmd, "%s %d,\"%X\",\"%X\",%d",s,&a,&b,&c,&d);
mazgch 79:291df065e345 294 if (r >= 2) {
mazgch 79:291df065e345 295 Reg *reg = !strcmp(s, "CREG:") ? &_net.csd :
mazgch 79:291df065e345 296 !strcmp(s, "CGREG:") ? &_net.psd : NULL;
mazgch 79:291df065e345 297 if (reg) {
mazgch 79:291df065e345 298 // network status
mazgch 79:291df065e345 299 if (a == 0) *reg = REG_NONE; // 0: not registered, home network
mazgch 79:291df065e345 300 else if (a == 1) *reg = REG_HOME; // 1: registered, home network
mazgch 79:291df065e345 301 else if (a == 2) *reg = REG_NONE; // 2: not registered, but MT is currently searching a new operator to register to
mazgch 79:291df065e345 302 else if (a == 3) *reg = REG_DENIED; // 3: registration denied
mazgch 79:291df065e345 303 else if (a == 4) *reg = REG_UNKNOWN; // 4: unknown
mazgch 79:291df065e345 304 else if (a == 5) *reg = REG_ROAMING; // 5: registered, roaming
mazgch 79:291df065e345 305 if ((r >= 3) && (b != 0xFFFF)) _net.lac = b; // location area code
mazgch 79:291df065e345 306 if ((r >= 4) && (c != 0xFFFFFFFF)) _net.ci = c; // cell ID
mazgch 79:291df065e345 307 // access technology
mazgch 79:291df065e345 308 if (r >= 5) {
mazgch 79:291df065e345 309 if (d == 0) _net.act = ACT_GSM; // 0: GSM
mazgch 79:291df065e345 310 else if (d == 1) _net.act = ACT_GSM; // 1: GSM COMPACT
mazgch 79:291df065e345 311 else if (d == 2) _net.act = ACT_UTRAN; // 2: UTRAN
mazgch 79:291df065e345 312 else if (d == 3) _net.act = ACT_EDGE; // 3: GSM with EDGE availability
mazgch 79:291df065e345 313 else if (d == 4) _net.act = ACT_UTRAN; // 4: UTRAN with HSDPA availability
mazgch 79:291df065e345 314 else if (d == 5) _net.act = ACT_UTRAN; // 5: UTRAN with HSUPA availability
mazgch 79:291df065e345 315 else if (d == 6) _net.act = ACT_UTRAN; // 6: UTRAN with HSDPA and HSUPA availability
mazgch 79:291df065e345 316 }
mazgch 79:291df065e345 317 }
mazgch 54:7ba8e4c218e2 318 }
mazgch 21:c4d64830bf02 319 }
mazgch 21:c4d64830bf02 320 }
mazgch 21:c4d64830bf02 321 }
mazgch 21:c4d64830bf02 322 if (cb) {
mazgch 21:c4d64830bf02 323 int len = LENGTH(ret);
mazgch 21:c4d64830bf02 324 int ret = cb(type, buf, len, param);
mazgch 21:c4d64830bf02 325 if (WAIT != ret)
mazgch 21:c4d64830bf02 326 return ret;
mazgch 21:c4d64830bf02 327 }
mazgch 95:8282dbbe1492 328 if (type == TYPE_OK)
mazgch 95:8282dbbe1492 329 return RESP_OK;
mazgch 95:8282dbbe1492 330 if (type == TYPE_ERROR)
mazgch 95:8282dbbe1492 331 return RESP_ERROR;
mazgch 95:8282dbbe1492 332 if (type == TYPE_PROMPT)
mazgch 95:8282dbbe1492 333 return RESP_PROMPT;
mazgch 21:c4d64830bf02 334 }
mazgch 21:c4d64830bf02 335 // relax a bit
mazgch 95:8282dbbe1492 336 wait_ms(10);
mazgch 21:c4d64830bf02 337 }
mazgch 75:ce6e12067d0c 338 while (!TIMEOUT(timer, timeout_ms));
mazgch 21:c4d64830bf02 339 return WAIT;
mazgch 21:c4d64830bf02 340 }
mazgch 21:c4d64830bf02 341
mazgch 31:a0bed6c1e05d 342 int MDMParser::_cbString(int type, const char* buf, int len, char* str)
mazgch 21:c4d64830bf02 343 {
mazgch 37:cc3433329d66 344 if (str && (type == TYPE_UNKNOWN)) {
mazgch 31:a0bed6c1e05d 345 if (sscanf(buf, "\r\n%s\r\n", str) == 1)
mazgch 31:a0bed6c1e05d 346 /*nothing*/;
mazgch 21:c4d64830bf02 347 }
mazgch 21:c4d64830bf02 348 return WAIT;
mazgch 21:c4d64830bf02 349 }
mazgch 21:c4d64830bf02 350
mazgch 31:a0bed6c1e05d 351 int MDMParser::_cbInt(int type, const char* buf, int len, int* val)
mazgch 31:a0bed6c1e05d 352 {
mazgch 37:cc3433329d66 353 if (val && (type == TYPE_UNKNOWN)) {
mazgch 31:a0bed6c1e05d 354 if (sscanf(buf, "\r\n%d\r\n", val) == 1)
mazgch 31:a0bed6c1e05d 355 /*nothing*/;
mazgch 31:a0bed6c1e05d 356 }
mazgch 31:a0bed6c1e05d 357 return WAIT;
mazgch 31:a0bed6c1e05d 358 }
mazgch 31:a0bed6c1e05d 359
RobMeades 118:f3fd6c30dc19 360 // Neul modem flavour of manufacturer ID string
RobMeades 118:f3fd6c30dc19 361 int MDMParser::_cbGmiString(int type, const char* buf, int len, char* str)
RobMeades 118:f3fd6c30dc19 362 {
RobMeades 118:f3fd6c30dc19 363 if (str && (type == TYPE_PLUS)) {
RobMeades 118:f3fd6c30dc19 364 if (sscanf(buf, "\r\n+GMI:%s\r\n", str) == 1)
RobMeades 118:f3fd6c30dc19 365 /*nothing*/;
RobMeades 118:f3fd6c30dc19 366 }
RobMeades 118:f3fd6c30dc19 367 return WAIT;
RobMeades 118:f3fd6c30dc19 368 }
RobMeades 118:f3fd6c30dc19 369
RobMeades 118:f3fd6c30dc19 370 // Neul modem flavour of manufacturer model string
RobMeades 118:f3fd6c30dc19 371 int MDMParser::_cbGmmString(int type, const char* buf, int len, char* str)
RobMeades 118:f3fd6c30dc19 372 {
RobMeades 118:f3fd6c30dc19 373 if (str && (type == TYPE_PLUS)) {
RobMeades 126:76b578ec2912 374 if (sscanf(buf, "\r\n+GMM:%[^\r\n]", str) == 1) // Don't use %s as it doesn't go beyond a space character
RobMeades 126:76b578ec2912 375 /*nothing*/; // However, note that this means no null terminator is added
RobMeades 118:f3fd6c30dc19 376 }
RobMeades 118:f3fd6c30dc19 377 return WAIT;
RobMeades 118:f3fd6c30dc19 378 }
RobMeades 118:f3fd6c30dc19 379
RobMeades 118:f3fd6c30dc19 380 // Neul modem flavour of manufacturer revision string
RobMeades 118:f3fd6c30dc19 381 int MDMParser::_cbGmrString(int type, const char* buf, int len, char* str)
RobMeades 118:f3fd6c30dc19 382 {
RobMeades 118:f3fd6c30dc19 383 if (str && (type == TYPE_PLUS)) {
RobMeades 118:f3fd6c30dc19 384 if (sscanf(buf, "\r\n+GMR:%s\r\n", str) == 1)
RobMeades 118:f3fd6c30dc19 385 /*nothing*/;
RobMeades 118:f3fd6c30dc19 386 }
RobMeades 118:f3fd6c30dc19 387 return WAIT;
RobMeades 118:f3fd6c30dc19 388 }
RobMeades 118:f3fd6c30dc19 389
mazgch 31:a0bed6c1e05d 390 // ----------------------------------------------------------------
mazgch 31:a0bed6c1e05d 391
mazgch 57:869bd35f44cc 392 bool MDMParser::connect(
mazgch 57:869bd35f44cc 393 const char* simpin,
mazgch 80:34985b4d821e 394 const char* apn, const char* username,
mazgch 80:34985b4d821e 395 const char* password, Auth auth,
mazgch 74:208e3e32d263 396 PinName pn)
mazgch 57:869bd35f44cc 397 {
mazgch 75:ce6e12067d0c 398 bool ok = init(simpin, NULL, pn);
mazgch 74:208e3e32d263 399 #ifdef MDM_DEBUG
mazgch 75:ce6e12067d0c 400 if (_debugLevel >= 1) dumpDevStatus(&_dev);
mazgch 74:208e3e32d263 401 #endif
mazgch 75:ce6e12067d0c 402 if (!ok)
mazgch 57:869bd35f44cc 403 return false;
mazgch 75:ce6e12067d0c 404 ok = registerNet();
mazgch 74:208e3e32d263 405 #ifdef MDM_DEBUG
mazgch 75:ce6e12067d0c 406 if (_debugLevel >= 1) dumpNetStatus(&_net);
mazgch 74:208e3e32d263 407 #endif
mazgch 75:ce6e12067d0c 408 if (!ok)
mazgch 57:869bd35f44cc 409 return false;
mazgch 80:34985b4d821e 410 IP ip = join(apn,username,password,auth);
mazgch 74:208e3e32d263 411 #ifdef MDM_DEBUG
mazgch 74:208e3e32d263 412 if (_debugLevel >= 1) dumpIp(ip);
mazgch 74:208e3e32d263 413 #endif
mazgch 57:869bd35f44cc 414 if (ip == NOIP)
mazgch 57:869bd35f44cc 415 return false;
mazgch 57:869bd35f44cc 416 return true;
mazgch 57:869bd35f44cc 417 }
mazgch 57:869bd35f44cc 418
mazgch 74:208e3e32d263 419 bool MDMParser::init(const char* simpin, DevStatus* status, PinName pn)
mazgch 21:c4d64830bf02 420 {
mazgch 74:208e3e32d263 421 int i = 10;
mazgch 95:8282dbbe1492 422 LOCK();
mazgch 76:f7c3dd568dae 423 memset(&_dev, 0, sizeof(_dev));
mazgch 74:208e3e32d263 424 if (pn != NC) {
mazgch 74:208e3e32d263 425 INFO("Modem::wakeup\r\n");
mazgch 74:208e3e32d263 426 DigitalOut pin(pn, 1);
mazgch 74:208e3e32d263 427 while (i--) {
RobMeades 122:c6b2fa1928f2 428 if (_dev.dev != DEV_LISA_N100) {
RobMeades 118:f3fd6c30dc19 429 // SARA-U2/LISA-U2 50..80us
RobMeades 118:f3fd6c30dc19 430 pin = 0; ::wait_us(50);
RobMeades 118:f3fd6c30dc19 431 pin = 1; ::wait_ms(10);
mazgch 79:291df065e345 432
RobMeades 118:f3fd6c30dc19 433 // SARA-G35 >5ms, LISA-C2 > 150ms, LEON-G2 >5ms
RobMeades 118:f3fd6c30dc19 434 pin = 0; ::wait_ms(150);
RobMeades 118:f3fd6c30dc19 435 pin = 1; ::wait_ms(100);
RobMeades 118:f3fd6c30dc19 436 }
mazgch 79:291df065e345 437 // purge any messages
mazgch 101:edfeb8af206e 438 purge();
mazgch 95:8282dbbe1492 439
mazgch 101:edfeb8af206e 440 // check interface
mazgch 74:208e3e32d263 441 sendFormated("AT\r\n");
mazgch 101:edfeb8af206e 442 int r = waitFinalResp(NULL,NULL,1000);
mazgch 95:8282dbbe1492 443 if(RESP_OK == r) break;
RobMeades 118:f3fd6c30dc19 444 if(RESP_ERROR == r) break; // Neul modem responds with ERROR when sent AT with no following parameters
mazgch 74:208e3e32d263 445 }
mazgch 75:ce6e12067d0c 446 if (i < 0) {
mazgch 95:8282dbbe1492 447 ERROR("No Reply from Modem\r\n");
mazgch 95:8282dbbe1492 448 goto failure;
mazgch 75:ce6e12067d0c 449 }
mazgch 21:c4d64830bf02 450 }
mazgch 76:f7c3dd568dae 451 _init = true;
mazgch 75:ce6e12067d0c 452
mazgch 74:208e3e32d263 453 INFO("Modem::init\r\n");
RobMeades 118:f3fd6c30dc19 454 // Attempt to get the manufacturer model string
RobMeades 126:76b578ec2912 455 memset (_dev.model, 0, sizeof (_dev.model)); // Necessary since the _cbGmmString call doesn't insert a terminator
RobMeades 118:f3fd6c30dc19 456 sendFormated("AT+GMM\r\n");
RobMeades 122:c6b2fa1928f2 457 if ((RESP_OK == waitFinalResp(_cbGmmString, _dev.model)) && (strstr (_dev.model, "Neul") == _dev.model)) {
RobMeades 122:c6b2fa1928f2 458 _dev.dev = DEV_LISA_N100;
RobMeades 122:c6b2fa1928f2 459 // Neul modem specific init
RobMeades 122:c6b2fa1928f2 460 printf ("Neul AT parser revision 0.1 (for interface NT1001).\n");
RobMeades 122:c6b2fa1928f2 461 // get the manufacturer ID string
RobMeades 122:c6b2fa1928f2 462 sendFormated("AT+GMI\r\n");
RobMeades 122:c6b2fa1928f2 463 if (RESP_OK != waitFinalResp(_cbGmiString, _dev.manu))
RobMeades 122:c6b2fa1928f2 464 goto failure;
RobMeades 126:76b578ec2912 465 sendFormated ("AT+DI=0\r\n");
RobMeades 126:76b578ec2912 466 if (RESP_OK != waitFinalResp())
RobMeades 126:76b578ec2912 467 goto failure;
RobMeades 122:c6b2fa1928f2 468 // get the sw version
RobMeades 122:c6b2fa1928f2 469 sendFormated("AT+GMR\r\n");
RobMeades 122:c6b2fa1928f2 470 if (RESP_OK != waitFinalResp(_cbGmrString, _dev.ver))
RobMeades 122:c6b2fa1928f2 471 goto failure;
RobMeades 122:c6b2fa1928f2 472 // Don't set an error if this fails as it's not set on some modules
RobMeades 122:c6b2fa1928f2 473 sendFormated("AT+GSN\r\n");
RobMeades 122:c6b2fa1928f2 474 waitFinalResp(NULL, NULL, 1000);
RobMeades 126:76b578ec2912 475 // Try to switch on NMI=2 (supported by phase 2 modules and beyond)
RobMeades 122:c6b2fa1928f2 476 // Switch on new message indications
RobMeades 124:a58c1a7c5e18 477 sendFormated("AT+NMI=2\r\n");
RobMeades 126:76b578ec2912 478 if (RESP_OK == waitFinalResp()) {
RobMeades 126:76b578ec2912 479 _useNMI = true;
RobMeades 126:76b578ec2912 480 } else { // If not OK, make sure it's switched off
RobMeades 126:76b578ec2912 481 sendFormated("AT+NMI=0\r\n");
RobMeades 126:76b578ec2912 482 if (RESP_OK != waitFinalResp())
RobMeades 126:76b578ec2912 483 goto failure;
RobMeades 126:76b578ec2912 484 }
RobMeades 122:c6b2fa1928f2 485 // Switch on send message indications
RobMeades 122:c6b2fa1928f2 486 sendFormated("AT+SMI=1\r\n");
RobMeades 122:c6b2fa1928f2 487 if (RESP_OK != waitFinalResp())
RobMeades 122:c6b2fa1928f2 488 goto failure;
RobMeades 126:76b578ec2912 489 // Query the scan range
RobMeades 126:76b578ec2912 490 sendFormated("AT+DEVELOPER_CHANNELS?\r\n");
RobMeades 126:76b578ec2912 491 // Don't set an error if this fails as it's not on phase 1 modules
RobMeades 126:76b578ec2912 492 waitFinalResp( NULL, NULL, 1000);
RobMeades 126:76b578ec2912 493 sendFormated("AT+DEVELOPER_DCI_MCS?\r\n");
RobMeades 126:76b578ec2912 494 // Don't set an error if this fails as it's not on phase 1 modules
RobMeades 126:76b578ec2912 495 waitFinalResp( NULL, NULL, 1000);
RobMeades 118:f3fd6c30dc19 496 } else {
RobMeades 118:f3fd6c30dc19 497 // 3GPP/CDMA modem init
RobMeades 118:f3fd6c30dc19 498 // echo off
RobMeades 118:f3fd6c30dc19 499 sendFormated("AT E0\r\n");
RobMeades 118:f3fd6c30dc19 500 if(RESP_OK != waitFinalResp())
mazgch 95:8282dbbe1492 501 goto failure;
RobMeades 118:f3fd6c30dc19 502 // enable verbose error messages
RobMeades 118:f3fd6c30dc19 503 sendFormated("AT+CMEE=2\r\n");
RobMeades 118:f3fd6c30dc19 504 if(RESP_OK != waitFinalResp())
mazgch 95:8282dbbe1492 505 goto failure;
RobMeades 118:f3fd6c30dc19 506 // set baud rate
RobMeades 118:f3fd6c30dc19 507 sendFormated("AT+IPR=115200\r\n");
mazgch 79:291df065e345 508 if (RESP_OK != waitFinalResp())
mazgch 95:8282dbbe1492 509 goto failure;
RobMeades 118:f3fd6c30dc19 510 // wait some time until baudrate is applied
RobMeades 118:f3fd6c30dc19 511 wait_ms(200); // SARA-G > 40ms
RobMeades 118:f3fd6c30dc19 512 // identify the module
RobMeades 118:f3fd6c30dc19 513 sendFormated("ATI\r\n");
RobMeades 118:f3fd6c30dc19 514 if (RESP_OK != waitFinalResp(_cbATI, &_dev.dev))
RobMeades 118:f3fd6c30dc19 515 goto failure;
RobMeades 118:f3fd6c30dc19 516 if (_dev.dev == DEV_UNKNOWN)
RobMeades 118:f3fd6c30dc19 517 goto failure;
RobMeades 118:f3fd6c30dc19 518 // 3GPP/CDMA device specific init
RobMeades 118:f3fd6c30dc19 519 if (_dev.dev == DEV_LISA_C200) {
RobMeades 118:f3fd6c30dc19 520 // get the manufacturer
RobMeades 118:f3fd6c30dc19 521 sendFormated("AT+GMI\r\n");
RobMeades 118:f3fd6c30dc19 522 if (RESP_OK != waitFinalResp(_cbString, _dev.manu))
RobMeades 118:f3fd6c30dc19 523 goto failure;
RobMeades 118:f3fd6c30dc19 524 // get the model identification
RobMeades 118:f3fd6c30dc19 525 sendFormated("AT+GMM\r\n");
RobMeades 118:f3fd6c30dc19 526 if (RESP_OK != waitFinalResp(_cbString, _dev.model))
RobMeades 118:f3fd6c30dc19 527 goto failure;
RobMeades 118:f3fd6c30dc19 528 // get the sw version
RobMeades 118:f3fd6c30dc19 529 sendFormated("AT+GMR\r\n");
RobMeades 118:f3fd6c30dc19 530 if (RESP_OK != waitFinalResp(_cbString, _dev.ver))
RobMeades 118:f3fd6c30dc19 531 goto failure;
RobMeades 118:f3fd6c30dc19 532 // get the pseudo ESN or MEID
RobMeades 118:f3fd6c30dc19 533 sendFormated("AT+GSN\r\n");
RobMeades 118:f3fd6c30dc19 534 if (RESP_OK != waitFinalResp(_cbString, _dev.meid))
RobMeades 118:f3fd6c30dc19 535 goto failure;
RobMeades 118:f3fd6c30dc19 536 #if 0
RobMeades 118:f3fd6c30dc19 537 // enable power saving
RobMeades 118:f3fd6c30dc19 538 if (_dev.lpm != LPM_DISABLED) {
RobMeades 118:f3fd6c30dc19 539 // enable power saving (requires flow control, cts at least)
RobMeades 118:f3fd6c30dc19 540 sendFormated("AT+UPSV=1,1280\r\n");
RobMeades 118:f3fd6c30dc19 541 if (RESP_OK != waitFinalResp())
RobMeades 118:f3fd6c30dc19 542 goto failure;
RobMeades 118:f3fd6c30dc19 543 _dev.lpm = LPM_ACTIVE;
RobMeades 118:f3fd6c30dc19 544 }
RobMeades 118:f3fd6c30dc19 545 #endif
RobMeades 118:f3fd6c30dc19 546 } else {
RobMeades 118:f3fd6c30dc19 547 if ((_dev.dev == DEV_LISA_U200) || (_dev.dev == DEV_LEON_G200)) {
RobMeades 118:f3fd6c30dc19 548 // enable the network identification feature
RobMeades 118:f3fd6c30dc19 549 sendFormated("AT+UGPIOC=20,2\r\n");
RobMeades 118:f3fd6c30dc19 550 if (RESP_OK != waitFinalResp())
RobMeades 118:f3fd6c30dc19 551 goto failure;
RobMeades 118:f3fd6c30dc19 552 } else if ((_dev.dev == DEV_SARA_U260) || (_dev.dev == DEV_SARA_U270) ||
RobMeades 118:f3fd6c30dc19 553 (_dev.dev == DEV_SARA_G350)) {
RobMeades 118:f3fd6c30dc19 554 // enable the network identification feature
RobMeades 118:f3fd6c30dc19 555 sendFormated("AT+UGPIOC=16,2\r\n");
RobMeades 118:f3fd6c30dc19 556 if (RESP_OK != waitFinalResp())
RobMeades 118:f3fd6c30dc19 557 goto failure;
RobMeades 118:f3fd6c30dc19 558 }
RobMeades 118:f3fd6c30dc19 559 // check the sim card
RobMeades 118:f3fd6c30dc19 560 for (int i = 0; (i < 5) && (_dev.sim != SIM_READY); i++) {
RobMeades 118:f3fd6c30dc19 561 sendFormated("AT+CPIN?\r\n");
RobMeades 118:f3fd6c30dc19 562 int ret = waitFinalResp(_cbCPIN, &_dev.sim);
RobMeades 118:f3fd6c30dc19 563 // having an error here is ok (sim may still be initializing)
RobMeades 118:f3fd6c30dc19 564 if ((RESP_OK != ret) && (RESP_ERROR != ret))
RobMeades 118:f3fd6c30dc19 565 goto failure;
RobMeades 118:f3fd6c30dc19 566 // Enter PIN if needed
RobMeades 118:f3fd6c30dc19 567 if (_dev.sim == SIM_PIN) {
RobMeades 118:f3fd6c30dc19 568 if (!simpin) {
RobMeades 118:f3fd6c30dc19 569 ERROR("SIM PIN not available\r\n");
RobMeades 118:f3fd6c30dc19 570 goto failure;
RobMeades 118:f3fd6c30dc19 571 }
RobMeades 118:f3fd6c30dc19 572 sendFormated("AT+CPIN=%s\r\n", simpin);
RobMeades 118:f3fd6c30dc19 573 if (RESP_OK != waitFinalResp(_cbCPIN, &_dev.sim))
RobMeades 118:f3fd6c30dc19 574 goto failure;
RobMeades 118:f3fd6c30dc19 575 } else if (_dev.sim != SIM_READY) {
RobMeades 118:f3fd6c30dc19 576 wait_ms(1000);
RobMeades 118:f3fd6c30dc19 577 }
RobMeades 118:f3fd6c30dc19 578 }
RobMeades 118:f3fd6c30dc19 579 if (_dev.sim != SIM_READY) {
RobMeades 118:f3fd6c30dc19 580 if (_dev.sim == SIM_MISSING)
RobMeades 118:f3fd6c30dc19 581 ERROR("SIM not inserted\r\n");
RobMeades 118:f3fd6c30dc19 582 goto failure;
RobMeades 118:f3fd6c30dc19 583 }
RobMeades 118:f3fd6c30dc19 584 // get the manufacturer
RobMeades 118:f3fd6c30dc19 585 sendFormated("AT+CGMI\r\n");
RobMeades 118:f3fd6c30dc19 586 if (RESP_OK != waitFinalResp(_cbString, _dev.manu))
RobMeades 118:f3fd6c30dc19 587 goto failure;
RobMeades 118:f3fd6c30dc19 588 // get the model identification
RobMeades 118:f3fd6c30dc19 589 sendFormated("AT+CGMM\r\n");
RobMeades 118:f3fd6c30dc19 590 if (RESP_OK != waitFinalResp(_cbString, _dev.model))
RobMeades 118:f3fd6c30dc19 591 goto failure;
RobMeades 118:f3fd6c30dc19 592 // get the
RobMeades 118:f3fd6c30dc19 593 sendFormated("AT+CGMR\r\n");
RobMeades 118:f3fd6c30dc19 594 if (RESP_OK != waitFinalResp(_cbString, _dev.ver))
RobMeades 118:f3fd6c30dc19 595 goto failure;
RobMeades 118:f3fd6c30dc19 596 // Returns the ICCID (Integrated Circuit Card ID) of the SIM-card.
RobMeades 118:f3fd6c30dc19 597 // ICCID is a serial number identifying the SIM.
RobMeades 118:f3fd6c30dc19 598 sendFormated("AT+CCID\r\n");
RobMeades 118:f3fd6c30dc19 599 if (RESP_OK != waitFinalResp(_cbCCID, _dev.ccid))
RobMeades 118:f3fd6c30dc19 600 goto failure;
RobMeades 118:f3fd6c30dc19 601 // Returns the product serial number, IMEI (International Mobile Equipment Identity)
RobMeades 118:f3fd6c30dc19 602 sendFormated("AT+CGSN\r\n");
RobMeades 118:f3fd6c30dc19 603 if (RESP_OK != waitFinalResp(_cbString, _dev.imei))
RobMeades 118:f3fd6c30dc19 604 goto failure;
RobMeades 118:f3fd6c30dc19 605 // enable power saving
RobMeades 118:f3fd6c30dc19 606 if (_dev.lpm != LPM_DISABLED) {
RobMeades 118:f3fd6c30dc19 607 // enable power saving (requires flow control, cts at least)
RobMeades 118:f3fd6c30dc19 608 sendFormated("AT+UPSV=1\r\n");
RobMeades 118:f3fd6c30dc19 609 if (RESP_OK != waitFinalResp())
RobMeades 118:f3fd6c30dc19 610 goto failure;
RobMeades 118:f3fd6c30dc19 611 _dev.lpm = LPM_ACTIVE;
RobMeades 118:f3fd6c30dc19 612 }
RobMeades 118:f3fd6c30dc19 613 // enable the psd registration unsolicited result code
RobMeades 118:f3fd6c30dc19 614 sendFormated("AT+CGREG=2\r\n");
RobMeades 118:f3fd6c30dc19 615 if (RESP_OK != waitFinalResp())
RobMeades 118:f3fd6c30dc19 616 goto failure;
RobMeades 118:f3fd6c30dc19 617 }
RobMeades 118:f3fd6c30dc19 618 // enable the network registration unsolicited result code
RobMeades 118:f3fd6c30dc19 619 sendFormated("AT+CREG=%d\r\n", (_dev.dev == DEV_LISA_C200) ? 1 : 2);
RobMeades 118:f3fd6c30dc19 620 if (RESP_OK != waitFinalResp())
RobMeades 118:f3fd6c30dc19 621 goto failure;
RobMeades 118:f3fd6c30dc19 622 // Setup SMS in text mode
RobMeades 118:f3fd6c30dc19 623 sendFormated("AT+CMGF=1\r\n");
RobMeades 118:f3fd6c30dc19 624 if (RESP_OK != waitFinalResp())
RobMeades 118:f3fd6c30dc19 625 goto failure;
RobMeades 118:f3fd6c30dc19 626 // setup new message indication
RobMeades 118:f3fd6c30dc19 627 sendFormated("AT+CNMI=2,1\r\n");
RobMeades 118:f3fd6c30dc19 628 if (RESP_OK != waitFinalResp())
RobMeades 118:f3fd6c30dc19 629 goto failure;
RobMeades 118:f3fd6c30dc19 630 // Request IMSI (International Mobile Subscriber Identification)
RobMeades 118:f3fd6c30dc19 631 sendFormated("AT+CIMI\r\n");
RobMeades 118:f3fd6c30dc19 632 if (RESP_OK != waitFinalResp(_cbString, _dev.imsi))
RobMeades 118:f3fd6c30dc19 633 goto failure;
RobMeades 118:f3fd6c30dc19 634 if (status)
RobMeades 118:f3fd6c30dc19 635 memcpy(status, &_dev, sizeof(DevStatus));
RobMeades 118:f3fd6c30dc19 636 UNLOCK();
RobMeades 118:f3fd6c30dc19 637 }
mazgch 31:a0bed6c1e05d 638 return true;
mazgch 95:8282dbbe1492 639 failure:
mazgch 95:8282dbbe1492 640 unlock();
mazgch 95:8282dbbe1492 641 return false;
mazgch 31:a0bed6c1e05d 642 }
mazgch 31:a0bed6c1e05d 643
mazgch 74:208e3e32d263 644 bool MDMParser::powerOff(void)
mazgch 74:208e3e32d263 645 {
mazgch 95:8282dbbe1492 646 bool ok = false;
mazgch 76:f7c3dd568dae 647 if (_init) {
mazgch 95:8282dbbe1492 648 LOCK();
mazgch 76:f7c3dd568dae 649 INFO("Modem::powerOff\r\n");
mazgch 76:f7c3dd568dae 650 sendFormated("AT+CPWROFF\r\n");
mazgch 95:8282dbbe1492 651 if (RESP_OK == waitFinalResp(NULL,NULL,120*1000)) {
mazgch 95:8282dbbe1492 652 _init = false;
mazgch 95:8282dbbe1492 653 ok = true;
mazgch 95:8282dbbe1492 654 }
mazgch 95:8282dbbe1492 655 UNLOCK();
mazgch 76:f7c3dd568dae 656 }
mazgch 95:8282dbbe1492 657 return ok;
mazgch 74:208e3e32d263 658 }
mazgch 74:208e3e32d263 659
mazgch 32:8f12ac182bbb 660 int MDMParser::_cbATI(int type, const char* buf, int len, Dev* dev)
mazgch 31:a0bed6c1e05d 661 {
mazgch 37:cc3433329d66 662 if ((type == TYPE_UNKNOWN) && dev) {
mazgch 98:c786461edd40 663 if (strstr(buf, "SARA-G350")) *dev = DEV_SARA_G350;
mazgch 98:c786461edd40 664 else if (strstr(buf, "LISA-U200")) *dev = DEV_LISA_U200;
mazgch 98:c786461edd40 665 else if (strstr(buf, "LISA-C200")) *dev = DEV_LISA_C200;
mazgch 98:c786461edd40 666 else if (strstr(buf, "SARA-U260")) *dev = DEV_SARA_U260;
mazgch 98:c786461edd40 667 else if (strstr(buf, "SARA-U270")) *dev = DEV_SARA_U270;
mazgch 98:c786461edd40 668 else if (strstr(buf, "LEON-G200")) *dev = DEV_LEON_G200;
mazgch 28:4d9509e3b1cf 669 }
mazgch 31:a0bed6c1e05d 670 return WAIT;
mazgch 31:a0bed6c1e05d 671 }
mazgch 31:a0bed6c1e05d 672
mazgch 31:a0bed6c1e05d 673 int MDMParser::_cbCPIN(int type, const char* buf, int len, Sim* sim)
mazgch 31:a0bed6c1e05d 674 {
mazgch 75:ce6e12067d0c 675 if (sim) {
mazgch 75:ce6e12067d0c 676 if (type == TYPE_PLUS){
mazgch 75:ce6e12067d0c 677 char s[16];
mazgch 75:ce6e12067d0c 678 if (sscanf(buf, "\r\n+CPIN: %[^\r]\r\n", s) >= 1)
mazgch 75:ce6e12067d0c 679 *sim = (0 == strcmp("READY", s)) ? SIM_READY : SIM_PIN;
mazgch 75:ce6e12067d0c 680 } else if (type == TYPE_ERROR) {
mazgch 75:ce6e12067d0c 681 if (strstr(buf, "+CME ERROR: SIM not inserted"))
mazgch 75:ce6e12067d0c 682 *sim = SIM_MISSING;
mazgch 31:a0bed6c1e05d 683 }
mazgch 31:a0bed6c1e05d 684 }
mazgch 31:a0bed6c1e05d 685 return WAIT;
mazgch 21:c4d64830bf02 686 }
mazgch 21:c4d64830bf02 687
mazgch 26:07be5faf8925 688 int MDMParser::_cbCCID(int type, const char* buf, int len, char* ccid)
mazgch 26:07be5faf8925 689 {
mazgch 26:07be5faf8925 690 if ((type == TYPE_PLUS) && ccid){
mazgch 26:07be5faf8925 691 if (sscanf(buf, "\r\n+CCID: %[^\r]\r\n", ccid) == 1)
mazgch 31:a0bed6c1e05d 692 /*TRACE("Got CCID: %s\r\n", ccid)*/;
mazgch 26:07be5faf8925 693 }
mazgch 26:07be5faf8925 694 return WAIT;
mazgch 26:07be5faf8925 695 }
mazgch 26:07be5faf8925 696
mazgch 75:ce6e12067d0c 697 bool MDMParser::registerNet(NetStatus* status /*= NULL*/, int timeout_ms /*= 180000*/)
mazgch 75:ce6e12067d0c 698 {
mazgch 75:ce6e12067d0c 699 Timer timer;
mazgch 75:ce6e12067d0c 700 timer.start();
mazgch 75:ce6e12067d0c 701 INFO("Modem::register\r\n");
mazgch 75:ce6e12067d0c 702 while (!checkNetStatus(status) && !TIMEOUT(timer, timeout_ms))
mazgch 95:8282dbbe1492 703 wait_ms(1000);
mazgch 79:291df065e345 704 if (_net.csd == REG_DENIED) ERROR("CSD Registration Denied\r\n");
mazgch 79:291df065e345 705 if (_net.psd == REG_DENIED) ERROR("PSD Registration Denied\r\n");
mazgch 79:291df065e345 706 return REG_OK(_net.csd) || REG_OK(_net.psd);
mazgch 75:ce6e12067d0c 707 }
mazgch 75:ce6e12067d0c 708
mazgch 28:4d9509e3b1cf 709 bool MDMParser::checkNetStatus(NetStatus* status /*= NULL*/)
mazgch 21:c4d64830bf02 710 {
mazgch 95:8282dbbe1492 711 bool ok = false;
mazgch 95:8282dbbe1492 712 LOCK();
mazgch 75:ce6e12067d0c 713 memset(&_net, 0, sizeof(_net));
mazgch 75:ce6e12067d0c 714 _net.lac = 0xFFFF;
mazgch 75:ce6e12067d0c 715 _net.ci = 0xFFFFFFFF;
mazgch 21:c4d64830bf02 716 // check registration
RobMeades 122:c6b2fa1928f2 717 if (_dev.dev == DEV_LISA_N100) {
RobMeades 118:f3fd6c30dc19 718 // Neul modem --------------------------
RobMeades 118:f3fd6c30dc19 719 sendFormated("AT+RAS\r\n");
RobMeades 127:4df82b52f834 720 if (waitFinalResp(_cbRAS, &ok))
RobMeades 127:4df82b52f834 721 waitFinalResp(NULL); // Must wait for the OK string also
RobMeades 127:4df82b52f834 722 if (!ok)
RobMeades 118:f3fd6c30dc19 723 goto failure;
RobMeades 126:76b578ec2912 724 if (ok) {
RobMeades 126:76b578ec2912 725 _net.psd = REG_HOME;
RobMeades 126:76b578ec2912 726 if (!getRssi (&(_net.rssi)))
RobMeades 126:76b578ec2912 727 goto failure;
RobMeades 126:76b578ec2912 728 }
RobMeades 118:f3fd6c30dc19 729 } else {
RobMeades 118:f3fd6c30dc19 730 sendFormated("AT+CREG?\r\n");
RobMeades 118:f3fd6c30dc19 731 waitFinalResp(); // don't fail as service could be not subscribed
RobMeades 118:f3fd6c30dc19 732 if (_dev.dev != DEV_LISA_C200) {
RobMeades 118:f3fd6c30dc19 733 // check PSD registration
RobMeades 118:f3fd6c30dc19 734 sendFormated("AT+CGREG?\r\n");
RobMeades 118:f3fd6c30dc19 735 waitFinalResp(); // don't fail as service could be not subscribed
RobMeades 118:f3fd6c30dc19 736 }
RobMeades 118:f3fd6c30dc19 737 if (REG_OK(_net.csd) || REG_OK(_net.psd))
RobMeades 118:f3fd6c30dc19 738 {
RobMeades 118:f3fd6c30dc19 739 // check modem specific status messages
RobMeades 118:f3fd6c30dc19 740 if (_dev.dev == DEV_LISA_C200) {
RobMeades 118:f3fd6c30dc19 741 sendFormated("AT+CSS?\r\n");
RobMeades 118:f3fd6c30dc19 742 if (RESP_OK != waitFinalResp())
mazgch 95:8282dbbe1492 743 goto failure;
RobMeades 118:f3fd6c30dc19 744 while (1) {
RobMeades 118:f3fd6c30dc19 745 // get the Telephone number
RobMeades 118:f3fd6c30dc19 746 sendFormated("AT$MDN?\r\n");
RobMeades 118:f3fd6c30dc19 747 if (RESP_OK != waitFinalResp(_cbString, _net.num))
mazgch 95:8282dbbe1492 748 goto failure;
RobMeades 118:f3fd6c30dc19 749 // check if we have a Mobile Directory Number
RobMeades 118:f3fd6c30dc19 750 if (*_net.num && (memcmp(_net.num, "000000", 6) != 0))
RobMeades 118:f3fd6c30dc19 751 break;
RobMeades 118:f3fd6c30dc19 752
RobMeades 118:f3fd6c30dc19 753 INFO("Device not yet activated\r\n");
RobMeades 118:f3fd6c30dc19 754 INFO("Make sure you have a valid contract with the network operator for this device.\r\n");
RobMeades 118:f3fd6c30dc19 755 // Check if the the version contains a V for Verizon
RobMeades 118:f3fd6c30dc19 756 // Verizon: E0.V.xx.00.xxR,
RobMeades 118:f3fd6c30dc19 757 // Sprint E0.S.xx.00.xxR
RobMeades 118:f3fd6c30dc19 758 if (_dev.ver[3] == 'V') {
RobMeades 118:f3fd6c30dc19 759 int i;
RobMeades 118:f3fd6c30dc19 760 INFO("Start device over-the-air activation (this can take a few minutes)\r\n");
RobMeades 118:f3fd6c30dc19 761 sendFormated("AT+CDV=*22899\r\n");
RobMeades 118:f3fd6c30dc19 762 i = 1;
RobMeades 118:f3fd6c30dc19 763 if ((RESP_OK != waitFinalResp(_cbUACTIND, &i, 120*1000)) || (i == 1)) {
RobMeades 118:f3fd6c30dc19 764 ERROR("Device over-the-air activation failed\r\n");
RobMeades 118:f3fd6c30dc19 765 goto failure;
RobMeades 118:f3fd6c30dc19 766 }
RobMeades 118:f3fd6c30dc19 767 INFO("Device over-the-air activation successful\r\n");
RobMeades 118:f3fd6c30dc19 768
RobMeades 118:f3fd6c30dc19 769 INFO("Start PRL over-the-air update (this can take a few minutes)\r\n");
RobMeades 118:f3fd6c30dc19 770 sendFormated("AT+CDV=*22891\r\n");
RobMeades 118:f3fd6c30dc19 771 i = 1;
RobMeades 118:f3fd6c30dc19 772 if ((RESP_OK != waitFinalResp(_cbUACTIND, &i, 120*1000)) || (i == 1)) {
RobMeades 118:f3fd6c30dc19 773 ERROR("PRL over-the-air update failed\r\n");
RobMeades 118:f3fd6c30dc19 774 goto failure;
RobMeades 118:f3fd6c30dc19 775 }
RobMeades 118:f3fd6c30dc19 776 INFO("PRL over-the-air update successful\r\n");
RobMeades 118:f3fd6c30dc19 777
RobMeades 118:f3fd6c30dc19 778 } else {
RobMeades 118:f3fd6c30dc19 779 // Sprint or Aeris
RobMeades 118:f3fd6c30dc19 780 INFO("Wait for OMA-DM over-the-air activation (this can take a few minutes)\r\n");
RobMeades 118:f3fd6c30dc19 781 wait_ms(120*1000);
mazgch 81:3966a5c17037 782 }
mazgch 81:3966a5c17037 783 }
RobMeades 118:f3fd6c30dc19 784 // get the the Network access identifier string
RobMeades 118:f3fd6c30dc19 785 char nai[64];
RobMeades 118:f3fd6c30dc19 786 sendFormated("AT$QCMIPNAI?\r\n");
RobMeades 118:f3fd6c30dc19 787 if (RESP_OK != waitFinalResp(_cbString, nai))
RobMeades 118:f3fd6c30dc19 788 goto failure;
RobMeades 118:f3fd6c30dc19 789 } else {
RobMeades 118:f3fd6c30dc19 790 sendFormated("AT+COPS?\r\n");
RobMeades 118:f3fd6c30dc19 791 if (RESP_OK != waitFinalResp(_cbCOPS, &_net))
RobMeades 118:f3fd6c30dc19 792 goto failure;
RobMeades 118:f3fd6c30dc19 793 // get the MSISDNs related to this subscriber
RobMeades 118:f3fd6c30dc19 794 sendFormated("AT+CNUM\r\n");
RobMeades 118:f3fd6c30dc19 795 if (RESP_OK != waitFinalResp(_cbCNUM, _net.num))
RobMeades 118:f3fd6c30dc19 796 goto failure;
RobMeades 118:f3fd6c30dc19 797 }
RobMeades 118:f3fd6c30dc19 798 // get the signal strength indication
RobMeades 118:f3fd6c30dc19 799 sendFormated("AT+CSQ\r\n");
RobMeades 118:f3fd6c30dc19 800 if (RESP_OK != waitFinalResp(_cbCSQ, &_net))
mazgch 95:8282dbbe1492 801 goto failure;
RobMeades 118:f3fd6c30dc19 802 }
mazgch 75:ce6e12067d0c 803 }
mazgch 28:4d9509e3b1cf 804 if (status) {
mazgch 31:a0bed6c1e05d 805 memcpy(status, &_net, sizeof(NetStatus));
mazgch 25:4045d02e44f1 806 }
RobMeades 122:c6b2fa1928f2 807 if (_dev.dev == DEV_LISA_N100) {
RobMeades 126:76b578ec2912 808 ok = REG_OK(_net.psd); // No CSD for the Neul modem
RobMeades 118:f3fd6c30dc19 809 } else {
RobMeades 118:f3fd6c30dc19 810 ok = REG_DONE(_net.csd) && REG_DONE(_net.psd);
RobMeades 118:f3fd6c30dc19 811 }
mazgch 95:8282dbbe1492 812 UNLOCK();
mazgch 95:8282dbbe1492 813 return ok;
mazgch 95:8282dbbe1492 814 failure:
mazgch 95:8282dbbe1492 815 unlock();
mazgch 95:8282dbbe1492 816 return false;
mazgch 31:a0bed6c1e05d 817 }
mazgch 31:a0bed6c1e05d 818
mazgch 31:a0bed6c1e05d 819 int MDMParser::_cbCOPS(int type, const char* buf, int len, NetStatus* status)
mazgch 31:a0bed6c1e05d 820 {
mazgch 31:a0bed6c1e05d 821 if ((type == TYPE_PLUS) && status){
mazgch 31:a0bed6c1e05d 822 int act = 99;
mazgch 31:a0bed6c1e05d 823 // +COPS: <mode>[,<format>,<oper>[,<AcT>]]
mazgch 31:a0bed6c1e05d 824 if (sscanf(buf, "\r\n+COPS: %*d,%*d,\"%[^\"]\",%d",status->opr,&act) >= 1) {
mazgch 31:a0bed6c1e05d 825 if (act == 0) status->act = ACT_GSM; // 0: GSM,
mazgch 31:a0bed6c1e05d 826 else if (act == 2) status->act = ACT_UTRAN; // 2: UTRAN
mazgch 31:a0bed6c1e05d 827 }
mazgch 31:a0bed6c1e05d 828 }
mazgch 31:a0bed6c1e05d 829 return WAIT;
mazgch 31:a0bed6c1e05d 830 }
mazgch 31:a0bed6c1e05d 831
mazgch 31:a0bed6c1e05d 832 int MDMParser::_cbCNUM(int type, const char* buf, int len, char* num)
mazgch 31:a0bed6c1e05d 833 {
mazgch 31:a0bed6c1e05d 834 if ((type == TYPE_PLUS) && num){
mazgch 31:a0bed6c1e05d 835 int a;
mazgch 31:a0bed6c1e05d 836 if ((sscanf(buf, "\r\n+CNUM: \"My Number\",\"%31[^\"]\",%d", num, &a) == 2) &&
mazgch 31:a0bed6c1e05d 837 ((a == 129) || (a == 145))) {
mazgch 31:a0bed6c1e05d 838 }
mazgch 31:a0bed6c1e05d 839 }
mazgch 31:a0bed6c1e05d 840 return WAIT;
mazgch 31:a0bed6c1e05d 841 }
mazgch 31:a0bed6c1e05d 842
mazgch 54:7ba8e4c218e2 843 int MDMParser::_cbCSQ(int type, const char* buf, int len, NetStatus* status)
mazgch 31:a0bed6c1e05d 844 {
mazgch 54:7ba8e4c218e2 845 if ((type == TYPE_PLUS) && status){
mazgch 54:7ba8e4c218e2 846 int a,b;
mazgch 54:7ba8e4c218e2 847 char _ber[] = { 49, 43, 37, 25, 19, 13, 7, 0 }; // see 3GPP TS 45.008 [20] subclause 8.2.4
mazgch 31:a0bed6c1e05d 848 // +CSQ: <rssi>,<qual>
mazgch 54:7ba8e4c218e2 849 if (sscanf(buf, "\r\n+CSQ: %d,%d",&a,&b) == 2) {
mazgch 54:7ba8e4c218e2 850 if (a != 99) status->rssi = -113 + 2*a; // 0: -113 1: -111 ... 30: -53 dBm with 2 dBm steps
mazgch 54:7ba8e4c218e2 851 if ((b != 99) && (b < sizeof(_ber))) status->ber = _ber[b]; //
mazgch 31:a0bed6c1e05d 852 }
mazgch 31:a0bed6c1e05d 853 }
mazgch 31:a0bed6c1e05d 854 return WAIT;
mazgch 31:a0bed6c1e05d 855 }
mazgch 21:c4d64830bf02 856
mazgch 81:3966a5c17037 857 int MDMParser::_cbUACTIND(int type, const char* buf, int len, int* i)
mazgch 81:3966a5c17037 858 {
mazgch 81:3966a5c17037 859 if ((type == TYPE_PLUS) && i){
mazgch 82:055dcfcf9dcc 860 int a;
mazgch 82:055dcfcf9dcc 861 if (sscanf(buf, "\r\n+UACTIND: %d", &a) == 1) {
mazgch 82:055dcfcf9dcc 862 *i = a;
mazgch 81:3966a5c17037 863 }
mazgch 81:3966a5c17037 864 }
mazgch 81:3966a5c17037 865 return WAIT;
mazgch 81:3966a5c17037 866 }
mazgch 81:3966a5c17037 867
RobMeades 118:f3fd6c30dc19 868 // Neul radio activity status
RobMeades 118:f3fd6c30dc19 869 int MDMParser::_cbRAS(int type, const char* buf, int len, bool* connected)
RobMeades 118:f3fd6c30dc19 870 {
RobMeades 118:f3fd6c30dc19 871 *connected = false;
RobMeades 118:f3fd6c30dc19 872 char status[32];
RobMeades 118:f3fd6c30dc19 873 if ((type == TYPE_PLUS) && connected) {
RobMeades 118:f3fd6c30dc19 874 // +RAS: <status>
RobMeades 118:f3fd6c30dc19 875 if (sscanf(buf, "\r\n+RAS:%s", status) == 1) {
RobMeades 126:76b578ec2912 876 if (strcmp ("CONNECTED", status) == 0) {
RobMeades 118:f3fd6c30dc19 877 *connected = true;
RobMeades 118:f3fd6c30dc19 878 }
RobMeades 118:f3fd6c30dc19 879 return RESP_OK;
RobMeades 118:f3fd6c30dc19 880 }
RobMeades 118:f3fd6c30dc19 881 }
RobMeades 118:f3fd6c30dc19 882 return WAIT;
RobMeades 118:f3fd6c30dc19 883 }
RobMeades 118:f3fd6c30dc19 884
mazgch 21:c4d64830bf02 885 // ----------------------------------------------------------------
mazgch 21:c4d64830bf02 886 // internet connection
mazgch 21:c4d64830bf02 887
mazgch 79:291df065e345 888 MDMParser::IP MDMParser::join(const char* apn /*= NULL*/, const char* username /*= NULL*/,
mazgch 79:291df065e345 889 const char* password /*= NULL*/, Auth auth /*= AUTH_DETECT*/)
mazgch 21:c4d64830bf02 890 {
mazgch 95:8282dbbe1492 891 LOCK();
mazgch 78:caf0014375cb 892 INFO("Modem::join\r\n");
mazgch 32:8f12ac182bbb 893 _ip = NOIP;
mazgch 32:8f12ac182bbb 894 if (_dev.dev == DEV_LISA_C200) {
mazgch 76:f7c3dd568dae 895 // make a dumy dns lookup (which will fail, so ignore the result)
mazgch 76:f7c3dd568dae 896 sendFormated("AT+UDNSRN=0,\"u-blox.com\"\r\n");
mazgch 76:f7c3dd568dae 897 waitFinalResp();
mazgch 76:f7c3dd568dae 898 // This fake lookup will enable the IP connection and we
mazgch 76:f7c3dd568dae 899 // should have an IP after this, so we check it
mazgch 76:f7c3dd568dae 900
mazgch 21:c4d64830bf02 901 //Get local IP address
mazgch 21:c4d64830bf02 902 sendFormated("AT+CMIP?\r\n");
mazgch 52:8071747a7cb3 903 if (RESP_OK != waitFinalResp(_cbCMIP, &_ip))
mazgch 95:8282dbbe1492 904 goto failure;
mazgch 21:c4d64830bf02 905 } else {
mazgch 21:c4d64830bf02 906 // check gprs attach status
mazgch 72:d1e943ad6558 907 sendFormated("AT+CGATT=1\r\n");
mazgch 74:208e3e32d263 908 if (RESP_OK != waitFinalResp(NULL,NULL,3*60*1000))
mazgch 95:8282dbbe1492 909 goto failure;
mazgch 31:a0bed6c1e05d 910
mazgch 31:a0bed6c1e05d 911 // Check the profile
mazgch 31:a0bed6c1e05d 912 int a = 0;
mazgch 79:291df065e345 913 bool force = true;
mazgch 31:a0bed6c1e05d 914 sendFormated("AT+UPSND=" PROFILE ",8\r\n");
mazgch 52:8071747a7cb3 915 if (RESP_OK != waitFinalResp(_cbUPSND, &a))
mazgch 95:8282dbbe1492 916 goto failure;
mazgch 79:291df065e345 917 if (a == 1 && force) {
mazgch 31:a0bed6c1e05d 918 // disconnect the profile already if it is connected
mazgch 31:a0bed6c1e05d 919 sendFormated("AT+UPSDA=" PROFILE ",4\r\n");
mazgch 58:e38a2e942fbb 920 if (RESP_OK != waitFinalResp(NULL,NULL,40*1000))
mazgch 95:8282dbbe1492 921 goto failure;
mazgch 79:291df065e345 922 a = 0;
mazgch 31:a0bed6c1e05d 923 }
mazgch 79:291df065e345 924 if (a == 0) {
mazgch 84:a05edb010176 925 bool ok = false;
mazgch 84:a05edb010176 926 // try to lookup the apn settings from our local database by mccmnc
mazgch 84:a05edb010176 927 const char* config = NULL;
mazgch 88:135fb4bb7aac 928 if (!apn && !username && !password)
mazgch 88:135fb4bb7aac 929 config = apnconfig(_dev.imsi);
mazgch 84:a05edb010176 930
mazgch 79:291df065e345 931 // Set up the dynamic IP address assignment.
mazgch 79:291df065e345 932 sendFormated("AT+UPSD=" PROFILE ",7,\"0.0.0.0\"\r\n");
mazgch 52:8071747a7cb3 933 if (RESP_OK != waitFinalResp())
mazgch 95:8282dbbe1492 934 goto failure;
mazgch 84:a05edb010176 935
mazgch 84:a05edb010176 936 do {
mazgch 84:a05edb010176 937 if (config) {
mazgch 85:dd8f4f0d0ca9 938 apn = _APN_GET(config);
mazgch 85:dd8f4f0d0ca9 939 username = _APN_GET(config);
mazgch 85:dd8f4f0d0ca9 940 password = _APN_GET(config);
mazgch 84:a05edb010176 941 TRACE("Testing APN Settings(\"%s\",\"%s\",\"%s\")\r\n", apn, username, password);
mazgch 79:291df065e345 942 }
mazgch 84:a05edb010176 943 // Set up the APN
mazgch 90:3915192f6d7e 944 if (apn && *apn) {
mazgch 90:3915192f6d7e 945 sendFormated("AT+UPSD=" PROFILE ",1,\"%s\"\r\n", apn);
mazgch 90:3915192f6d7e 946 if (RESP_OK != waitFinalResp())
mazgch 95:8282dbbe1492 947 goto failure;
mazgch 90:3915192f6d7e 948 }
mazgch 90:3915192f6d7e 949 if (username && *username) {
mazgch 90:3915192f6d7e 950 sendFormated("AT+UPSD=" PROFILE ",2,\"%s\"\r\n", username);
mazgch 90:3915192f6d7e 951 if (RESP_OK != waitFinalResp())
mazgch 95:8282dbbe1492 952 goto failure;
mazgch 90:3915192f6d7e 953 }
mazgch 90:3915192f6d7e 954 if (password && *password) {
mazgch 90:3915192f6d7e 955 sendFormated("AT+UPSD=" PROFILE ",3,\"%s\"\r\n", password);
mazgch 90:3915192f6d7e 956 if (RESP_OK != waitFinalResp())
mazgch 95:8282dbbe1492 957 goto failure;
mazgch 90:3915192f6d7e 958 }
mazgch 84:a05edb010176 959 // try different Authentication Protocols
mazgch 84:a05edb010176 960 // 0 = none
mazgch 84:a05edb010176 961 // 1 = PAP (Password Authentication Protocol)
mazgch 84:a05edb010176 962 // 2 = CHAP (Challenge Handshake Authentication Protocol)
mazgch 84:a05edb010176 963 for (int i = AUTH_NONE; i <= AUTH_CHAP && !ok; i ++) {
mazgch 84:a05edb010176 964 if ((auth == AUTH_DETECT) || (auth == i)) {
mazgch 84:a05edb010176 965 // Set up the Authentication Protocol
mazgch 84:a05edb010176 966 sendFormated("AT+UPSD=" PROFILE ",6,%d\r\n", i);
mazgch 84:a05edb010176 967 if (RESP_OK != waitFinalResp())
mazgch 95:8282dbbe1492 968 goto failure;
mazgch 84:a05edb010176 969 // Activate the profile and make connection
mazgch 84:a05edb010176 970 sendFormated("AT+UPSDA=" PROFILE ",3\r\n");
mazgch 84:a05edb010176 971 if (RESP_OK == waitFinalResp(NULL,NULL,150*1000))
mazgch 84:a05edb010176 972 ok = true;
mazgch 84:a05edb010176 973 }
mazgch 84:a05edb010176 974 }
mazgch 99:3116d3e900ed 975 } while (!ok && config && *config); // maybe use next setting ?
mazgch 84:a05edb010176 976 if (!ok) {
mazgch 79:291df065e345 977 ERROR("Your modem APN/password/username may be wrong\r\n");
mazgch 95:8282dbbe1492 978 goto failure;
mazgch 79:291df065e345 979 }
mazgch 74:208e3e32d263 980 }
mazgch 21:c4d64830bf02 981 //Get local IP address
mazgch 21:c4d64830bf02 982 sendFormated("AT+UPSND=" PROFILE ",0\r\n");
mazgch 52:8071747a7cb3 983 if (RESP_OK != waitFinalResp(_cbUPSND, &_ip))
mazgch 95:8282dbbe1492 984 goto failure;
mazgch 31:a0bed6c1e05d 985 }
mazgch 95:8282dbbe1492 986 UNLOCK();
mazgch 32:8f12ac182bbb 987 return _ip;
mazgch 95:8282dbbe1492 988 failure:
mazgch 95:8282dbbe1492 989 unlock();
mazgch 95:8282dbbe1492 990 return NOIP;
mazgch 31:a0bed6c1e05d 991 }
mazgch 31:a0bed6c1e05d 992
mazgch 84:a05edb010176 993 int MDMParser::_cbUDOPN(int type, const char* buf, int len, char* mccmnc)
mazgch 84:a05edb010176 994 {
mazgch 84:a05edb010176 995 if ((type == TYPE_PLUS) && mccmnc) {
mazgch 84:a05edb010176 996 if (sscanf(buf, "\r\n+UDOPN: 0,\"%[^\"]\"", mccmnc) == 1)
mazgch 84:a05edb010176 997 ;
mazgch 84:a05edb010176 998 }
mazgch 84:a05edb010176 999 return WAIT;
mazgch 84:a05edb010176 1000 }
mazgch 84:a05edb010176 1001
mazgch 32:8f12ac182bbb 1002 int MDMParser::_cbCMIP(int type, const char* buf, int len, IP* ip)
mazgch 32:8f12ac182bbb 1003 {
mazgch 102:fb982ff9da82 1004 if ((type == TYPE_UNKNOWN) && ip) {
mazgch 32:8f12ac182bbb 1005 int a,b,c,d;
mazgch 102:fb982ff9da82 1006 if (sscanf(buf, "\r\n" IPSTR, &a,&b,&c,&d) == 4)
mazgch 32:8f12ac182bbb 1007 *ip = IPADR(a,b,c,d);
mazgch 32:8f12ac182bbb 1008 }
mazgch 32:8f12ac182bbb 1009 return WAIT;
mazgch 32:8f12ac182bbb 1010 }
mazgch 32:8f12ac182bbb 1011
mazgch 31:a0bed6c1e05d 1012 int MDMParser::_cbUPSND(int type, const char* buf, int len, int* act)
mazgch 31:a0bed6c1e05d 1013 {
mazgch 31:a0bed6c1e05d 1014 if ((type == TYPE_PLUS) && act) {
mazgch 31:a0bed6c1e05d 1015 if (sscanf(buf, "\r\n+UPSND: %*d,%*d,%d", act) == 1)
mazgch 31:a0bed6c1e05d 1016 /*nothing*/;
mazgch 21:c4d64830bf02 1017 }
mazgch 31:a0bed6c1e05d 1018 return WAIT;
mazgch 31:a0bed6c1e05d 1019 }
mazgch 31:a0bed6c1e05d 1020
mazgch 31:a0bed6c1e05d 1021 int MDMParser::_cbUPSND(int type, const char* buf, int len, IP* ip)
mazgch 31:a0bed6c1e05d 1022 {
mazgch 31:a0bed6c1e05d 1023 if ((type == TYPE_PLUS) && ip) {
mazgch 31:a0bed6c1e05d 1024 int a,b,c,d;
mazgch 31:a0bed6c1e05d 1025 // +UPSND=<profile_id>,<param_tag>[,<dynamic_param_val>]
mazgch 31:a0bed6c1e05d 1026 if (sscanf(buf, "\r\n+UPSND: " PROFILE ",0,\"" IPSTR "\"", &a,&b,&c,&d) == 4)
mazgch 31:a0bed6c1e05d 1027 *ip = IPADR(a,b,c,d);
mazgch 31:a0bed6c1e05d 1028 }
mazgch 31:a0bed6c1e05d 1029 return WAIT;
mazgch 31:a0bed6c1e05d 1030 }
mazgch 31:a0bed6c1e05d 1031
mazgch 31:a0bed6c1e05d 1032 int MDMParser::_cbUDNSRN(int type, const char* buf, int len, IP* ip)
mazgch 31:a0bed6c1e05d 1033 {
mazgch 31:a0bed6c1e05d 1034 if ((type == TYPE_PLUS) && ip) {
mazgch 31:a0bed6c1e05d 1035 int a,b,c,d;
mazgch 95:8282dbbe1492 1036 if (sscanf(buf, "\r\n+UDNSRN: \"" IPSTR "\"", &a,&b,&c,&d) == 4)
mazgch 31:a0bed6c1e05d 1037 *ip = IPADR(a,b,c,d);
mazgch 31:a0bed6c1e05d 1038 }
mazgch 31:a0bed6c1e05d 1039 return WAIT;
mazgch 21:c4d64830bf02 1040 }
mazgch 21:c4d64830bf02 1041
mazgch 21:c4d64830bf02 1042 bool MDMParser::disconnect(void)
mazgch 21:c4d64830bf02 1043 {
mazgch 95:8282dbbe1492 1044 bool ok = false;
mazgch 95:8282dbbe1492 1045 LOCK();
mazgch 74:208e3e32d263 1046 INFO("Modem::disconnect\r\n");
mazgch 95:8282dbbe1492 1047 if (_ip != NOIP) {
mazgch 95:8282dbbe1492 1048 if (_dev.dev == DEV_LISA_C200) {
mazgch 95:8282dbbe1492 1049 // There something to do here
mazgch 95:8282dbbe1492 1050 _ip = NOIP;
mazgch 95:8282dbbe1492 1051 ok = true;
mazgch 95:8282dbbe1492 1052 } else {
mazgch 95:8282dbbe1492 1053 sendFormated("AT+UPSDA=" PROFILE ",4\r\n");
mazgch 95:8282dbbe1492 1054 if (RESP_OK != waitFinalResp()) {
mazgch 95:8282dbbe1492 1055 _ip = NOIP;
mazgch 95:8282dbbe1492 1056 ok = true;
mazgch 95:8282dbbe1492 1057 }
mazgch 95:8282dbbe1492 1058 }
mazgch 21:c4d64830bf02 1059 }
mazgch 95:8282dbbe1492 1060 UNLOCK();
mazgch 95:8282dbbe1492 1061 return ok;
mazgch 21:c4d64830bf02 1062 }
mazgch 21:c4d64830bf02 1063
mazgch 31:a0bed6c1e05d 1064 MDMParser::IP MDMParser::gethostbyname(const char* host)
mazgch 21:c4d64830bf02 1065 {
mazgch 31:a0bed6c1e05d 1066 IP ip = NOIP;
mazgch 31:a0bed6c1e05d 1067 int a,b,c,d;
mazgch 31:a0bed6c1e05d 1068 if (sscanf(host, IPSTR, &a,&b,&c,&d) == 4)
mazgch 31:a0bed6c1e05d 1069 ip = IPADR(a,b,c,d);
mazgch 31:a0bed6c1e05d 1070 else {
mazgch 95:8282dbbe1492 1071 LOCK();
mazgch 31:a0bed6c1e05d 1072 sendFormated("AT+UDNSRN=0,\"%s\"\r\n", host);
mazgch 52:8071747a7cb3 1073 if (RESP_OK != waitFinalResp(_cbUDNSRN, &ip))
mazgch 95:8282dbbe1492 1074 ip = NOIP;
mazgch 95:8282dbbe1492 1075 UNLOCK();
mazgch 21:c4d64830bf02 1076 }
mazgch 31:a0bed6c1e05d 1077 return ip;
mazgch 21:c4d64830bf02 1078 }
mazgch 21:c4d64830bf02 1079
mazgch 21:c4d64830bf02 1080 // ----------------------------------------------------------------
mazgch 21:c4d64830bf02 1081 // sockets
mazgch 21:c4d64830bf02 1082
mazgch 103:197fa7920ad8 1083 int MDMParser::_cbUSOCR(int type, const char* buf, int len, int* handle)
mazgch 21:c4d64830bf02 1084 {
mazgch 103:197fa7920ad8 1085 if ((type == TYPE_PLUS) && handle) {
mazgch 108:254bf037f83f 1086 // +USOCR: socket
mazgch 108:254bf037f83f 1087 if (sscanf(buf, "\r\n+USOCR: %d", handle) == 1)
mazgch 108:254bf037f83f 1088 /*nothing*/;
mazgch 21:c4d64830bf02 1089 }
mazgch 21:c4d64830bf02 1090 return WAIT;
mazgch 21:c4d64830bf02 1091 }
mazgch 21:c4d64830bf02 1092
mazgch 63:42cb563a25bc 1093 int MDMParser::socketSocket(IpProtocol ipproto, int port)
mazgch 21:c4d64830bf02 1094 {
mazgch 103:197fa7920ad8 1095 int socket;
mazgch 95:8282dbbe1492 1096 LOCK();
mazgch 103:197fa7920ad8 1097 // find an free socket
mazgch 103:197fa7920ad8 1098 socket = _findSocket();
mazgch 47:9a89e5195721 1099 TRACE("socketSocket(%d)\r\n", ipproto);
mazgch 95:8282dbbe1492 1100 if (socket != SOCKET_ERROR) {
mazgch 106:18aeacdae391 1101 if (ipproto == IPPROTO_UDP) {
mazgch 106:18aeacdae391 1102 // sending port can only be set on 2G/3G modules
mazgch 106:18aeacdae391 1103 if ((port != -1) && (_dev.dev != DEV_LISA_C200)) {
mazgch 106:18aeacdae391 1104 sendFormated("AT+USOCR=17,%d\r\n", port);
mazgch 106:18aeacdae391 1105 } else {
mazgch 106:18aeacdae391 1106 sendFormated("AT+USOCR=17\r\n");
mazgch 106:18aeacdae391 1107 }
mazgch 103:197fa7920ad8 1108 } else /*(ipproto == IPPROTO_TCP)*/ {
mazgch 103:197fa7920ad8 1109 sendFormated("AT+USOCR=6\r\n");
mazgch 103:197fa7920ad8 1110 }
mazgch 103:197fa7920ad8 1111 int handle = SOCKET_ERROR;
mazgch 103:197fa7920ad8 1112 if ((RESP_OK == waitFinalResp(_cbUSOCR, &handle)) &&
mazgch 103:197fa7920ad8 1113 (handle != SOCKET_ERROR)) {
mazgch 103:197fa7920ad8 1114 TRACE("Socket %d: handle %d was created\r\n", socket, handle);
mazgch 103:197fa7920ad8 1115 _sockets[socket].handle = handle;
mazgch 103:197fa7920ad8 1116 _sockets[socket].timeout_ms = TIMEOUT_BLOCKING;
mazgch 103:197fa7920ad8 1117 _sockets[socket].connected = false;
mazgch 103:197fa7920ad8 1118 _sockets[socket].pending = 0;
mazgch 103:197fa7920ad8 1119 }
mazgch 103:197fa7920ad8 1120 else
mazgch 103:197fa7920ad8 1121 socket = SOCKET_ERROR;
mazgch 95:8282dbbe1492 1122 }
mazgch 95:8282dbbe1492 1123 UNLOCK();
mazgch 21:c4d64830bf02 1124 return socket;
mazgch 21:c4d64830bf02 1125 }
mazgch 21:c4d64830bf02 1126
mazgch 21:c4d64830bf02 1127 bool MDMParser::socketConnect(int socket, const char * host, int port)
mazgch 21:c4d64830bf02 1128 {
mazgch 31:a0bed6c1e05d 1129 IP ip = gethostbyname(host);
mazgch 31:a0bed6c1e05d 1130 if (ip == NOIP)
mazgch 21:c4d64830bf02 1131 return false;
mazgch 21:c4d64830bf02 1132 // connect to socket
mazgch 95:8282dbbe1492 1133 bool ok = false;
mazgch 95:8282dbbe1492 1134 LOCK();
mazgch 103:197fa7920ad8 1135 if (ISSOCKET(socket) && (!_sockets[socket].connected)) {
mazgch 95:8282dbbe1492 1136 TRACE("socketConnect(%d,%s,%d)\r\n", socket,host,port);
mazgch 103:197fa7920ad8 1137 sendFormated("AT+USOCO=%d,\"" IPSTR "\",%d\r\n", _sockets[socket].handle, IPNUM(ip), port);
mazgch 95:8282dbbe1492 1138 if (RESP_OK == waitFinalResp())
mazgch 103:197fa7920ad8 1139 ok = _sockets[socket].connected = true;
mazgch 95:8282dbbe1492 1140 }
mazgch 95:8282dbbe1492 1141 UNLOCK();
mazgch 95:8282dbbe1492 1142 return ok;
mazgch 21:c4d64830bf02 1143 }
mazgch 21:c4d64830bf02 1144
mazgch 44:9d12223b78ff 1145 bool MDMParser::socketIsConnected(int socket)
mazgch 44:9d12223b78ff 1146 {
mazgch 95:8282dbbe1492 1147 bool ok = false;
mazgch 95:8282dbbe1492 1148 LOCK();
mazgch 103:197fa7920ad8 1149 ok = ISSOCKET(socket) && _sockets[socket].connected;
mazgch 107:436ee320efd6 1150 TRACE("socketIsConnected(%d) %s\r\n", socket, ok?"yes":"no");
mazgch 95:8282dbbe1492 1151 UNLOCK();
mazgch 95:8282dbbe1492 1152 return ok;
mazgch 44:9d12223b78ff 1153 }
mazgch 44:9d12223b78ff 1154
mazgch 66:69072b3c5bca 1155 bool MDMParser::socketSetBlocking(int socket, int timeout_ms)
mazgch 44:9d12223b78ff 1156 {
mazgch 95:8282dbbe1492 1157 bool ok = false;
mazgch 95:8282dbbe1492 1158 LOCK();
mazgch 103:197fa7920ad8 1159 TRACE("socketSetBlocking(%d,%d)\r\n", socket,timeout_ms);
mazgch 95:8282dbbe1492 1160 if (ISSOCKET(socket)) {
mazgch 95:8282dbbe1492 1161 _sockets[socket].timeout_ms = timeout_ms;
mazgch 95:8282dbbe1492 1162 ok = true;
mazgch 95:8282dbbe1492 1163 }
mazgch 95:8282dbbe1492 1164 UNLOCK();
mazgch 95:8282dbbe1492 1165 return ok;
mazgch 44:9d12223b78ff 1166 }
mazgch 44:9d12223b78ff 1167
mazgch 21:c4d64830bf02 1168 bool MDMParser::socketClose(int socket)
mazgch 21:c4d64830bf02 1169 {
mazgch 95:8282dbbe1492 1170 bool ok = false;
mazgch 95:8282dbbe1492 1171 LOCK();
mazgch 103:197fa7920ad8 1172 if (ISSOCKET(socket) && _sockets[socket].connected) {
mazgch 95:8282dbbe1492 1173 TRACE("socketClose(%d)\r\n", socket);
mazgch 103:197fa7920ad8 1174 sendFormated("AT+USOCL=%d\r\n", _sockets[socket].handle);
mazgch 95:8282dbbe1492 1175 if (RESP_OK == waitFinalResp()) {
mazgch 103:197fa7920ad8 1176 _sockets[socket].connected = false;
mazgch 95:8282dbbe1492 1177 ok = true;
mazgch 95:8282dbbe1492 1178 }
mazgch 95:8282dbbe1492 1179 }
mazgch 95:8282dbbe1492 1180 UNLOCK();
mazgch 95:8282dbbe1492 1181 return ok;
mazgch 21:c4d64830bf02 1182 }
mazgch 21:c4d64830bf02 1183
mazgch 21:c4d64830bf02 1184 bool MDMParser::socketFree(int socket)
mazgch 21:c4d64830bf02 1185 {
mazgch 95:8282dbbe1492 1186 // make sure it is closed
mazgch 21:c4d64830bf02 1187 socketClose(socket);
mazgch 95:8282dbbe1492 1188 bool ok = true;
mazgch 95:8282dbbe1492 1189 LOCK();
mazgch 103:197fa7920ad8 1190 if (ISSOCKET(socket)) {
mazgch 103:197fa7920ad8 1191 TRACE("socketFree(%d)\r\n", socket);
mazgch 103:197fa7920ad8 1192 _sockets[socket].handle = SOCKET_ERROR;
mazgch 103:197fa7920ad8 1193 _sockets[socket].timeout_ms = TIMEOUT_BLOCKING;
mazgch 103:197fa7920ad8 1194 _sockets[socket].connected = false;
mazgch 103:197fa7920ad8 1195 _sockets[socket].pending = 0;
mazgch 95:8282dbbe1492 1196 ok = true;
mazgch 95:8282dbbe1492 1197 }
mazgch 95:8282dbbe1492 1198 UNLOCK();
mazgch 95:8282dbbe1492 1199 return ok;
mazgch 21:c4d64830bf02 1200 }
mazgch 21:c4d64830bf02 1201
mazgch 69:4d6fa520dfca 1202 #define USO_MAX_WRITE 1024 //!< maximum number of bytes to write to socket
mazgch 69:4d6fa520dfca 1203
mazgch 21:c4d64830bf02 1204 int MDMParser::socketSend(int socket, const char * buf, int len)
mazgch 21:c4d64830bf02 1205 {
mazgch 47:9a89e5195721 1206 TRACE("socketSend(%d,,%d)\r\n", socket,len);
mazgch 68:33a96cf64986 1207 int cnt = len;
mazgch 68:33a96cf64986 1208 while (cnt > 0) {
mazgch 69:4d6fa520dfca 1209 int blk = USO_MAX_WRITE;
mazgch 68:33a96cf64986 1210 if (cnt < blk)
mazgch 68:33a96cf64986 1211 blk = cnt;
mazgch 95:8282dbbe1492 1212 bool ok = false;
mazgch 95:8282dbbe1492 1213 LOCK();
mazgch 103:197fa7920ad8 1214 if (ISSOCKET(socket)) {
mazgch 103:197fa7920ad8 1215 sendFormated("AT+USOWR=%d,%d\r\n",_sockets[socket].handle,blk);
mazgch 103:197fa7920ad8 1216 if (RESP_PROMPT == waitFinalResp()) {
mazgch 103:197fa7920ad8 1217 wait_ms(50);
mazgch 103:197fa7920ad8 1218 send(buf, blk);
mazgch 103:197fa7920ad8 1219 if (RESP_OK == waitFinalResp())
mazgch 103:197fa7920ad8 1220 ok = true;
mazgch 103:197fa7920ad8 1221 }
mazgch 95:8282dbbe1492 1222 }
mazgch 95:8282dbbe1492 1223 UNLOCK();
mazgch 95:8282dbbe1492 1224 if (!ok)
mazgch 21:c4d64830bf02 1225 return SOCKET_ERROR;
mazgch 68:33a96cf64986 1226 buf += blk;
mazgch 68:33a96cf64986 1227 cnt -= blk;
mazgch 21:c4d64830bf02 1228 }
mazgch 68:33a96cf64986 1229 return (len - cnt);
mazgch 21:c4d64830bf02 1230 }
mazgch 21:c4d64830bf02 1231
mazgch 21:c4d64830bf02 1232 int MDMParser::socketSendTo(int socket, IP ip, int port, const char * buf, int len)
mazgch 21:c4d64830bf02 1233 {
mazgch 103:197fa7920ad8 1234 TRACE("socketSendTo(%d," IPSTR ",%d,,%d)\r\n", socket,IPNUM(ip),port,len);
mazgch 68:33a96cf64986 1235 int cnt = len;
mazgch 68:33a96cf64986 1236 while (cnt > 0) {
mazgch 69:4d6fa520dfca 1237 int blk = USO_MAX_WRITE;
mazgch 68:33a96cf64986 1238 if (cnt < blk)
mazgch 68:33a96cf64986 1239 blk = cnt;
mazgch 95:8282dbbe1492 1240 bool ok = false;
mazgch 95:8282dbbe1492 1241 LOCK();
mazgch 103:197fa7920ad8 1242 if (ISSOCKET(socket)) {
mazgch 103:197fa7920ad8 1243 sendFormated("AT+USOST=%d,\"" IPSTR "\",%d,%d\r\n",_sockets[socket].handle,IPNUM(ip),port,blk);
mazgch 103:197fa7920ad8 1244 if (RESP_PROMPT == waitFinalResp()) {
mazgch 103:197fa7920ad8 1245 wait_ms(50);
mazgch 103:197fa7920ad8 1246 send(buf, blk);
mazgch 103:197fa7920ad8 1247 if (RESP_OK == waitFinalResp())
mazgch 103:197fa7920ad8 1248 ok = true;
mazgch 103:197fa7920ad8 1249 }
mazgch 95:8282dbbe1492 1250 }
mazgch 95:8282dbbe1492 1251 UNLOCK();
mazgch 95:8282dbbe1492 1252 if (!ok)
mazgch 21:c4d64830bf02 1253 return SOCKET_ERROR;
mazgch 68:33a96cf64986 1254 buf += blk;
mazgch 68:33a96cf64986 1255 cnt -= blk;
mazgch 21:c4d64830bf02 1256 }
mazgch 68:33a96cf64986 1257 return (len - cnt);
mazgch 21:c4d64830bf02 1258 }
mazgch 21:c4d64830bf02 1259
mazgch 21:c4d64830bf02 1260 int MDMParser::socketReadable(int socket)
mazgch 21:c4d64830bf02 1261 {
mazgch 95:8282dbbe1492 1262 int pending = SOCKET_ERROR;
mazgch 95:8282dbbe1492 1263 LOCK();
mazgch 103:197fa7920ad8 1264 if (ISSOCKET(socket) && _sockets[socket].connected) {
mazgch 95:8282dbbe1492 1265 TRACE("socketReadable(%d)\r\n", socket);
mazgch 95:8282dbbe1492 1266 // allow to receive unsolicited commands
mazgch 95:8282dbbe1492 1267 waitFinalResp(NULL, NULL, 0);
mazgch 103:197fa7920ad8 1268 if (_sockets[socket].connected)
mazgch 95:8282dbbe1492 1269 pending = _sockets[socket].pending;
mazgch 95:8282dbbe1492 1270 }
mazgch 95:8282dbbe1492 1271 UNLOCK();
mazgch 95:8282dbbe1492 1272 return pending;
mazgch 21:c4d64830bf02 1273 }
mazgch 21:c4d64830bf02 1274
mazgch 21:c4d64830bf02 1275 int MDMParser::_cbUSORD(int type, const char* buf, int len, char* out)
mazgch 21:c4d64830bf02 1276 {
mazgch 21:c4d64830bf02 1277 if ((type == TYPE_PLUS) && out) {
mazgch 21:c4d64830bf02 1278 int sz, sk;
mazgch 21:c4d64830bf02 1279 if ((sscanf(buf, "\r\n+USORD: %d,%d,", &sk, &sz) == 2) &&
mazgch 21:c4d64830bf02 1280 (buf[len-sz-2] == '\"') && (buf[len-1] == '\"')) {
mazgch 21:c4d64830bf02 1281 memcpy(out, &buf[len-1-sz], sz);
mazgch 21:c4d64830bf02 1282 }
mazgch 21:c4d64830bf02 1283 }
mazgch 21:c4d64830bf02 1284 return WAIT;
mazgch 21:c4d64830bf02 1285 }
mazgch 21:c4d64830bf02 1286
mazgch 21:c4d64830bf02 1287 int MDMParser::socketRecv(int socket, char* buf, int len)
mazgch 21:c4d64830bf02 1288 {
mazgch 21:c4d64830bf02 1289 int cnt = 0;
mazgch 47:9a89e5195721 1290 TRACE("socketRecv(%d,,%d)\r\n", socket, len);
mazgch 95:8282dbbe1492 1291 #ifdef MDM_DEBUG
mazgch 21:c4d64830bf02 1292 memset(buf, '\0', len);
mazgch 95:8282dbbe1492 1293 #endif
mazgch 44:9d12223b78ff 1294 Timer timer;
mazgch 44:9d12223b78ff 1295 timer.start();
mazgch 21:c4d64830bf02 1296 while (len) {
mazgch 69:4d6fa520dfca 1297 int blk = MAX_SIZE; // still need space for headers and unsolicited commands
mazgch 21:c4d64830bf02 1298 if (len < blk) blk = len;
mazgch 95:8282dbbe1492 1299 bool ok = false;
mazgch 95:8282dbbe1492 1300 LOCK();
mazgch 95:8282dbbe1492 1301 if (ISSOCKET(socket)) {
mazgch 103:197fa7920ad8 1302 if (_sockets[socket].connected) {
mazgch 95:8282dbbe1492 1303 if (_sockets[socket].pending < blk)
mazgch 95:8282dbbe1492 1304 blk = _sockets[socket].pending;
mazgch 95:8282dbbe1492 1305 if (blk > 0) {
mazgch 103:197fa7920ad8 1306 sendFormated("AT+USORD=%d,%d\r\n",_sockets[socket].handle, blk);
mazgch 95:8282dbbe1492 1307 if (RESP_OK == waitFinalResp(_cbUSORD, buf)) {
mazgch 95:8282dbbe1492 1308 _sockets[socket].pending -= blk;
mazgch 95:8282dbbe1492 1309 len -= blk;
mazgch 95:8282dbbe1492 1310 cnt += blk;
mazgch 95:8282dbbe1492 1311 buf += blk;
mazgch 95:8282dbbe1492 1312 ok = true;
mazgch 95:8282dbbe1492 1313 }
mazgch 95:8282dbbe1492 1314 } else if (!TIMEOUT(timer, _sockets[socket].timeout_ms)) {
mazgch 95:8282dbbe1492 1315 ok = (WAIT == waitFinalResp(NULL,NULL,0)); // wait for URCs
mazgch 95:8282dbbe1492 1316 } else {
mazgch 95:8282dbbe1492 1317 len = 0;
mazgch 95:8282dbbe1492 1318 ok = true;
mazgch 95:8282dbbe1492 1319 }
mazgch 103:197fa7920ad8 1320 } else {
mazgch 95:8282dbbe1492 1321 len = 0;
mazgch 95:8282dbbe1492 1322 ok = true;
mazgch 21:c4d64830bf02 1323 }
mazgch 21:c4d64830bf02 1324 }
mazgch 95:8282dbbe1492 1325 UNLOCK();
mazgch 107:436ee320efd6 1326 if (!ok) {
mazgch 107:436ee320efd6 1327 TRACE("socketRecv: ERROR\r\n");
mazgch 95:8282dbbe1492 1328 return SOCKET_ERROR;
mazgch 107:436ee320efd6 1329 }
mazgch 21:c4d64830bf02 1330 }
mazgch 107:436ee320efd6 1331 TRACE("socketRecv: %d \"%*s\"\r\n", cnt, cnt, buf-cnt);
mazgch 21:c4d64830bf02 1332 return cnt;
mazgch 21:c4d64830bf02 1333 }
mazgch 21:c4d64830bf02 1334
mazgch 21:c4d64830bf02 1335 int MDMParser::_cbUSORF(int type, const char* buf, int len, USORFparam* param)
mazgch 21:c4d64830bf02 1336 {
mazgch 21:c4d64830bf02 1337 if ((type == TYPE_PLUS) && param) {
mazgch 21:c4d64830bf02 1338 int sz, sk, p, a,b,c,d;
mazgch 95:8282dbbe1492 1339 int r = sscanf(buf, "\r\n+USORF: %d,\"" IPSTR "\",%d,%d,",
mazgch 95:8282dbbe1492 1340 &sk,&a,&b,&c,&d,&p,&sz);
mazgch 95:8282dbbe1492 1341 if ((r == 7) && (buf[len-sz-2] == '\"') && (buf[len-1] == '\"')) {
mazgch 21:c4d64830bf02 1342 memcpy(param->buf, &buf[len-1-sz], sz);
mazgch 21:c4d64830bf02 1343 param->ip = IPADR(a,b,c,d);
mazgch 21:c4d64830bf02 1344 param->port = p;
mazgch 21:c4d64830bf02 1345 }
mazgch 21:c4d64830bf02 1346 }
mazgch 21:c4d64830bf02 1347 return WAIT;
mazgch 21:c4d64830bf02 1348 }
mazgch 21:c4d64830bf02 1349
mazgch 63:42cb563a25bc 1350 int MDMParser::socketRecvFrom(int socket, IP* ip, int* port, char* buf, int len)
mazgch 21:c4d64830bf02 1351 {
mazgch 21:c4d64830bf02 1352 int cnt = 0;
mazgch 63:42cb563a25bc 1353 TRACE("socketRecvFrom(%d,,%d)\r\n", socket, len);
mazgch 95:8282dbbe1492 1354 #ifdef MDM_DEBUG
mazgch 21:c4d64830bf02 1355 memset(buf, '\0', len);
mazgch 95:8282dbbe1492 1356 #endif
mazgch 44:9d12223b78ff 1357 Timer timer;
mazgch 44:9d12223b78ff 1358 timer.start();
mazgch 21:c4d64830bf02 1359 while (len) {
mazgch 69:4d6fa520dfca 1360 int blk = MAX_SIZE; // still need space for headers and unsolicited commands
mazgch 21:c4d64830bf02 1361 if (len < blk) blk = len;
mazgch 95:8282dbbe1492 1362 bool ok = false;
mazgch 95:8282dbbe1492 1363 LOCK();
mazgch 95:8282dbbe1492 1364 if (ISSOCKET(socket)) {
mazgch 95:8282dbbe1492 1365 if (_sockets[socket].pending < blk)
mazgch 95:8282dbbe1492 1366 blk = _sockets[socket].pending;
mazgch 95:8282dbbe1492 1367 if (blk > 0) {
mazgch 103:197fa7920ad8 1368 sendFormated("AT+USORF=%d,%d\r\n",_sockets[socket].handle, blk);
mazgch 95:8282dbbe1492 1369 USORFparam param;
mazgch 95:8282dbbe1492 1370 param.buf = buf;
mazgch 95:8282dbbe1492 1371 if (RESP_OK == waitFinalResp(_cbUSORF, &param)) {
mazgch 95:8282dbbe1492 1372 _sockets[socket].pending -= blk;
mazgch 95:8282dbbe1492 1373 *ip = param.ip;
mazgch 95:8282dbbe1492 1374 *port = param.port;
mazgch 95:8282dbbe1492 1375 len -= blk;
mazgch 95:8282dbbe1492 1376 cnt += blk;
mazgch 95:8282dbbe1492 1377 buf += blk;
mazgch 95:8282dbbe1492 1378 len = 0; // done
mazgch 95:8282dbbe1492 1379 ok = true;
mazgch 95:8282dbbe1492 1380 }
mazgch 95:8282dbbe1492 1381 } else if (!TIMEOUT(timer, _sockets[socket].timeout_ms)) {
mazgch 95:8282dbbe1492 1382 ok = (WAIT == waitFinalResp(NULL,NULL,0)); // wait for URCs
mazgch 95:8282dbbe1492 1383 } else {
mazgch 95:8282dbbe1492 1384 len = 0; // no more data and socket closed or timed-out
mazgch 95:8282dbbe1492 1385 ok = true;
mazgch 21:c4d64830bf02 1386 }
mazgch 95:8282dbbe1492 1387 }
mazgch 95:8282dbbe1492 1388 UNLOCK();
mazgch 107:436ee320efd6 1389 if (!ok) {
mazgch 107:436ee320efd6 1390 TRACE("socketRecv: ERROR\r\n");
mazgch 95:8282dbbe1492 1391 return SOCKET_ERROR;
mazgch 107:436ee320efd6 1392 }
mazgch 21:c4d64830bf02 1393 }
mazgch 44:9d12223b78ff 1394 timer.stop();
mazgch 44:9d12223b78ff 1395 timer.reset();
mazgch 107:436ee320efd6 1396 TRACE("socketRecv: %d \"%*s\"\r\n", cnt, cnt, buf-cnt);
mazgch 21:c4d64830bf02 1397 return cnt;
mazgch 21:c4d64830bf02 1398 }
mazgch 21:c4d64830bf02 1399
mazgch 103:197fa7920ad8 1400 int MDMParser::_findSocket(int handle) {
mazgch 104:c64ba749a422 1401 for (int socket = 0; socket < NUMSOCKETS; socket ++) {
mazgch 103:197fa7920ad8 1402 if (_sockets[socket].handle == handle)
mazgch 103:197fa7920ad8 1403 return socket;
mazgch 103:197fa7920ad8 1404 }
mazgch 103:197fa7920ad8 1405 return SOCKET_ERROR;
mazgch 103:197fa7920ad8 1406 }
mazgch 103:197fa7920ad8 1407
mazgch 21:c4d64830bf02 1408 // ----------------------------------------------------------------
mazgch 31:a0bed6c1e05d 1409
mazgch 31:a0bed6c1e05d 1410 int MDMParser::_cbCMGL(int type, const char* buf, int len, CMGLparam* param)
mazgch 21:c4d64830bf02 1411 {
mazgch 31:a0bed6c1e05d 1412 if ((type == TYPE_PLUS) && param && param->num) {
mazgch 31:a0bed6c1e05d 1413 // +CMGL: <ix>,...
mazgch 31:a0bed6c1e05d 1414 int ix;
mazgch 31:a0bed6c1e05d 1415 if (sscanf(buf, "\r\n+CMGL: %d,", &ix) == 1)
mazgch 31:a0bed6c1e05d 1416 {
mazgch 31:a0bed6c1e05d 1417 *param->ix++ = ix;
mazgch 31:a0bed6c1e05d 1418 param->num--;
mazgch 31:a0bed6c1e05d 1419 }
mazgch 29:53d346010624 1420 }
mazgch 29:53d346010624 1421 return WAIT;
mazgch 21:c4d64830bf02 1422 }
mazgch 21:c4d64830bf02 1423
mazgch 31:a0bed6c1e05d 1424 int MDMParser::smsList(const char* stat /*= "ALL"*/, int* ix /*=NULL*/, int num /*= 0*/) {
mazgch 95:8282dbbe1492 1425 int ret = -1;
mazgch 95:8282dbbe1492 1426 LOCK();
mazgch 31:a0bed6c1e05d 1427 sendFormated("AT+CMGL=\"%s\"\r\n", stat);
mazgch 31:a0bed6c1e05d 1428 CMGLparam param;
mazgch 31:a0bed6c1e05d 1429 param.ix = ix;
mazgch 31:a0bed6c1e05d 1430 param.num = num;
mazgch 95:8282dbbe1492 1431 if (RESP_OK == waitFinalResp(_cbCMGL, &param))
mazgch 95:8282dbbe1492 1432 ret = num - param.num;
mazgch 95:8282dbbe1492 1433 UNLOCK();
mazgch 95:8282dbbe1492 1434 return ret;
mazgch 21:c4d64830bf02 1435 }
mazgch 21:c4d64830bf02 1436
mazgch 21:c4d64830bf02 1437 bool MDMParser::smsSend(const char* num, const char* buf)
mazgch 21:c4d64830bf02 1438 {
mazgch 95:8282dbbe1492 1439 bool ok = false;
mazgch 95:8282dbbe1492 1440 LOCK();
mazgch 80:34985b4d821e 1441 sendFormated("AT+CMGS=\"%s\"\r\n",num);
mazgch 95:8282dbbe1492 1442 if (RESP_PROMPT == waitFinalResp(NULL,NULL,150*1000)) {
mazgch 95:8282dbbe1492 1443 send(buf, strlen(buf));
mazgch 95:8282dbbe1492 1444 const char ctrlZ = 0x1A;
mazgch 95:8282dbbe1492 1445 send(&ctrlZ, sizeof(ctrlZ));
mazgch 95:8282dbbe1492 1446 ok = (RESP_OK == waitFinalResp());
mazgch 21:c4d64830bf02 1447 }
mazgch 95:8282dbbe1492 1448 UNLOCK();
mazgch 95:8282dbbe1492 1449 return ok;
mazgch 21:c4d64830bf02 1450 }
mazgch 21:c4d64830bf02 1451
mazgch 21:c4d64830bf02 1452 bool MDMParser::smsDelete(int ix)
mazgch 21:c4d64830bf02 1453 {
mazgch 95:8282dbbe1492 1454 bool ok = false;
mazgch 95:8282dbbe1492 1455 LOCK();
mazgch 21:c4d64830bf02 1456 sendFormated("AT+CMGD=%d\r\n",ix);
mazgch 95:8282dbbe1492 1457 ok = (RESP_OK == waitFinalResp());
mazgch 95:8282dbbe1492 1458 UNLOCK();
mazgch 95:8282dbbe1492 1459 return ok;
mazgch 21:c4d64830bf02 1460 }
mazgch 21:c4d64830bf02 1461
mazgch 21:c4d64830bf02 1462 int MDMParser::_cbCMGR(int type, const char* buf, int len, CMGRparam* param)
mazgch 21:c4d64830bf02 1463 {
mazgch 21:c4d64830bf02 1464 if (param) {
mazgch 21:c4d64830bf02 1465 if (type == TYPE_PLUS) {
mazgch 21:c4d64830bf02 1466 if (sscanf(buf, "\r\n+CMGR: \"%*[^\"]\",\"%[^\"]", param->num) == 1) {
mazgch 21:c4d64830bf02 1467 }
mazgch 37:cc3433329d66 1468 } else if ((type == TYPE_UNKNOWN) && (buf[len-2] == '\r') && (buf[len-1] == '\n')) {
mazgch 21:c4d64830bf02 1469 memcpy(param->buf, buf, len-2);
mazgch 21:c4d64830bf02 1470 param->buf[len-2] = '\0';
mazgch 21:c4d64830bf02 1471 }
mazgch 21:c4d64830bf02 1472 }
mazgch 21:c4d64830bf02 1473 return WAIT;
mazgch 21:c4d64830bf02 1474 }
mazgch 21:c4d64830bf02 1475
mazgch 21:c4d64830bf02 1476 bool MDMParser::smsRead(int ix, char* num, char* buf, int len)
mazgch 21:c4d64830bf02 1477 {
mazgch 95:8282dbbe1492 1478 bool ok = false;
mazgch 95:8282dbbe1492 1479 LOCK();
mazgch 21:c4d64830bf02 1480 CMGRparam param;
mazgch 21:c4d64830bf02 1481 param.num = num;
mazgch 21:c4d64830bf02 1482 param.buf = buf;
mazgch 21:c4d64830bf02 1483 sendFormated("AT+CMGR=%d\r\n",ix);
mazgch 95:8282dbbe1492 1484 ok = (RESP_OK == waitFinalResp(_cbCMGR, &param));
mazgch 95:8282dbbe1492 1485 UNLOCK();
mazgch 95:8282dbbe1492 1486 return ok;
mazgch 21:c4d64830bf02 1487 }
mazgch 54:7ba8e4c218e2 1488
mazgch 54:7ba8e4c218e2 1489 // ----------------------------------------------------------------
mazgch 70:0a87d256cd24 1490
mazgch 70:0a87d256cd24 1491 int MDMParser::_cbCUSD(int type, const char* buf, int len, char* resp)
mazgch 70:0a87d256cd24 1492 {
mazgch 70:0a87d256cd24 1493 if ((type == TYPE_PLUS) && resp) {
mazgch 70:0a87d256cd24 1494 // +USD: \"%*[^\"]\",\"%[^\"]\",,\"%*[^\"]\",%d,%d,%d,%d,\"*[^\"]\",%d,%d"..);
mazgch 70:0a87d256cd24 1495 if (sscanf(buf, "\r\n+CUSD: %*d,\"%[^\"]\",%*d", resp) == 1) {
mazgch 70:0a87d256cd24 1496 /*nothing*/
mazgch 70:0a87d256cd24 1497 }
mazgch 70:0a87d256cd24 1498 }
mazgch 70:0a87d256cd24 1499 return WAIT;
mazgch 70:0a87d256cd24 1500 }
mazgch 70:0a87d256cd24 1501
mazgch 70:0a87d256cd24 1502 bool MDMParser::ussdCommand(const char* cmd, char* buf)
mazgch 70:0a87d256cd24 1503 {
mazgch 95:8282dbbe1492 1504 bool ok = false;
mazgch 95:8282dbbe1492 1505 LOCK();
mazgch 70:0a87d256cd24 1506 *buf = '\0';
mazgch 95:8282dbbe1492 1507 if (_dev.dev != DEV_LISA_C200) {
mazgch 95:8282dbbe1492 1508 sendFormated("AT+CUSD=1,\"%s\"\r\n",cmd);
mazgch 95:8282dbbe1492 1509 ok = (RESP_OK == waitFinalResp(_cbCUSD, buf));
mazgch 70:0a87d256cd24 1510 }
mazgch 95:8282dbbe1492 1511 UNLOCK();
mazgch 95:8282dbbe1492 1512 return ok;
mazgch 70:0a87d256cd24 1513 }
mazgch 80:34985b4d821e 1514
mazgch 80:34985b4d821e 1515 // ----------------------------------------------------------------
RobMeades 118:f3fd6c30dc19 1516 // Neul AT command handling functions
RobMeades 126:76b578ec2912 1517 char * MDMParser::getVersion(void)
RobMeades 126:76b578ec2912 1518 {
RobMeades 126:76b578ec2912 1519 return _dev.model;
RobMeades 126:76b578ec2912 1520 }
RobMeades 126:76b578ec2912 1521
RobMeades 126:76b578ec2912 1522 bool MDMParser::sendMactest (int size, const char* buf)
RobMeades 126:76b578ec2912 1523 {
RobMeades 126:76b578ec2912 1524 bool ok = false;
RobMeades 126:76b578ec2912 1525 int sizeToSend;
RobMeades 126:76b578ec2912 1526 char bufToSend[MAX_SIZE];
RobMeades 126:76b578ec2912 1527
RobMeades 126:76b578ec2912 1528 LOCK();
RobMeades 126:76b578ec2912 1529
RobMeades 126:76b578ec2912 1530 if (size <= (int) (sizeof(bufToSend) / 2))
RobMeades 126:76b578ec2912 1531 {
RobMeades 126:76b578ec2912 1532 sizeToSend = bytesToHexString (buf, size, bufToSend, sizeof(bufToSend));
RobMeades 126:76b578ec2912 1533 sendFormated ("AT+MACTEST=%d,%.*s\r\n", size, sizeToSend, bufToSend);
RobMeades 126:76b578ec2912 1534 if (RESP_OK == waitFinalResp()) {
RobMeades 126:76b578ec2912 1535 ok = true;
RobMeades 126:76b578ec2912 1536 }
RobMeades 126:76b578ec2912 1537 }
RobMeades 126:76b578ec2912 1538
RobMeades 126:76b578ec2912 1539 UNLOCK();
RobMeades 126:76b578ec2912 1540
RobMeades 126:76b578ec2912 1541 return ok;
RobMeades 126:76b578ec2912 1542 }
RobMeades 126:76b578ec2912 1543
RobMeades 118:f3fd6c30dc19 1544 int MDMParser::_cbMGS (int type, const char* buf, int len, bool* ok)
RobMeades 118:f3fd6c30dc19 1545 {
RobMeades 118:f3fd6c30dc19 1546 *ok = false;
RobMeades 118:f3fd6c30dc19 1547 if (type == TYPE_PLUS) {
RobMeades 118:f3fd6c30dc19 1548 if (strstr(buf, "\r\n+MGS:OK") == buf) {
RobMeades 118:f3fd6c30dc19 1549 *ok = true;
RobMeades 118:f3fd6c30dc19 1550 return RESP_OK;
RobMeades 118:f3fd6c30dc19 1551 }
RobMeades 118:f3fd6c30dc19 1552 }
RobMeades 118:f3fd6c30dc19 1553 return WAIT;
RobMeades 118:f3fd6c30dc19 1554 }
RobMeades 118:f3fd6c30dc19 1555
RobMeades 118:f3fd6c30dc19 1556 int MDMParser::_cbSMI (int type, const char* buf, int len, bool* sent)
RobMeades 118:f3fd6c30dc19 1557 {
RobMeades 118:f3fd6c30dc19 1558 *sent = false;
RobMeades 118:f3fd6c30dc19 1559 if (type == TYPE_PLUS) {
RobMeades 118:f3fd6c30dc19 1560 if (strstr(buf, "\r\n+SMI:SENT") == buf) {
RobMeades 118:f3fd6c30dc19 1561 *sent = true;
RobMeades 118:f3fd6c30dc19 1562 return RESP_OK;
RobMeades 118:f3fd6c30dc19 1563 }
RobMeades 118:f3fd6c30dc19 1564 }
RobMeades 118:f3fd6c30dc19 1565 return WAIT;
RobMeades 118:f3fd6c30dc19 1566 }
RobMeades 118:f3fd6c30dc19 1567
RobMeades 118:f3fd6c30dc19 1568 bool MDMParser::datagramSend(int size, const char* buf)
RobMeades 118:f3fd6c30dc19 1569 {
RobMeades 118:f3fd6c30dc19 1570 bool ok = false;
RobMeades 124:a58c1a7c5e18 1571 int sizeToSend;
RobMeades 124:a58c1a7c5e18 1572 char bufToSend[MAX_SIZE];
RobMeades 118:f3fd6c30dc19 1573
RobMeades 118:f3fd6c30dc19 1574 LOCK();
RobMeades 124:a58c1a7c5e18 1575
RobMeades 124:a58c1a7c5e18 1576 if (size <= (int) (sizeof(bufToSend) / 2))
RobMeades 124:a58c1a7c5e18 1577 {
RobMeades 124:a58c1a7c5e18 1578 sizeToSend = bytesToHexString (buf, size, bufToSend, sizeof(bufToSend));
RobMeades 124:a58c1a7c5e18 1579 sendFormated ("AT+MGS=%d,%.*s\r\n", size, sizeToSend, bufToSend);
RobMeades 124:a58c1a7c5e18 1580 ok = (RESP_OK == waitFinalResp(_cbMGS, &ok)) && ok;
RobMeades 118:f3fd6c30dc19 1581 if (ok) {
RobMeades 124:a58c1a7c5e18 1582 ok = (RESP_OK == waitFinalResp(NULL));
RobMeades 124:a58c1a7c5e18 1583 if (ok) {
RobMeades 126:76b578ec2912 1584 ok = (RESP_OK == waitFinalResp(_cbSMI, &ok, 60000)) && ok;
RobMeades 124:a58c1a7c5e18 1585 }
RobMeades 118:f3fd6c30dc19 1586 }
RobMeades 118:f3fd6c30dc19 1587 }
RobMeades 124:a58c1a7c5e18 1588
RobMeades 118:f3fd6c30dc19 1589 UNLOCK();
RobMeades 118:f3fd6c30dc19 1590
RobMeades 118:f3fd6c30dc19 1591 return ok;
RobMeades 118:f3fd6c30dc19 1592 }
RobMeades 118:f3fd6c30dc19 1593
RobMeades 118:f3fd6c30dc19 1594 int MDMParser::_cbMGR (int type, const char* buf, int len, MGRparam* param)
RobMeades 118:f3fd6c30dc19 1595 {
RobMeades 118:f3fd6c30dc19 1596 int a = 0;
RobMeades 118:f3fd6c30dc19 1597 if (param) {
RobMeades 118:f3fd6c30dc19 1598 if (type == TYPE_PLUS) {
RobMeades 118:f3fd6c30dc19 1599 if ((sscanf(buf, "\r\n+MGR:%d", &a) == 1) && (a * 2 < param->maxlen)) {
RobMeades 118:f3fd6c30dc19 1600 if (sscanf(buf, "\r\n+MGR:%d,%s", &(param->outlen), param->buf) == 2) {
RobMeades 118:f3fd6c30dc19 1601 param->outlen *=2; // length in bytes rather than hex-char representation
RobMeades 118:f3fd6c30dc19 1602 return RESP_OK;
RobMeades 118:f3fd6c30dc19 1603 }
RobMeades 118:f3fd6c30dc19 1604 }
RobMeades 118:f3fd6c30dc19 1605 }
RobMeades 118:f3fd6c30dc19 1606 }
RobMeades 118:f3fd6c30dc19 1607
RobMeades 118:f3fd6c30dc19 1608 return WAIT;
RobMeades 118:f3fd6c30dc19 1609 }
RobMeades 118:f3fd6c30dc19 1610
RobMeades 118:f3fd6c30dc19 1611 bool MDMParser::doMGR (int* size, char* buf, MGRparam *param)
RobMeades 118:f3fd6c30dc19 1612 {
RobMeades 118:f3fd6c30dc19 1613 bool ok;
RobMeades 118:f3fd6c30dc19 1614
RobMeades 118:f3fd6c30dc19 1615 sendFormated ("AT+MGR\r\n");
RobMeades 118:f3fd6c30dc19 1616 ok = (RESP_OK == waitFinalResp(_cbMGR, param, 1000));
RobMeades 118:f3fd6c30dc19 1617 if (ok) {
RobMeades 118:f3fd6c30dc19 1618 if (ok && (param->outlen > 0)) {
RobMeades 118:f3fd6c30dc19 1619 ok = (RESP_OK == waitFinalResp(NULL));
RobMeades 118:f3fd6c30dc19 1620 *size = param->maxlen;
RobMeades 118:f3fd6c30dc19 1621 hexStringToBytes (param->buf, param->outlen, buf, size);
RobMeades 118:f3fd6c30dc19 1622 }
RobMeades 118:f3fd6c30dc19 1623 }
RobMeades 118:f3fd6c30dc19 1624
RobMeades 118:f3fd6c30dc19 1625 return ok;
RobMeades 118:f3fd6c30dc19 1626 }
RobMeades 118:f3fd6c30dc19 1627
RobMeades 118:f3fd6c30dc19 1628 bool MDMParser::datagramRecv(int* size, char* buf, int timeoutMs /* 10000 */)
RobMeades 118:f3fd6c30dc19 1629 {
RobMeades 126:76b578ec2912 1630 bool ok = false;
RobMeades 118:f3fd6c30dc19 1631 MGRparam param;
RobMeades 118:f3fd6c30dc19 1632 param.buf = buf;
RobMeades 118:f3fd6c30dc19 1633 param.maxlen = *size;
RobMeades 118:f3fd6c30dc19 1634 param.outlen = 0;
RobMeades 118:f3fd6c30dc19 1635
RobMeades 118:f3fd6c30dc19 1636 LOCK();
RobMeades 126:76b578ec2912 1637
RobMeades 126:76b578ec2912 1638 if (_useNMI)
RobMeades 118:f3fd6c30dc19 1639 {
RobMeades 126:76b578ec2912 1640 // If NMI type 2 is supported (so NMI doesn't destroy the datagram),
RobMeades 126:76b578ec2912 1641 // use the _outstandingNMI count and read the messages from the queue
RobMeades 126:76b578ec2912 1642 if (_outstandingNMI == 0)
RobMeades 126:76b578ec2912 1643 {
RobMeades 126:76b578ec2912 1644 waitFinalResp(NULL, NULL, timeoutMs);
RobMeades 126:76b578ec2912 1645 }
RobMeades 126:76b578ec2912 1646 if (_outstandingNMI > 0)
RobMeades 126:76b578ec2912 1647 {
RobMeades 126:76b578ec2912 1648 ok = doMGR (size, buf, &param);
RobMeades 126:76b578ec2912 1649 if (ok) {
RobMeades 126:76b578ec2912 1650 _outstandingNMI--;
RobMeades 126:76b578ec2912 1651 if (param.outlen > 0) {
RobMeades 126:76b578ec2912 1652 ok = true;
RobMeades 126:76b578ec2912 1653 }
RobMeades 126:76b578ec2912 1654 } else {
RobMeades 126:76b578ec2912 1655 *size = 0;
RobMeades 118:f3fd6c30dc19 1656 }
RobMeades 126:76b578ec2912 1657 }
RobMeades 126:76b578ec2912 1658 }
RobMeades 126:76b578ec2912 1659 else
RobMeades 126:76b578ec2912 1660 {
RobMeades 126:76b578ec2912 1661 // If NMI type 2 is not supported, poll with MGR instead
RobMeades 126:76b578ec2912 1662 Timer timer;
RobMeades 126:76b578ec2912 1663
RobMeades 126:76b578ec2912 1664 timer.start();
RobMeades 126:76b578ec2912 1665 ok = true;
RobMeades 126:76b578ec2912 1666 while (ok && (param.outlen == 0) && (timer.read_ms() < timeoutMs)) {
RobMeades 126:76b578ec2912 1667 ok = doMGR (size, buf, &param);
RobMeades 126:76b578ec2912 1668 if (ok && param.outlen == 0) {
RobMeades 126:76b578ec2912 1669 wait_ms (500);
RobMeades 126:76b578ec2912 1670 }
RobMeades 126:76b578ec2912 1671 }
RobMeades 126:76b578ec2912 1672 if (param.outlen == 0) {
RobMeades 126:76b578ec2912 1673 ok = false;
RobMeades 118:f3fd6c30dc19 1674 *size = 0;
RobMeades 118:f3fd6c30dc19 1675 }
RobMeades 118:f3fd6c30dc19 1676 }
RobMeades 118:f3fd6c30dc19 1677
RobMeades 118:f3fd6c30dc19 1678 UNLOCK();
RobMeades 118:f3fd6c30dc19 1679
RobMeades 118:f3fd6c30dc19 1680 return ok;
RobMeades 118:f3fd6c30dc19 1681 }
RobMeades 118:f3fd6c30dc19 1682
RobMeades 118:f3fd6c30dc19 1683 int MDMParser::_cbCSQN(int type, const char* buf, int len, int* rssi)
RobMeades 118:f3fd6c30dc19 1684 {
RobMeades 118:f3fd6c30dc19 1685 if ((type == TYPE_PLUS) && rssi) {
RobMeades 118:f3fd6c30dc19 1686 // +CSQ: <rssi>
RobMeades 118:f3fd6c30dc19 1687 if (sscanf(buf, "\r\n+CSQ: %d", rssi) == 1) {
RobMeades 118:f3fd6c30dc19 1688 return RESP_OK;
RobMeades 118:f3fd6c30dc19 1689 }
RobMeades 118:f3fd6c30dc19 1690 }
RobMeades 118:f3fd6c30dc19 1691
RobMeades 118:f3fd6c30dc19 1692 return WAIT;
RobMeades 118:f3fd6c30dc19 1693 }
RobMeades 118:f3fd6c30dc19 1694
RobMeades 118:f3fd6c30dc19 1695 bool MDMParser::getRssi(int *rssi)
RobMeades 118:f3fd6c30dc19 1696 {
RobMeades 118:f3fd6c30dc19 1697 bool ok = false;
RobMeades 118:f3fd6c30dc19 1698 if (rssi) {
RobMeades 118:f3fd6c30dc19 1699 LOCK();
RobMeades 118:f3fd6c30dc19 1700 sendFormated ("AT+CSQ\r\n");
RobMeades 118:f3fd6c30dc19 1701 ok = (RESP_OK == waitFinalResp(_cbCSQN, rssi));
RobMeades 118:f3fd6c30dc19 1702 if (ok) {
RobMeades 118:f3fd6c30dc19 1703 ok = (RESP_OK == waitFinalResp(NULL));
RobMeades 118:f3fd6c30dc19 1704 }
RobMeades 118:f3fd6c30dc19 1705 UNLOCK();
RobMeades 118:f3fd6c30dc19 1706 }
RobMeades 118:f3fd6c30dc19 1707 return ok;
RobMeades 118:f3fd6c30dc19 1708 }
RobMeades 118:f3fd6c30dc19 1709
RobMeades 118:f3fd6c30dc19 1710 int MDMParser::_cbRB (int type, const char* buf, int len, bool* ok)
RobMeades 118:f3fd6c30dc19 1711 {
RobMeades 118:f3fd6c30dc19 1712 *ok = false;
RobMeades 118:f3fd6c30dc19 1713 if (type == TYPE_PLUS) {
RobMeades 118:f3fd6c30dc19 1714 if (strstr(buf, "\r\n+RB:REBOOTING") == buf) {
RobMeades 118:f3fd6c30dc19 1715 *ok = true;
RobMeades 118:f3fd6c30dc19 1716 return RESP_OK;
RobMeades 118:f3fd6c30dc19 1717 }
RobMeades 118:f3fd6c30dc19 1718 }
RobMeades 118:f3fd6c30dc19 1719 return WAIT;
RobMeades 118:f3fd6c30dc19 1720 }
RobMeades 118:f3fd6c30dc19 1721
RobMeades 118:f3fd6c30dc19 1722 bool MDMParser::neulReboot()
RobMeades 118:f3fd6c30dc19 1723 {
RobMeades 118:f3fd6c30dc19 1724 bool ok = false;
RobMeades 118:f3fd6c30dc19 1725 LOCK();
RobMeades 118:f3fd6c30dc19 1726 sendFormated ("AT+RB\r\n");
RobMeades 118:f3fd6c30dc19 1727 ok = (RESP_OK == waitFinalResp(_cbRB, &ok)) && ok;
RobMeades 118:f3fd6c30dc19 1728 if (ok) {
RobMeades 118:f3fd6c30dc19 1729 ok = (RESP_OK == waitFinalResp(NULL));
RobMeades 118:f3fd6c30dc19 1730 }
RobMeades 118:f3fd6c30dc19 1731 UNLOCK();
RobMeades 118:f3fd6c30dc19 1732
RobMeades 118:f3fd6c30dc19 1733 return ok;
RobMeades 118:f3fd6c30dc19 1734 }
RobMeades 118:f3fd6c30dc19 1735
RobMeades 124:a58c1a7c5e18 1736 int MDMParser::bytesToHexString (const char * inBuf, int size, char *outBuf, int lenOutBuf)
RobMeades 124:a58c1a7c5e18 1737 {
RobMeades 124:a58c1a7c5e18 1738 int x = 0;
RobMeades 124:a58c1a7c5e18 1739 int y = 0;
RobMeades 124:a58c1a7c5e18 1740
RobMeades 124:a58c1a7c5e18 1741 for (x = 0; (x < size) && (y < lenOutBuf); x++)
RobMeades 124:a58c1a7c5e18 1742 {
RobMeades 124:a58c1a7c5e18 1743 outBuf[y] = hexTable[(inBuf[x] >> 4) & 0x0f]; // upper nibble
RobMeades 124:a58c1a7c5e18 1744 y++;
RobMeades 124:a58c1a7c5e18 1745 if (y < lenOutBuf)
RobMeades 124:a58c1a7c5e18 1746 {
RobMeades 124:a58c1a7c5e18 1747 outBuf[y] = hexTable[inBuf[x] & 0x0f]; // lower nibble
RobMeades 124:a58c1a7c5e18 1748 y++;
RobMeades 124:a58c1a7c5e18 1749 }
RobMeades 124:a58c1a7c5e18 1750 }
RobMeades 124:a58c1a7c5e18 1751
RobMeades 124:a58c1a7c5e18 1752 return y;
RobMeades 124:a58c1a7c5e18 1753 }
RobMeades 124:a58c1a7c5e18 1754
RobMeades 118:f3fd6c30dc19 1755 void MDMParser::hexStringToBytes (const char *inBuf, int lenInBuf, char * outBuf, int* lenOutBuf)
RobMeades 118:f3fd6c30dc19 1756 {
RobMeades 118:f3fd6c30dc19 1757 int x;
RobMeades 118:f3fd6c30dc19 1758 int y = 0;
RobMeades 118:f3fd6c30dc19 1759 int z;
RobMeades 118:f3fd6c30dc19 1760
RobMeades 118:f3fd6c30dc19 1761 for (x = 0; (x < lenInBuf) && (y < *lenOutBuf); x++)
RobMeades 118:f3fd6c30dc19 1762 {
RobMeades 118:f3fd6c30dc19 1763 z = *(inBuf + x);
RobMeades 118:f3fd6c30dc19 1764 if ((z >= '0') && (z <= '9'))
RobMeades 118:f3fd6c30dc19 1765 {
RobMeades 118:f3fd6c30dc19 1766 z = z - '0';
RobMeades 118:f3fd6c30dc19 1767 }
RobMeades 118:f3fd6c30dc19 1768 else
RobMeades 118:f3fd6c30dc19 1769 {
RobMeades 118:f3fd6c30dc19 1770 z &= ~0x20;
RobMeades 118:f3fd6c30dc19 1771 if ((z >= 'A') && (z <= 'F'))
RobMeades 118:f3fd6c30dc19 1772 {
RobMeades 118:f3fd6c30dc19 1773 z = z - 'A' + 10;
RobMeades 118:f3fd6c30dc19 1774 }
RobMeades 118:f3fd6c30dc19 1775 }
RobMeades 118:f3fd6c30dc19 1776
RobMeades 118:f3fd6c30dc19 1777 if (x % 2 == 0)
RobMeades 118:f3fd6c30dc19 1778 {
RobMeades 118:f3fd6c30dc19 1779 *(outBuf + y) = (z << 4) & 0xF0;
RobMeades 118:f3fd6c30dc19 1780 }
RobMeades 118:f3fd6c30dc19 1781 else
RobMeades 118:f3fd6c30dc19 1782 {
RobMeades 118:f3fd6c30dc19 1783 *(outBuf + y) += z;
RobMeades 118:f3fd6c30dc19 1784 y++;
RobMeades 118:f3fd6c30dc19 1785 }
RobMeades 118:f3fd6c30dc19 1786 }
RobMeades 118:f3fd6c30dc19 1787
RobMeades 118:f3fd6c30dc19 1788 *lenOutBuf = y;
RobMeades 118:f3fd6c30dc19 1789 }
RobMeades 118:f3fd6c30dc19 1790
RobMeades 118:f3fd6c30dc19 1791 // ----------------------------------------------------------------
mazgch 70:0a87d256cd24 1792
mazgch 115:d8d94b73c725 1793 int MDMParser::_cbUDELFILE(int type, const char* buf, int len, void*)
mazgch 115:d8d94b73c725 1794 {
mazgch 115:d8d94b73c725 1795 if ((type == TYPE_ERROR) && strstr(buf, "+CME ERROR: FILE NOT FOUND"))
mazgch 115:d8d94b73c725 1796 return RESP_OK; // file does not exist, so all ok...
mazgch 115:d8d94b73c725 1797 return WAIT;
mazgch 115:d8d94b73c725 1798 }
mazgch 115:d8d94b73c725 1799
mazgch 80:34985b4d821e 1800 bool MDMParser::delFile(const char* filename)
mazgch 80:34985b4d821e 1801 {
mazgch 95:8282dbbe1492 1802 bool ok = false;
mazgch 95:8282dbbe1492 1803 LOCK();
mazgch 80:34985b4d821e 1804 sendFormated("AT+UDELFILE=\"%s\"\r\n", filename);
mazgch 115:d8d94b73c725 1805 ok = (RESP_OK == waitFinalResp(_cbUDELFILE));
mazgch 95:8282dbbe1492 1806 UNLOCK();
mazgch 95:8282dbbe1492 1807 return ok;
mazgch 80:34985b4d821e 1808 }
mazgch 80:34985b4d821e 1809
mazgch 80:34985b4d821e 1810 int MDMParser::writeFile(const char* filename, const char* buf, int len)
mazgch 80:34985b4d821e 1811 {
mazgch 95:8282dbbe1492 1812 bool ok = false;
mazgch 95:8282dbbe1492 1813 LOCK();
mazgch 80:34985b4d821e 1814 sendFormated("AT+UDWNFILE=\"%s\",%d\r\n", filename, len);
mazgch 95:8282dbbe1492 1815 if (RESP_PROMPT == waitFinalResp()) {
mazgch 95:8282dbbe1492 1816 send(buf, len);
mazgch 95:8282dbbe1492 1817 ok = (RESP_OK == waitFinalResp());
mazgch 95:8282dbbe1492 1818 }
mazgch 95:8282dbbe1492 1819 UNLOCK();
mazgch 95:8282dbbe1492 1820 return ok ? len : -1;
mazgch 80:34985b4d821e 1821 }
mazgch 80:34985b4d821e 1822
mazgch 80:34985b4d821e 1823 int MDMParser::readFile(const char* filename, char* buf, int len)
mazgch 80:34985b4d821e 1824 {
mazgch 80:34985b4d821e 1825 URDFILEparam param;
mazgch 80:34985b4d821e 1826 param.filename = filename;
mazgch 80:34985b4d821e 1827 param.buf = buf;
mazgch 80:34985b4d821e 1828 param.sz = len;
mazgch 80:34985b4d821e 1829 param.len = 0;
mazgch 95:8282dbbe1492 1830 LOCK();
mazgch 95:8282dbbe1492 1831 sendFormated("AT+URDFILE=\"%s\"\r\n", filename, len);
mazgch 105:f6bb2a20de70 1832 if (RESP_OK != waitFinalResp(_cbURDFILE, &param))
mazgch 95:8282dbbe1492 1833 param.len = -1;
mazgch 95:8282dbbe1492 1834 UNLOCK();
mazgch 80:34985b4d821e 1835 return param.len;
mazgch 80:34985b4d821e 1836 }
mazgch 80:34985b4d821e 1837
mazgch 80:34985b4d821e 1838 int MDMParser::_cbURDFILE(int type, const char* buf, int len, URDFILEparam* param)
mazgch 80:34985b4d821e 1839 {
mazgch 80:34985b4d821e 1840 if ((type == TYPE_PLUS) && param && param->filename && param->buf) {
mazgch 80:34985b4d821e 1841 char filename[48];
mazgch 80:34985b4d821e 1842 int sz;
mazgch 80:34985b4d821e 1843 if ((sscanf(buf, "\r\n+URDFILE: \"%[^\"]\",%d,", filename, &sz) == 2) &&
mazgch 80:34985b4d821e 1844 (0 == strcmp(param->filename, filename)) &&
mazgch 80:34985b4d821e 1845 (buf[len-sz-2] == '\"') && (buf[len-1] == '\"')) {
mazgch 80:34985b4d821e 1846 param->len = (sz < param->sz) ? sz : param->sz;
mazgch 80:34985b4d821e 1847 memcpy(param->buf, &buf[len-1-sz], param->len);
mazgch 80:34985b4d821e 1848 }
mazgch 80:34985b4d821e 1849 }
mazgch 80:34985b4d821e 1850 return WAIT;
mazgch 80:34985b4d821e 1851 }
mazgch 80:34985b4d821e 1852
mazgch 70:0a87d256cd24 1853 // ----------------------------------------------------------------
mazgch 74:208e3e32d263 1854 bool MDMParser::setDebug(int level)
mazgch 74:208e3e32d263 1855 {
mazgch 74:208e3e32d263 1856 #ifdef MDM_DEBUG
mazgch 117:74e4e0109a9e 1857 if ((_debugLevel >= -1) && (level >= -1) &&
mazgch 117:74e4e0109a9e 1858 (_debugLevel <= 3) && (level <= 3)) {
mazgch 74:208e3e32d263 1859 _debugLevel = level;
mazgch 74:208e3e32d263 1860 return true;
mazgch 74:208e3e32d263 1861 }
mazgch 74:208e3e32d263 1862 #endif
mazgch 74:208e3e32d263 1863 return false;
mazgch 74:208e3e32d263 1864 }
mazgch 74:208e3e32d263 1865
mazgch 73:2b32e0a21df2 1866 void MDMParser::dumpDevStatus(MDMParser::DevStatus* status,
mazgch 73:2b32e0a21df2 1867 _DPRINT dprint, void* param)
mazgch 54:7ba8e4c218e2 1868 {
mazgch 75:ce6e12067d0c 1869 dprint(param, "Modem::devStatus\r\n");
mazgch 98:c786461edd40 1870 const char* txtDev[] = { "Unknown", "SARA-G350", "LISA-U200", "LISA-C200", "SARA-U260", "SARA-U270", "LEON-G200" };
mazgch 98:c786461edd40 1871 if (status->dev < sizeof(txtDev)/sizeof(*txtDev) && (status->dev != DEV_UNKNOWN))
mazgch 73:2b32e0a21df2 1872 dprint(param, " Device: %s\r\n", txtDev[status->dev]);
mazgch 54:7ba8e4c218e2 1873 const char* txtLpm[] = { "Disabled", "Enabled", "Active" };
mazgch 54:7ba8e4c218e2 1874 if (status->lpm < sizeof(txtLpm)/sizeof(*txtLpm))
mazgch 73:2b32e0a21df2 1875 dprint(param, " Power Save: %s\r\n", txtLpm[status->lpm]);
mazgch 75:ce6e12067d0c 1876 const char* txtSim[] = { "Unknown", "Missing", "Pin", "Ready" };
mazgch 98:c786461edd40 1877 if (status->sim < sizeof(txtSim)/sizeof(*txtSim) && (status->sim != SIM_UNKNOWN))
mazgch 73:2b32e0a21df2 1878 dprint(param, " SIM: %s\r\n", txtSim[status->sim]);
mazgch 54:7ba8e4c218e2 1879 if (*status->ccid)
mazgch 73:2b32e0a21df2 1880 dprint(param, " CCID: %s\r\n", status->ccid);
mazgch 54:7ba8e4c218e2 1881 if (*status->imei)
mazgch 73:2b32e0a21df2 1882 dprint(param, " IMEI: %s\r\n", status->imei);
mazgch 54:7ba8e4c218e2 1883 if (*status->imsi)
mazgch 73:2b32e0a21df2 1884 dprint(param, " IMSI: %s\r\n", status->imsi);
mazgch 54:7ba8e4c218e2 1885 if (*status->meid)
mazgch 73:2b32e0a21df2 1886 dprint(param, " MEID: %s\r\n", status->meid); // LISA-C
mazgch 54:7ba8e4c218e2 1887 if (*status->manu)
mazgch 73:2b32e0a21df2 1888 dprint(param, " Manufacturer: %s\r\n", status->manu);
mazgch 54:7ba8e4c218e2 1889 if (*status->model)
mazgch 73:2b32e0a21df2 1890 dprint(param, " Model: %s\r\n", status->model);
mazgch 54:7ba8e4c218e2 1891 if (*status->ver)
mazgch 73:2b32e0a21df2 1892 dprint(param, " Version: %s\r\n", status->ver);
mazgch 54:7ba8e4c218e2 1893 }
mazgch 54:7ba8e4c218e2 1894
mazgch 73:2b32e0a21df2 1895 void MDMParser::dumpNetStatus(MDMParser::NetStatus *status,
mazgch 73:2b32e0a21df2 1896 _DPRINT dprint, void* param)
mazgch 54:7ba8e4c218e2 1897 {
mazgch 75:ce6e12067d0c 1898 dprint(param, "Modem::netStatus\r\n");
mazgch 54:7ba8e4c218e2 1899 const char* txtReg[] = { "Unknown", "Denied", "None", "Home", "Roaming" };
mazgch 98:c786461edd40 1900 if (status->csd < sizeof(txtReg)/sizeof(*txtReg) && (status->csd != REG_UNKNOWN))
mazgch 79:291df065e345 1901 dprint(param, " CSD Registration: %s\r\n", txtReg[status->csd]);
mazgch 98:c786461edd40 1902 if (status->psd < sizeof(txtReg)/sizeof(*txtReg) && (status->psd != REG_UNKNOWN))
mazgch 79:291df065e345 1903 dprint(param, " PSD Registration: %s\r\n", txtReg[status->psd]);
mazgch 54:7ba8e4c218e2 1904 const char* txtAct[] = { "Unknown", "GSM", "Edge", "3G", "CDMA" };
mazgch 98:c786461edd40 1905 if (status->act < sizeof(txtAct)/sizeof(*txtAct) && (status->act != ACT_UNKNOWN))
mazgch 73:2b32e0a21df2 1906 dprint(param, " Access Technology: %s\r\n", txtAct[status->act]);
mazgch 54:7ba8e4c218e2 1907 if (status->rssi)
mazgch 73:2b32e0a21df2 1908 dprint(param, " Signal Strength: %d dBm\r\n", status->rssi);
mazgch 54:7ba8e4c218e2 1909 if (status->ber)
mazgch 73:2b32e0a21df2 1910 dprint(param, " Bit Error Rate: %d\r\n", status->ber);
mazgch 54:7ba8e4c218e2 1911 if (*status->opr)
mazgch 73:2b32e0a21df2 1912 dprint(param, " Operator: %s\r\n", status->opr);
mazgch 54:7ba8e4c218e2 1913 if (status->lac != 0xFFFF)
mazgch 73:2b32e0a21df2 1914 dprint(param, " Location Area Code: %04X\r\n", status->lac);
mazgch 54:7ba8e4c218e2 1915 if (status->ci != 0xFFFFFFFF)
mazgch 73:2b32e0a21df2 1916 dprint(param, " Cell ID: %08X\r\n", status->ci);
mazgch 54:7ba8e4c218e2 1917 if (*status->num)
mazgch 73:2b32e0a21df2 1918 dprint(param, " Phone Number: %s\r\n", status->num);
mazgch 54:7ba8e4c218e2 1919 }
mazgch 54:7ba8e4c218e2 1920
mazgch 73:2b32e0a21df2 1921 void MDMParser::dumpIp(MDMParser::IP ip,
mazgch 73:2b32e0a21df2 1922 _DPRINT dprint, void* param)
mazgch 54:7ba8e4c218e2 1923 {
mazgch 57:869bd35f44cc 1924 if (ip != NOIP)
mazgch 75:ce6e12067d0c 1925 dprint(param, "Modem:IP " IPSTR "\r\n", IPNUM(ip));
mazgch 54:7ba8e4c218e2 1926 }
mazgch 70:0a87d256cd24 1927
mazgch 21:c4d64830bf02 1928 // ----------------------------------------------------------------
mazgch 21:c4d64830bf02 1929 int MDMParser::_parseMatch(Pipe<char>* pipe, int len, const char* sta, const char* end)
mazgch 18:e5697801df29 1930 {
mazgch 18:e5697801df29 1931 int o = 0;
mazgch 21:c4d64830bf02 1932 if (sta) {
mazgch 21:c4d64830bf02 1933 while (*sta) {
mazgch 21:c4d64830bf02 1934 if (++o > len) return WAIT;
mazgch 21:c4d64830bf02 1935 char ch = pipe->next();
mazgch 21:c4d64830bf02 1936 if (*sta++ != ch) return NOT_FOUND;
mazgch 21:c4d64830bf02 1937 }
mazgch 21:c4d64830bf02 1938 }
mazgch 21:c4d64830bf02 1939 if (!end) return o; // no termination
mazgch 35:9275215a3a5b 1940 // at least any char
mazgch 35:9275215a3a5b 1941 if (++o > len) return WAIT;
mazgch 35:9275215a3a5b 1942 pipe->next();
mazgch 35:9275215a3a5b 1943 // check the end
mazgch 21:c4d64830bf02 1944 int x = 0;
mazgch 21:c4d64830bf02 1945 while (end[x]) {
mazgch 21:c4d64830bf02 1946 if (++o > len) return WAIT;
mazgch 21:c4d64830bf02 1947 char ch = pipe->next();
mazgch 21:c4d64830bf02 1948 x = (end[x] == ch) ? x + 1 :
mazgch 21:c4d64830bf02 1949 (end[0] == ch) ? 1 :
mazgch 21:c4d64830bf02 1950 0;
mazgch 21:c4d64830bf02 1951 }
mazgch 21:c4d64830bf02 1952 return o;
mazgch 21:c4d64830bf02 1953 }
mazgch 21:c4d64830bf02 1954
mazgch 21:c4d64830bf02 1955 int MDMParser::_parseFormated(Pipe<char>* pipe, int len, const char* fmt)
mazgch 21:c4d64830bf02 1956 {
mazgch 21:c4d64830bf02 1957 int o = 0;
mazgch 21:c4d64830bf02 1958 int num = 0;
mazgch 21:c4d64830bf02 1959 if (fmt) {
mazgch 21:c4d64830bf02 1960 while (*fmt) {
mazgch 21:c4d64830bf02 1961 if (++o > len) return WAIT;
mazgch 21:c4d64830bf02 1962 char ch = pipe->next();
mazgch 21:c4d64830bf02 1963 if (*fmt == '%') {
mazgch 21:c4d64830bf02 1964 fmt++;
mazgch 21:c4d64830bf02 1965 if (*fmt == 'd') { // numeric
mazgch 21:c4d64830bf02 1966 fmt ++;
mazgch 21:c4d64830bf02 1967 num = 0;
mazgch 21:c4d64830bf02 1968 while (ch >= '0' && ch <= '9') {
mazgch 21:c4d64830bf02 1969 num = num * 10 + (ch - '0');
mazgch 21:c4d64830bf02 1970 if (++o > len) return WAIT;
mazgch 21:c4d64830bf02 1971 ch = pipe->next();
mazgch 21:c4d64830bf02 1972 }
mazgch 21:c4d64830bf02 1973 }
mazgch 21:c4d64830bf02 1974 else if (*fmt == 'c') { // char buffer (takes last numeric as length)
mazgch 21:c4d64830bf02 1975 fmt ++;
mazgch 21:c4d64830bf02 1976 while (num --) {
mazgch 21:c4d64830bf02 1977 if (++o > len) return WAIT;
mazgch 21:c4d64830bf02 1978 ch = pipe->next();
mazgch 21:c4d64830bf02 1979 }
mazgch 21:c4d64830bf02 1980 }
mazgch 80:34985b4d821e 1981 else if (*fmt == 's') {
mazgch 80:34985b4d821e 1982 fmt ++;
mazgch 80:34985b4d821e 1983 if (ch != '\"') return NOT_FOUND;
mazgch 80:34985b4d821e 1984 do {
mazgch 80:34985b4d821e 1985 if (++o > len) return WAIT;
mazgch 80:34985b4d821e 1986 ch = pipe->next();
mazgch 80:34985b4d821e 1987 } while (ch != '\"');
mazgch 80:34985b4d821e 1988 if (++o > len) return WAIT;
mazgch 80:34985b4d821e 1989 ch = pipe->next();
mazgch 80:34985b4d821e 1990 }
mazgch 21:c4d64830bf02 1991 }
mazgch 21:c4d64830bf02 1992 if (*fmt++ != ch) return NOT_FOUND;
mazgch 18:e5697801df29 1993 }
mazgch 18:e5697801df29 1994 }
mazgch 21:c4d64830bf02 1995 return o;
mazgch 21:c4d64830bf02 1996 }
mazgch 21:c4d64830bf02 1997
mazgch 21:c4d64830bf02 1998 int MDMParser::_getLine(Pipe<char>* pipe, char* buf, int len)
mazgch 21:c4d64830bf02 1999 {
mazgch 21:c4d64830bf02 2000 int unkn = 0;
mazgch 21:c4d64830bf02 2001 int sz = pipe->size();
mazgch 21:c4d64830bf02 2002 int fr = pipe->free();
mazgch 21:c4d64830bf02 2003 if (len > sz)
mazgch 21:c4d64830bf02 2004 len = sz;
mazgch 21:c4d64830bf02 2005 while (len > 0)
mazgch 21:c4d64830bf02 2006 {
mazgch 21:c4d64830bf02 2007 static struct {
mazgch 21:c4d64830bf02 2008 const char* fmt; int type;
mazgch 21:c4d64830bf02 2009 } lutF[] = {
mazgch 21:c4d64830bf02 2010 { "\r\n+USORD: %d,%d,\"%c\"", TYPE_PLUS },
mazgch 95:8282dbbe1492 2011 { "\r\n+USORF: %d,\"" IPSTR "\",%d,%d,\"%c\"", TYPE_PLUS },
mazgch 80:34985b4d821e 2012 { "\r\n+URDFILE: %s,%d,\"%c\"", TYPE_PLUS },
mazgch 21:c4d64830bf02 2013 };
mazgch 21:c4d64830bf02 2014 static struct {
mazgch 21:c4d64830bf02 2015 const char* sta; const char* end; int type;
mazgch 21:c4d64830bf02 2016 } lut[] = {
mazgch 21:c4d64830bf02 2017 { "\r\nOK\r\n", NULL, TYPE_OK },
mazgch 21:c4d64830bf02 2018 { "\r\nERROR\r\n", NULL, TYPE_ERROR },
mazgch 31:a0bed6c1e05d 2019 { "\r\n+CME ERROR:", "\r\n", TYPE_ERROR },
mazgch 21:c4d64830bf02 2020 { "\r\n+CMS ERROR:", "\r\n", TYPE_ERROR },
mazgch 21:c4d64830bf02 2021 { "\r\nRING\r\n", NULL, TYPE_RING },
mazgch 21:c4d64830bf02 2022 { "\r\nCONNECT\r\n", NULL, TYPE_CONNECT },
mazgch 21:c4d64830bf02 2023 { "\r\nNO CARRIER\r\n", NULL, TYPE_NOCARRIER },
mazgch 21:c4d64830bf02 2024 { "\r\nNO DIALTONE\r\n", NULL, TYPE_NODIALTONE },
mazgch 21:c4d64830bf02 2025 { "\r\nBUSY\r\n", NULL, TYPE_BUSY },
mazgch 21:c4d64830bf02 2026 { "\r\nNO ANSWER\r\n", NULL, TYPE_NOANSWER },
mazgch 21:c4d64830bf02 2027 { "\r\n+", "\r\n", TYPE_PLUS },
RobMeades 126:76b578ec2912 2028 { "+", "\r\n", TYPE_PLUS }, // Special for Neul modem as they sometimes drop off the \r\n at the start
mazgch 21:c4d64830bf02 2029 { "\r\n@", NULL, TYPE_PROMPT }, // Sockets
mazgch 21:c4d64830bf02 2030 { "\r\n>", NULL, TYPE_PROMPT }, // SMS
mazgch 80:34985b4d821e 2031 { "\n>", NULL, TYPE_PROMPT }, // File
mazgch 21:c4d64830bf02 2032 };
mazgch 21:c4d64830bf02 2033 for (int i = 0; i < sizeof(lutF)/sizeof(*lutF); i ++) {
mazgch 21:c4d64830bf02 2034 pipe->set(unkn);
mazgch 21:c4d64830bf02 2035 int ln = _parseFormated(pipe, len, lutF[i].fmt);
mazgch 21:c4d64830bf02 2036 if (ln == WAIT && fr)
mazgch 21:c4d64830bf02 2037 return WAIT;
mazgch 21:c4d64830bf02 2038 if ((ln != NOT_FOUND) && (unkn > 0))
mazgch 31:a0bed6c1e05d 2039 return TYPE_UNKNOWN | pipe->get(buf, unkn);
mazgch 21:c4d64830bf02 2040 if (ln > 0)
mazgch 21:c4d64830bf02 2041 return lutF[i].type | pipe->get(buf, ln);
mazgch 21:c4d64830bf02 2042 }
mazgch 21:c4d64830bf02 2043 for (int i = 0; i < sizeof(lut)/sizeof(*lut); i ++) {
mazgch 21:c4d64830bf02 2044 pipe->set(unkn);
mazgch 21:c4d64830bf02 2045 int ln = _parseMatch(pipe, len, lut[i].sta, lut[i].end);
mazgch 21:c4d64830bf02 2046 if (ln == WAIT && fr)
mazgch 21:c4d64830bf02 2047 return WAIT;
mazgch 21:c4d64830bf02 2048 if ((ln != NOT_FOUND) && (unkn > 0))
mazgch 31:a0bed6c1e05d 2049 return TYPE_UNKNOWN | pipe->get(buf, unkn);
mazgch 21:c4d64830bf02 2050 if (ln > 0)
mazgch 21:c4d64830bf02 2051 return lut[i].type | pipe->get(buf, ln);
mazgch 21:c4d64830bf02 2052 }
mazgch 21:c4d64830bf02 2053 // UNKNOWN
mazgch 21:c4d64830bf02 2054 unkn ++;
mazgch 21:c4d64830bf02 2055 len--;
mazgch 21:c4d64830bf02 2056 }
mazgch 18:e5697801df29 2057 return WAIT;
mazgch 18:e5697801df29 2058 }
mazgch 18:e5697801df29 2059
mazgch 18:e5697801df29 2060 // ----------------------------------------------------------------
mazgch 18:e5697801df29 2061 // Serial Implementation
mazgch 18:e5697801df29 2062 // ----------------------------------------------------------------
mazgch 18:e5697801df29 2063
mazgch 76:f7c3dd568dae 2064 /*! Helper Dev Null Device
mazgch 76:f7c3dd568dae 2065 Small helper class used to shut off stderr/stdout. Sometimes stdin/stdout
mazgch 76:f7c3dd568dae 2066 is shared with the serial port of the modem. Having printfs inbetween the
mazgch 76:f7c3dd568dae 2067 AT commands you cause a failure of the modem.
mazgch 76:f7c3dd568dae 2068 */
mazgch 76:f7c3dd568dae 2069 class DevNull : public Stream {
mazgch 76:f7c3dd568dae 2070 public:
mazgch 76:f7c3dd568dae 2071 DevNull() : Stream(_name+1) { } //!< Constructor
mazgch 76:f7c3dd568dae 2072 void claim(const char* mode, FILE* file)
mazgch 76:f7c3dd568dae 2073 { freopen(_name, mode, file); } //!< claim a stream
mazgch 76:f7c3dd568dae 2074 protected:
mazgch 76:f7c3dd568dae 2075 virtual int _getc() { return EOF; } //!< Nothing
mazgch 76:f7c3dd568dae 2076 virtual int _putc(int c) { return c; } //!< Discard
mazgch 76:f7c3dd568dae 2077 static const char* _name; //!< File name
mazgch 76:f7c3dd568dae 2078 };
mazgch 76:f7c3dd568dae 2079 const char* DevNull::_name = "/null"; //!< the null device name
mazgch 76:f7c3dd568dae 2080 static DevNull null; //!< the null device
mazgch 76:f7c3dd568dae 2081
mazgch 19:2b5d097ca15d 2082 MDMSerial::MDMSerial(PinName tx /*= MDMTXD*/, PinName rx /*= MDMRXD*/,
mazgch 19:2b5d097ca15d 2083 int baudrate /*= MDMBAUD*/,
mazgch 43:a89a7a505991 2084 #if DEVICE_SERIAL_FC
mazgch 19:2b5d097ca15d 2085 PinName rts /*= MDMRTS*/, PinName cts /*= MDMCTS*/,
mazgch 43:a89a7a505991 2086 #endif
mazgch 18:e5697801df29 2087 int rxSize /*= 256*/, int txSize /*= 128*/) :
mazgch 35:9275215a3a5b 2088 SerialPipe(tx, rx, rxSize, txSize)
mazgch 18:e5697801df29 2089 {
mazgch 76:f7c3dd568dae 2090 if (rx == USBRX)
mazgch 76:f7c3dd568dae 2091 null.claim("r", stdin);
mazgch 76:f7c3dd568dae 2092 if (tx == USBTX) {
mazgch 76:f7c3dd568dae 2093 null.claim("w", stdout);
mazgch 76:f7c3dd568dae 2094 null.claim("w", stderr);
mazgch 74:208e3e32d263 2095 #ifdef MDM_DEBUG
mazgch 76:f7c3dd568dae 2096 _debugLevel = -1;
mazgch 76:f7c3dd568dae 2097 #endif
mazgch 76:f7c3dd568dae 2098 }
mazgch 74:208e3e32d263 2099 #ifdef TARGET_UBLOX_C027
mazgch 74:208e3e32d263 2100 _onboard = (tx == MDMTXD) && (rx == MDMRXD);
mazgch 74:208e3e32d263 2101 if (_onboard)
mazgch 74:208e3e32d263 2102 c027_mdm_powerOn(false);
mazgch 74:208e3e32d263 2103 #endif
mazgch 18:e5697801df29 2104 baud(baudrate);
mazgch 35:9275215a3a5b 2105 #if DEVICE_SERIAL_FC
mazgch 35:9275215a3a5b 2106 if ((rts != NC) || (cts != NC))
mazgch 35:9275215a3a5b 2107 {
mazgch 35:9275215a3a5b 2108 Flow flow = (cts == NC) ? RTS :
mazgch 35:9275215a3a5b 2109 (rts == NC) ? CTS : RTSCTS ;
mazgch 35:9275215a3a5b 2110 set_flow_control(flow, rts, cts);
mazgch 35:9275215a3a5b 2111 if (cts != NC) _dev.lpm = LPM_ENABLED;
mazgch 35:9275215a3a5b 2112 }
mazgch 35:9275215a3a5b 2113 #endif
mazgch 18:e5697801df29 2114 }
mazgch 18:e5697801df29 2115
mazgch 76:f7c3dd568dae 2116 MDMSerial::~MDMSerial(void)
mazgch 76:f7c3dd568dae 2117 {
mazgch 76:f7c3dd568dae 2118 powerOff();
mazgch 76:f7c3dd568dae 2119 #ifdef TARGET_UBLOX_C027
mazgch 76:f7c3dd568dae 2120 if (_onboard)
mazgch 76:f7c3dd568dae 2121 c027_mdm_powerOff();
mazgch 76:f7c3dd568dae 2122 #endif
mazgch 76:f7c3dd568dae 2123 }
mazgch 76:f7c3dd568dae 2124
mazgch 18:e5697801df29 2125 int MDMSerial::_send(const void* buf, int len)
mazgch 18:e5697801df29 2126 {
mazgch 35:9275215a3a5b 2127 return put((const char*)buf, len, true/*=blocking*/);
mazgch 18:e5697801df29 2128 }
mazgch 18:e5697801df29 2129
mazgch 18:e5697801df29 2130 int MDMSerial::getLine(char* buffer, int length)
mazgch 18:e5697801df29 2131 {
mazgch 18:e5697801df29 2132 return _getLine(&_pipeRx, buffer, length);
mazgch 18:e5697801df29 2133 }
mazgch 18:e5697801df29 2134
mazgch 18:e5697801df29 2135 // ----------------------------------------------------------------
mazgch 18:e5697801df29 2136 // USB Implementation
mazgch 18:e5697801df29 2137 // ----------------------------------------------------------------
mazgch 18:e5697801df29 2138
mazgch 18:e5697801df29 2139 #ifdef HAVE_MDMUSB
mazgch 76:f7c3dd568dae 2140 MDMUsb::MDMUsb(void)
mazgch 74:208e3e32d263 2141 {
mazgch 74:208e3e32d263 2142 #ifdef MDM_DEBUG
mazgch 74:208e3e32d263 2143 _debugLevel = 1;
mazgch 74:208e3e32d263 2144 #endif
mazgch 74:208e3e32d263 2145 #ifdef TARGET_UBLOX_C027
mazgch 74:208e3e32d263 2146 _onboard = true;
mazgch 74:208e3e32d263 2147 c027_mdm_powerOn(true);
mazgch 74:208e3e32d263 2148 #endif
mazgch 74:208e3e32d263 2149 }
mazgch 76:f7c3dd568dae 2150
mazgch 76:f7c3dd568dae 2151 MDMUsb::~MDMUsb(void)
mazgch 76:f7c3dd568dae 2152 {
mazgch 76:f7c3dd568dae 2153 powerOff();
mazgch 76:f7c3dd568dae 2154 #ifdef TARGET_UBLOX_C027
mazgch 76:f7c3dd568dae 2155 if (_onboard)
mazgch 76:f7c3dd568dae 2156 c027_mdm_powerOff();
mazgch 76:f7c3dd568dae 2157 #endif
mazgch 76:f7c3dd568dae 2158 }
mazgch 76:f7c3dd568dae 2159
mazgch 76:f7c3dd568dae 2160 int MDMUsb::_send(const void* buf, int len) { return 0; }
mazgch 76:f7c3dd568dae 2161
mazgch 18:e5697801df29 2162 int MDMUsb::getLine(char* buffer, int length) { return NOT_FOUND; }
mazgch 76:f7c3dd568dae 2163
RobMeades 126:76b578ec2912 2164 #endif