Gammu internals  1.38.0
at.c
Go to the documentation of this file.
1 /* (c) 2002-2004 by Marcin Wiacek and Michal Cihar */
2 
3 #include "../../gsmstate.h"
4 
5 #if defined(GSM_ENABLE_AT) || defined(GSM_ENABLE_BLUEAT) || defined(GSM_ENABLE_IRDAAT) || defined(GSM_ENABLE_DKU2AT)
6 
7 #include <stdio.h>
8 #include <string.h>
9 #include <stdlib.h>
10 
11 #include "../../gsmcomon.h"
12 #include "at.h"
13 
14 static GSM_Error AT_WriteMessage (GSM_StateMachine *s, unsigned const char *buffer,
15  int length, int type)
16 {
17  int sent=0, write_data=0, i=0;
18 
19  GSM_DumpMessageText(s, buffer, length, type);
20  GSM_DumpMessageBinary(s, buffer, length, type);
21 
22  if (s->Protocol.Data.AT.FastWrite) {
23  while (sent != length) {
24  write_data = s->Device.Functions->WriteDevice(s,buffer + sent, length - sent);
25 
26  if (write_data == 0 || write_data < 0) {
27  return ERR_DEVICEWRITEERROR;
28  }
29  sent += write_data;
30  }
31  } else {
32  for (i = 0; i < length; i++) {
33  /* For some phones like Siemens M20 we need to wait a little
34  * after writing each char. Possible reason: these phones
35  * can't receive so fast chars or there is bug here in Gammu */
36  write_data = s->Device.Functions->WriteDevice(s, buffer + i, 1);
37 
38  if (write_data != 1) {
39  return ERR_DEVICEWRITEERROR;
40  }
41  usleep(1000);
42  }
43  usleep(400000);
44  }
45  return ERR_NONE;
46 }
47 
48 typedef struct {
49  const char *text;
50  int lines;
51  GSM_Phone_RequestID requestid;
52 } SpecialAnswersStruct;
53 
54 GSM_Error AT_StateMachine(GSM_StateMachine *s, unsigned char rx_char)
55 {
57  GSM_Protocol_ATData *d = &s->Protocol.Data.AT;
58  size_t i;
59 
60  /* These are lines with end of "normal" answers */
61  static const char *StatusStrings[] = {
62  /* Standard AT */
63  "OK\r",
64  "ERROR\r",
65 
66  /* AT with bad end of lines */
67  "OK\n",
68  "ERROR\n",
69 
70  /* Standard GSM */
71  "+CME ERROR:",
72  "+CMS ERROR:",
73 
74  /* Motorola A1200 */
75  "MODEM ERROR:",
76 
77  /* Huawei */
78  "COMMAND NOT SUPPORT",
79 
80  NULL};
81 
82  /* Some info from phone can be inside "normal" answers
83  * It starts with strings written here
84  */
85  static const SpecialAnswersStruct SpecialAnswers[] = {
86  /* Standard GSM */
87  {"+CGREG:" ,1, ID_GetNetworkInfo},
88  {"+CBM:" ,1, ID_All},
89  {"+CMT:" ,2, ID_All},
90  {"+CMTI:" ,1, ID_All},
91  {"+CDS:" ,2, ID_All},
92  {"+CDSI:" ,1, ID_All},
93  {"+CREG:" ,1, ID_GetNetworkInfo},
94  {"+CUSD" ,1, ID_All},
95  {"+COLP" ,1, ID_All},
96  {"+CLIP" ,1, ID_All},
97  {"+CRING" ,1, ID_All},
98  {"+CCWA" ,1, ID_All},
99  {"+CLCC" ,1, ID_All},
100 
101  /* Standard AT */
102  {"RING" ,1, ID_All},
103  {"NO CARRIER" ,1, ID_All},
104  {"NO ANSWER" ,1, ID_All},
105 
106  /* GlobeTrotter */
107  {"_OSIGQ:" ,1, ID_All},
108  {"_OBS:" ,1, ID_All},
109 
110  {"^SCN:" ,1, ID_All},
111 
112  /* Sony-Ericsson */
113  {"*EBCA" ,1, ID_All},
114 
115  /* Samsung binary transfer end */
116  {"SDNDCRC =" ,1, ID_All},
117  /* Samsung reply to SSHT in some cases */
118  {"SAMSUNG PTS DG Test", 1, ID_All},
119 
120  /* Cross PD1101wi reply to almost anything */
121  {"NOT FOND ^,NOT CUSTOM AT", 1, ID_All},
122 
123  /* Motorola banner */
124  {"+MBAN:" ,1, ID_All},
125 
126  /* HSPA CORPORATION */
127  {"+ZEND" ,1, ID_All},
128 
129  /* Huawei */
130  {"^RSSI:" ,1, ID_All}, /* ^RSSI:18 */
131  {"^HCSQ:" ,1, ID_All}, /* ^HCSQ:"WCDMA",39,29,45 */
132  {"^DSFLOWRPT:" ,1, ID_All}, /* ^DSFLOWRPT:00000124,00000082,00000EA6,0000000000012325,000000000022771D,0000BB80,0001F400 */
133  {"^BOOT:" ,1, ID_All}, /* ^BOOT:27710117,0,0,0,75 */
134  {"^MODE:" ,1, ID_All}, /* ^MODE:3,3 */
135  {"^CSNR:" ,1, ID_All}, /* ^CSNR:-93,-23 */
136  {"^HCSQ:" ,1, ID_All}, /* ^HCSQ:"LTE",59,50,161,24 */
137  {"^SRVST:" ,1, ID_All}, /* ^SRVST:0 */
138  {"^SIMST:" ,1, ID_All}, /* ^SIMST:1 */
139  {"^STIN:" ,1, ID_All}, /* ^STIN: 7, 0, 0 */
140 
141  /* ONDA */
142  {"+ZUSIMR:" ,1, ID_All}, /* +ZUSIMR:2 */
143 
144  {NULL ,1, ID_All}};
145 
146  /* We're starting new message */
147  if (d->Msg.Length == 0) {
148  /* Ignore leading CR, LF and ESC */
149  if (rx_char == 10 || rx_char == 13 || rx_char == 27) {
150  return ERR_NONE;
151  }
152  d->LineStart = 0;
153  }
154 
155  /* Allocate more memory if needed */
156  if (d->Msg.BufferUsed < d->Msg.Length + 2) {
157  d->Msg.BufferUsed = d->Msg.Length + 200;
158  d->Msg.Buffer = (unsigned char *)realloc(d->Msg.Buffer,d->Msg.BufferUsed);
159  if (d->Msg.Buffer == NULL) {
160  return ERR_MOREMEMORY;
161  }
162  }
163 
164  /* Store current char in the buffer */
165  d->Msg.Buffer[d->Msg.Length++] = rx_char;
166  d->Msg.Buffer[d->Msg.Length ] = 0;
167 
168  /* Parse char */
169  switch (rx_char) {
170  case 0:
171  break;
172  case 10:
173  case 13:
174  /* Store line end (if we did not do it in last char */
175  if (! d->wascrlf) {
176  d->LineEnd = d->Msg.Length - 1;
177  }
178  d->wascrlf = TRUE;
179 
180  /* Process line after \r\n */
181  if (d->Msg.Length > 0 && rx_char == 10 && d->Msg.Buffer[d->Msg.Length - 2] == 13) {
182  /* Process standard responses */
183  for (i = 0; StatusStrings[i] != NULL; i++) {
184  if (strncmp(StatusStrings[i],
185  d->Msg.Buffer + d->LineStart,
186  strlen(StatusStrings[i])) == 0) {
187  s->Phone.Data.RequestMsg = &d->Msg;
189  d->Msg.Length = 0;
190  break;
191  }
192  }
193  /* Generally hack for A2D */
194  if (d->CPINNoOK) {
195  if (strncmp("+CPIN: ",
196  d->Msg.Buffer + d->LineStart,
197  7) == 0) {
198  s->Phone.Data.RequestMsg = &d->Msg;
200  d->Msg.Length = 0;
201  break;
202  }
203  }
204 
205  /* Check for incoming frames */
206  for (i = 0; SpecialAnswers[i].text != NULL; i++) {
207  if (strncmp(SpecialAnswers[i].text,
208  d->Msg.Buffer + d->LineStart,
209  strlen(SpecialAnswers[i].text)) == 0) {
210  /* We need something better here */
211  if (s->Phone.Data.RequestID == SpecialAnswers[i].requestid) {
212  i++;
213  continue;
214  }
216  strcmp(SpecialAnswers[i].text, "NO CARRIER") == 0) {
217  i++;
218  continue;
219  }
221  d->SpecialAnswerLines = SpecialAnswers[i].lines;
222  }
223  }
224 
225  /* Last line of incoming frame */
226  if (d->SpecialAnswerLines == 1) {
227  /* This is end of special answer. We copy it and send to phone module */
228  Msg2.Buffer = (unsigned char *)malloc(d->LineEnd - d->SpecialAnswerStart + 3);
229  memcpy(Msg2. Buffer, d->Msg.Buffer + d->SpecialAnswerStart, d->LineEnd - d->SpecialAnswerStart + 2);
230  Msg2.Length = d->LineEnd - d->SpecialAnswerStart + 2;
231  Msg2.Buffer[Msg2.Length] = '\0';
232  Msg2.Type = 0;
233 
234  s->Phone.Data.RequestMsg = &Msg2;
236  free(Msg2.Buffer);
237  Msg2.Buffer = NULL;
238 
239  /* We cut special answer from main buffer */
240  d->Msg.Length = d->SpecialAnswerStart;
241  if (d->Msg.Length != 0) {
242  d->Msg.Length = d->Msg.Length - 2;
243  }
244 
245  /* We need to find earlier values of all variables */
246  d->wascrlf = FALSE;
247  d->LineStart = 0;
248  for (i = 0;i < d->Msg.Length; i++) {
249  switch (d->Msg.Buffer[i]) {
250  case 0:
251  break;
252  case 10:
253  case 13:
254  if (!d->wascrlf) {
255  d->LineEnd = d->Msg.Length - 1;
256  }
257  d->wascrlf = TRUE;
258  break;
259  default:
260  if (d->wascrlf) {
261  d->LineStart = d->Msg.Length - 1;
262  d->wascrlf = FALSE;
263  }
264  }
265  }
266  d->Msg.Buffer[d->Msg.Length] = 0;
267  }
268  if (d->SpecialAnswerLines > 0) {
269  d->SpecialAnswerLines--;
270  }
271  }
272  break;
273  case 'T':
274  /* When CONNECT string received, we know there will not follow
275  * anything AT related, after CONNECT can follow ppp data, alcabus
276  * data and also other things.
277  */
278  if (strncmp(d->Msg.Buffer + d->LineStart, "CONNECT", 7) == 0) {
279  s->Phone.Data.RequestMsg = &d->Msg;
281  d->LineStart = -1;
282  d->Msg.Length = 0;
283  break;
284  }
285  default:
286  if (d->wascrlf) {
287  d->LineStart = d->Msg.Length - 1;
288  d->wascrlf = FALSE;
289  }
290  if (d->EditMode) {
291  if (strlen(d->Msg.Buffer+d->LineStart) == 2 &&
292  strncmp(d->Msg. Buffer + d->LineStart, "> ", 2) == 0) {
293  s->Phone.Data.RequestMsg = &d->Msg;
295  }
296  }
297  }
298  return ERR_NONE;
299 }
300 
302 {
303  GSM_Protocol_ATData *d = &s->Protocol.Data.AT;
304  GSM_Error error;
305 
306  d->Msg.Buffer = NULL;
307  d->Msg.BufferUsed = 0;
308  d->Msg.Length = 0;
309  d->Msg.Type = 0;
310 
311  d->SpecialAnswerLines = 0;
312  d->LineStart = -1;
313  d->LineEnd = -1;
314  d->wascrlf = FALSE;
315  d->EditMode = FALSE;
316  /* Slow write makes sense only on cable for some phones */
317  d->FastWrite = (s->ConnectionType != GCT_AT);
318  d->CPINNoOK = FALSE;
319 
320  error = s->Device.Functions->DeviceSetParity(s, FALSE);
321  if (error != ERR_NONE) return error;
322 
323  error = s->Device.Functions->DeviceSetDtrRts(s, TRUE, TRUE);
324  if (error != ERR_NONE) return error;
325 
326  return s->Device.Functions->DeviceSetSpeed(s, s->Speed);
327 }
328 
329 static GSM_Error AT_Terminate(GSM_StateMachine *s)
330 {
331  free(s->Protocol.Data.AT.Msg.Buffer);
332  s->Protocol.Data.AT.Msg.Buffer = NULL;
333  return ERR_NONE;
334 }
335 
336 GSM_Protocol_Functions ATProtocol = {
337  AT_WriteMessage,
340  AT_Terminate
341 };
342 
343 #endif
344 
345 /* How should editor hadle tabs in this file? Add editor commands here.
346  * vim: noexpandtab sw=8 ts=8 sts=8:
347  */
void GSM_DumpMessageBinary(GSM_StateMachine *s, unsigned const char *message, size_t messagesize, int type)
Definition: gsmstate.c:1583
gboolean EditMode
Definition: at.h:17
GSM_Error(* DeviceSetDtrRts)(GSM_StateMachine *s, gboolean dtr, gboolean rts)
Definition: gsmstate.h:244
struct GSM_Protocol::@1 Data
GSM_Error(* DeviceSetParity)(GSM_StateMachine *s, gboolean parity)
Definition: gsmstate.h:240
GSM_ConnectionType ConnectionType
Definition: gsmstate.h:1402
gboolean FastWrite
Definition: at.h:18
GSM_Error
Definition: gammu-error.h:23
GSM_Error DispatchError
Definition: gsmstate.h:689
GSM_Error AT_StateMachine(GSM_StateMachine *s, unsigned char rx_char)
gboolean CPINNoOK
Definition: at.h:22
GSM_Protocol_Message Msg
Definition: at.h:12
int(* WriteDevice)(GSM_StateMachine *s, const void *buf, size_t nbytes)
Definition: gsmstate.h:256
GSM_Error AT_Initialise(GSM_StateMachine *s)
size_t LineStart
Definition: at.h:14
size_t LineEnd
Definition: at.h:14
gboolean wascrlf
Definition: at.h:13
GSM_Phone Phone
Definition: gsmstate.h:1431
#define FALSE
Definition: gammu-types.h:25
GSM_Phone_RequestID RequestID
Definition: gsmstate.h:685
GSM_Device_Functions * Functions
Definition: gsmstate.h:335
GSM_Protocol Protocol
Definition: gsmstate.h:1430
size_t SpecialAnswerStart
Definition: at.h:15
GSM_Phone_Data Data
Definition: gsmstate.h:1369
GSM_Phone_Functions * Functions
Definition: gsmstate.h:1373
GSM_Error(* DispatchMessage)(GSM_StateMachine *s)
Definition: gsmstate.h:765
#define TRUE
Definition: gammu-types.h:28
unsigned char * Buffer
Definition: protocol.h:22
size_t SpecialAnswerLines
Definition: at.h:15
GSM_Phone_RequestID
Definition: gsmreply.h:25
GSM_Protocol_Message * RequestMsg
Definition: gsmstate.h:676
GSM_Error(* DeviceSetSpeed)(GSM_StateMachine *s, int speed)
Definition: gsmstate.h:248
void GSM_DumpMessageText(GSM_StateMachine *s, unsigned const char *message, size_t messagesize, int type)
Definition: gsmstate.c:1555
GSM_Device Device
Definition: gsmstate.h:1429