~ubuntu-branches/ubuntu/trusty/gsmlib/trusty

« back to all changes in this revision

Viewing changes to gsmlib/gsm_at.cc

  • Committer: Bazaar Package Importer
  • Author(s): Mikael Hedin
  • Date: 2002-01-24 12:59:07 UTC
  • Revision ID: james.westby@ubuntu.com-20020124125907-b7qkpokx5283jdpu
Tags: upstream-1.8
ImportĀ upstreamĀ versionĀ 1.8

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// *************************************************************************
 
2
// * GSM TA/ME library
 
3
// *
 
4
// * File:    gsm_at.cc
 
5
// *
 
6
// * Purpose: Utility classes for AT command sequence handling
 
7
// *
 
8
// * Author:  Peter Hofmann (software@pxh.de)
 
9
// *
 
10
// * Created: 3.5.1999
 
11
// *************************************************************************
 
12
 
 
13
#ifdef HAVE_CONFIG_H
 
14
#include <gsm_config.h>
 
15
#endif
 
16
#include <gsmlib/gsm_at.h>
 
17
#include <gsmlib/gsm_nls.h>
 
18
#include <gsmlib/gsm_util.h>
 
19
#include <gsmlib/gsm_error.h>
 
20
#include <gsmlib/gsm_event.h>
 
21
#include <gsmlib/gsm_me_ta.h>
 
22
#include <ctype.h>
 
23
#include <strstream>
 
24
 
 
25
using namespace std;
 
26
using namespace gsmlib;
 
27
 
 
28
// GsmAt members
 
29
 
 
30
bool GsmAt::matchResponse(string answer, string responseToMatch)
 
31
{
 
32
  if (answer.substr(0, responseToMatch.length()) == responseToMatch)
 
33
    return true;
 
34
  else
 
35
    // some TAs omit the ':' at the end of the response
 
36
    if (_meTa.getCapabilities()._omitsColon &&
 
37
        responseToMatch[responseToMatch.length() - 1] == ':' &&
 
38
        answer.substr(0, responseToMatch.length() - 1) == 
 
39
        responseToMatch.substr(0, responseToMatch.length() - 1))
 
40
      return true;
 
41
  return false;
 
42
}
 
43
 
 
44
string GsmAt::cutResponse(string answer, string responseToMatch)
 
45
{
 
46
  if (answer.substr(0, responseToMatch.length()) == responseToMatch)
 
47
    return normalize(answer.substr(responseToMatch.length(),
 
48
                                   answer.length() -
 
49
                                   responseToMatch.length()));
 
50
  else
 
51
    // some TAs omit the ':' at the end of the response
 
52
    if (_meTa.getCapabilities()._omitsColon &&
 
53
        responseToMatch[responseToMatch.length() - 1] == ':' &&
 
54
        answer.substr(0, responseToMatch.length() - 1) == 
 
55
        responseToMatch.substr(0, responseToMatch.length() - 1))
 
56
      return normalize(answer.substr(responseToMatch.length() - 1,
 
57
                                     answer.length() -
 
58
                                     responseToMatch.length() + 1));
 
59
  assert(0);
 
60
  return "";
 
61
}
 
62
 
 
63
void GsmAt::throwCmeException(string s) throw(GsmException)
 
64
{
 
65
  if (matchResponse(s, "ERROR"))
 
66
    throw GsmException(_("unspecified ME/TA error"), ChatError);
 
67
 
 
68
  bool meError = matchResponse(s, "+CME ERROR:");
 
69
  if (meError)
 
70
    s = cutResponse(s, "+CME ERROR:");
 
71
  else
 
72
    s = cutResponse(s, "+CMS ERROR:");
 
73
  istrstream is(s.c_str());
 
74
  int error;
 
75
  is >> error;
 
76
  throw GsmException(_("ME/TA error '") +
 
77
                     (meError ? getMEErrorText(error) :
 
78
                      getSMSErrorText(error)) +
 
79
                     "' " +
 
80
                     stringPrintf(_("(code %s)"), s.c_str()),
 
81
                     ChatError, error);
 
82
}
 
83
 
 
84
GsmAt::GsmAt(MeTa &meTa) :
 
85
  _meTa(meTa), _port(meTa.getPort()), _eventHandler(NULL)
 
86
{
 
87
}
 
88
 
 
89
string GsmAt::chat(string atCommand, string response,
 
90
                   bool ignoreErrors, bool acceptEmptyResponse)
 
91
  throw(GsmException)
 
92
{
 
93
  string dummy;
 
94
  return chat(atCommand, response, dummy, ignoreErrors, false,
 
95
              acceptEmptyResponse);
 
96
}
 
97
 
 
98
string GsmAt::chat(string atCommand, string response, string &pdu,
 
99
                   bool ignoreErrors, bool expectPdu,
 
100
                   bool acceptEmptyResponse) throw(GsmException)
 
101
{
 
102
  string s;
 
103
  bool gotOk = false;           // special handling for empty SMS entries
 
104
 
 
105
  // send AT command
 
106
  putLine("AT" + atCommand);
 
107
  // and gobble up CR/LF (and possibly echoed characters if echo can't be
 
108
  // switched off)
 
109
  do
 
110
  {
 
111
    s = normalize(getLine());
 
112
  }
 
113
  while (s.length() == 0 || s == "AT" + atCommand);
 
114
 
 
115
  // handle errors
 
116
  if (matchResponse(s, "+CME ERROR:") || matchResponse(s, "+CMS ERROR:"))
 
117
    if (ignoreErrors)
 
118
      return "";
 
119
    else
 
120
      throwCmeException(s);
 
121
  if (matchResponse(s, "ERROR"))
 
122
    if (ignoreErrors)
 
123
      return "";
 
124
    else
 
125
      throw GsmException(_("ME/TA error '<unspecified>' (code not known)"), 
 
126
                         ChatError, -1);
 
127
 
 
128
  // return if response is "OK" and caller says this is OK
 
129
  if (acceptEmptyResponse && s == "OK")
 
130
    return "";
 
131
 
 
132
  // handle PDU if one is expected
 
133
  if (expectPdu)
 
134
  {
 
135
    string ps;
 
136
    do
 
137
    {
 
138
      ps = normalize(getLine());
 
139
    }
 
140
    while (ps.length() == 0 && ps != "OK");
 
141
    if (ps == "OK")
 
142
      gotOk = true;
 
143
    else
 
144
    {
 
145
      pdu = ps;
 
146
      // remove trailing zero added by some devices (e.g. Falcom A2-1)
 
147
      if (pdu.length() > 0 && pdu[pdu.length() - 1] == 0)
 
148
        pdu.erase(pdu.length() - 1);
 
149
    }
 
150
  }
 
151
 
 
152
  // handle expected response
 
153
  if (response.length() == 0)   // no response expected
 
154
  {
 
155
    if (s == "OK") return "";
 
156
    // else fall through to error
 
157
  }
 
158
  else
 
159
  {
 
160
    string result;
 
161
    // some TA/TEs don't prefix their response with the response string
 
162
    // as proscribed by the standard: just handle either case
 
163
    if (matchResponse(s, response))
 
164
      result = cutResponse(s, response);
 
165
    else
 
166
      result = s;
 
167
 
 
168
    if (gotOk)
 
169
      return result;
 
170
    else
 
171
    {
 
172
      // get the final "OK"
 
173
      do
 
174
      {
 
175
        s = normalize(getLine());
 
176
      }
 
177
      while (s.length() == 0);
 
178
 
 
179
      if (s == "OK") return result;
 
180
      // else fall through to error
 
181
    }
 
182
  }
 
183
  throw GsmException(
 
184
    stringPrintf(_("unexpected response '%s' when sending 'AT%s'"),
 
185
                 s.c_str(), atCommand.c_str()),
 
186
    ChatError);
 
187
}
 
188
 
 
189
vector<string> GsmAt::chatv(string atCommand, string response,
 
190
                            bool ignoreErrors) throw(GsmException)
 
191
{
 
192
  string s;
 
193
  vector<string> result;
 
194
 
 
195
  // send AT command
 
196
  putLine("AT" + atCommand);
 
197
  // and gobble up CR/LF (and possibly echoed characters if echo can't be
 
198
  // switched off)
 
199
  do
 
200
  {
 
201
    s = normalize(getLine());
 
202
  }
 
203
  while (s.length() == 0 || s == "AT" + atCommand);
 
204
 
 
205
  // handle errors
 
206
  if (matchResponse(s, "+CME ERROR:") || matchResponse(s, "+CMS ERROR:"))
 
207
    if (ignoreErrors)
 
208
      return result;
 
209
    else
 
210
      throwCmeException(s);
 
211
  if (matchResponse(s, "ERROR"))
 
212
    if (ignoreErrors)
 
213
      return result;
 
214
    else
 
215
      throw GsmException(_("ME/TA error '<unspecified>' (code not known)"), 
 
216
                         ChatError, -1);
 
217
 
 
218
  // push all lines that are not empty
 
219
  // cut response prefix if it is there
 
220
  // stop when an OK line is read
 
221
  while (1)
 
222
  {
 
223
    if (s == "OK")
 
224
      return result;
 
225
    // some TA/TEs don't prefix their response with the response string
 
226
    // as proscribed by the standard: just handle either case
 
227
    if (response.length() != 0 && matchResponse(s, response))
 
228
      result.push_back(cutResponse(s, response));
 
229
    else
 
230
      result.push_back(s);
 
231
    // get next line
 
232
    do
 
233
    {
 
234
      s = normalize(getLine());
 
235
    }
 
236
    while (s.length() == 0);
 
237
    reportProgress();
 
238
  }
 
239
 
 
240
  // never reached
 
241
  assert(0);
 
242
  return result;
 
243
}
 
244
 
 
245
string GsmAt::normalize(string s)
 
246
{
 
247
  size_t start = 0, end = s.length();
 
248
  bool changed = true;
 
249
 
 
250
  while (start < end && changed)
 
251
  {
 
252
    changed = false;
 
253
    if (isspace(s[start]))
 
254
    {
 
255
      ++start;
 
256
      changed = true;
 
257
    }
 
258
    else
 
259
      if (isspace(s[end - 1]))
 
260
      {
 
261
        --end;
 
262
        changed = true;
 
263
      }
 
264
  }
 
265
  return s.substr(start, end - start);
 
266
}
 
267
 
 
268
string GsmAt::sendPdu(string atCommand, string response,
 
269
                      string pdu) throw(GsmException)
 
270
{
 
271
  string s;
 
272
  bool errorCondition = false;
 
273
  bool retry = false;
 
274
 
 
275
  int c;
 
276
  do
 
277
  {
 
278
    putLine("AT" + atCommand);
 
279
    // read first of two bytes "> "
 
280
    c = readByte();
 
281
    
 
282
    // there have been reports that some phones give spurious CRs
 
283
    if (c == CR)
 
284
      c = readByte();
 
285
 
 
286
    if (c == '+' || c == 'E')   // error or unsolicited result code
 
287
    {
 
288
      _port->putBack(c);
 
289
      s = normalize(getLine());
 
290
      errorCondition = (s != "");
 
291
      
 
292
      retry = ! errorCondition;
 
293
      // The following code is for the unlikely case that the TA wants
 
294
      // to resume PDU sending after an unsolicited result code.
 
295
      // For the time being I have decided that it is better to retry
 
296
      // in this case.
 
297
//       if (! errorCondition)
 
298
//       {
 
299
//         // readByte() times out after TIMEOUT_SECS (gsm_port.h) seconds 
 
300
//         try
 
301
//         {
 
302
//           c = readByte();
 
303
//           retry = c != '>';     // TA still expects PDU if c == '>'
 
304
//           if (retry)
 
305
//              _port->putBack(c);
 
306
//         }
 
307
//         catch (GsmException &e)
 
308
//         {
 
309
//           retry = true;         // TA does not expect PDU anymore, retry
 
310
//         }
 
311
//       }
 
312
    }
 
313
  }
 
314
  while (retry);
 
315
 
 
316
  if (! errorCondition)
 
317
  {
 
318
    
 
319
    if (c != '>' || readByte() != ' ')
 
320
      throw GsmException(_("unexpected character in PDU handshake"),
 
321
                         ChatError);
 
322
    
 
323
    putLine(pdu + "\032", false); // write pdu followed by CTRL-Z
 
324
    do
 
325
    {
 
326
      s = normalize(getLine());
 
327
    }
 
328
    while (s.length() == 0 || s == pdu);
 
329
  }
 
330
 
 
331
  // handle errors
 
332
  if (matchResponse(s, "+CME ERROR:") || matchResponse(s, "+CMS ERROR:"))
 
333
    throwCmeException(s);
 
334
  if (matchResponse(s, "ERROR"))
 
335
    throw GsmException(_("ME/TA error '<unspecified>' (code not known)"), 
 
336
                       ChatError, -1);
 
337
 
 
338
  if (matchResponse(s, response))
 
339
  {
 
340
    string result = cutResponse(s, response);
 
341
    // get the final "OK"
 
342
    do
 
343
    {
 
344
      s = normalize(getLine());
 
345
    }
 
346
    while (s.length() == 0);
 
347
 
 
348
    if (s == "OK") return result;
 
349
    // else fall through to error
 
350
  }
 
351
  throw GsmException(
 
352
    stringPrintf(_("unexpected response '%s' when sending 'AT%s'"),
 
353
                 s.c_str(), atCommand.c_str()),
 
354
    ChatError);
 
355
}
 
356
 
 
357
string GsmAt::getLine() throw(GsmException)
 
358
{
 
359
  if (_eventHandler == (GsmEvent*)NULL)
 
360
    return _port->getLine();
 
361
  else
 
362
  {
 
363
    bool eventOccurred;
 
364
    string result;
 
365
    do
 
366
    {
 
367
      eventOccurred = false;
 
368
      result = _port->getLine();
 
369
      string s = normalize(result);
 
370
      if (matchResponse(s, "+CMT:") ||
 
371
          matchResponse(s, "+CBM:") ||
 
372
          matchResponse(s, "+CDS:") ||
 
373
          matchResponse(s, "+CMTI:") ||
 
374
          matchResponse(s, "+CBMI:") ||
 
375
          matchResponse(s, "+CDSI:") ||
 
376
          matchResponse(s, "RING") ||
 
377
          // hack: the +CLIP? sequence returns +CLIP: n,m
 
378
          // which is NOT an unsolicited result code
 
379
          (matchResponse(s, "+CLIP:") && s.length() > 10))
 
380
      {
 
381
        _eventHandler->dispatch(s, *this);
 
382
        eventOccurred = true;
 
383
      }
 
384
    }
 
385
    while (eventOccurred);
 
386
    return result;
 
387
  }
 
388
}
 
389
 
 
390
void GsmAt::putLine(string line,
 
391
                    bool carriageReturn) throw(GsmException)
 
392
{
 
393
  _port->putLine(line, carriageReturn);
 
394
  // remove empty echo line
 
395
  if (carriageReturn)
 
396
    getLine();
 
397
}
 
398
 
 
399
bool GsmAt::wait(GsmTime timeout) throw(GsmException)
 
400
{
 
401
  return _port->wait(timeout);
 
402
}
 
403
 
 
404
int GsmAt::readByte() throw(GsmException)
 
405
{
 
406
  return _port->readByte();
 
407
}
 
408
 
 
409
GsmEvent *GsmAt::setEventHandler(GsmEvent *newHandler)
 
410
{
 
411
  GsmEvent *result = _eventHandler;
 
412
  _eventHandler = newHandler;
 
413
  return result;
 
414
}