Imported gammu 0.90.7
[gammu.git] / common / protocol / at / at.c
blob734eb82e34a2036a1d884348ee524fdef8d46a25
2 #include "../../gsmstate.h"
4 #if defined(GSM_ENABLE_AT) || defined(GSM_ENABLE_BLUEAT) || defined(GSM_ENABLE_IRDAAT)
6 #include <stdio.h>
7 #include <string.h>
9 #include "../../gsmcomon.h"
10 #include "at.h"
12 static GSM_Error AT_WriteMessage (GSM_StateMachine *s, unsigned char *buffer,
13 int length, unsigned char type)
15 int i,sent = 0;
17 GSM_DumpMessageLevel2(s, buffer, length, type);
18 GSM_DumpMessageLevel3(s, buffer, length, type);
19 if (s->Protocol.Data.AT.FastWrite) {
20 while (sent != length) {
21 if ((i = s->Device.Functions->WriteDevice(s,buffer + sent, length - sent)) == 0) {
22 return GE_DEVICEWRITEERROR;
24 sent += i;
26 } else {
27 for (i=0;i<length;i++) {
28 if (s->Device.Functions->WriteDevice(s,buffer+i,1)!=1) return GE_DEVICEWRITEERROR;
29 /* For some phones like Siemens M20 we need to wait a little
30 * after writing each char. Possible reason: these phones
31 * can't receive so fast chars or there is bug here in Gammu */
32 my_sleep(1);
34 my_sleep(400);
37 return GE_NONE;
40 typedef struct {
41 char *text;
42 int lines;
43 } SpecialAnswersStruct;
45 static GSM_Error AT_StateMachine(GSM_StateMachine *s, unsigned char rx_byte)
47 GSM_Protocol_Message Msg2;
48 GSM_Protocol_ATData *d = &s->Protocol.Data.AT;
49 int i;
51 /* These are lines with end of "normal" answers */
52 static char *StartStrings[] = {
53 "OK" , "ERROR" ,
54 "+CME ERROR:" , "+CMS ERROR:" ,
56 "+CPIN: " , /*A2D issue*/
58 NULL};
60 /* Some info from phone can be inside "normal" answers
61 * It starts with strings written here
63 static SpecialAnswersStruct SpecialAnswers[] = {
64 {"_OSIGQ:" ,1}, {"_OBS:" ,1},
65 {"^SCN:" ,1}, {"+CGREG:" ,1},
66 {"+CBM:" ,1}, {"+CMT:" ,2},
67 {"+CMTI:" ,1}, {"+CDS:" ,2},
69 {"RING" ,1}, {"NO CARRIER" ,1},
70 {"NO ANSWER" ,1}, {"+COLP" ,1},
71 {"+CLIP" ,1},
73 {NULL ,1}};
75 /* Ignore leading CR, LF and ESC */
76 if (d->Msg.Length == 0) {
77 if (rx_byte == 10 || rx_byte == 13 || rx_byte == 27) return GE_NONE;
78 d->LineStart = d->Msg.Length;
81 if (d->Msg.BufferUsed < d->Msg.Length + 2) {
82 d->Msg.BufferUsed = d->Msg.Length + 2;
83 d->Msg.Buffer = (unsigned char *)realloc(d->Msg.Buffer,d->Msg.BufferUsed);
85 d->Msg.Buffer[d->Msg.Length++] = rx_byte;
86 d->Msg.Buffer[d->Msg.Length ] = 0;
88 switch (rx_byte) {
89 case 0:
90 break;
91 case 10:
92 case 13:
93 if (!d->wascrlf) d->LineEnd = d->Msg.Length-1;
94 d->wascrlf = true;
95 if (d->Msg.Length > 0 && rx_byte == 10 && d->Msg.Buffer[d->Msg.Length-2]==13) {
96 i = 0;
97 while (StartStrings[i] != NULL) {
98 if (strlen(StartStrings[i])==0) break;
99 if (strncmp(StartStrings[i],d->Msg.Buffer+d->LineStart,strlen(StartStrings[i])) == 0) {
100 s->Phone.Data.RequestMsg = &d->Msg;
101 s->Phone.Data.DispatchError = s->Phone.Functions->DispatchMessage(s);
102 d->Msg.Length = 0;
103 break;
105 i++;
107 if (d->Msg.Length == 0) break;
109 i = 0;
110 while (SpecialAnswers[i].text != NULL) {
111 if (strlen(SpecialAnswers[i].text)==0) break;
112 if (strncmp(SpecialAnswers[i].text,d->Msg.Buffer+d->LineStart,strlen(SpecialAnswers[i].text)) == 0) {
113 d->SpecialAnswerStart = d->LineStart;
114 d->SpecialAnswerLines = SpecialAnswers[i].lines;
116 i++;
119 if (d->SpecialAnswerLines == 1) {
120 /* This is end of special answer. We copy it and send to phone module */
121 Msg2.Buffer = malloc(d->LineEnd - d->SpecialAnswerStart + 3);
122 memcpy(Msg2.Buffer,d->Msg.Buffer+d->SpecialAnswerStart,d->LineEnd - d->SpecialAnswerStart + 2);
123 Msg2.Length = d->LineEnd - d->SpecialAnswerStart + 2;
124 Msg2.Buffer[Msg2.Length] = 0;
126 s->Phone.Data.RequestMsg = &Msg2;
127 s->Phone.Data.DispatchError = s->Phone.Functions->DispatchMessage(s);
128 free(Msg2.Buffer);
130 /* We cut special answer from main buffer */
131 d->Msg.Length = d->SpecialAnswerStart;
132 if (d->Msg.Length != 0) d->Msg.Length = d->Msg.Length - 2;
134 /* We need to find earlier values of all variables */
135 d->wascrlf = false;
136 d->LineStart = 0;
137 for (i=0;i<d->Msg.Length;i++) {
138 switch(d->Msg.Buffer[i]) {
139 case 0:
140 break;
141 case 10:
142 case 13:
143 if (!d->wascrlf) d->LineEnd = d->Msg.Length-1;
144 d->wascrlf = true;
145 break;
146 default:
147 if (d->wascrlf) {
148 d->LineStart = d->Msg.Length-1;
149 d->wascrlf = false;
153 d->Msg.Buffer[d->Msg.Length] = 0;
155 if (d->SpecialAnswerLines > 0) d->SpecialAnswerLines--;
157 break;
158 case 'T':
159 /* When CONNECT string received, we know there will not follow
160 * anything AT related, after CONNECT can follow ppp data, alcabus
161 * data and also other things.
163 if (strncmp(d->Msg.Buffer+d->LineStart, "CONNECT", 7) == 0) {
164 s->Phone.Data.RequestMsg = &d->Msg;
165 s->Phone.Data.DispatchError = s->Phone.Functions->DispatchMessage(s);
166 d->LineStart = -1;
167 d->Msg.Length = 0;
168 break;
170 default:
171 if (d->wascrlf) {
172 d->LineStart = d->Msg.Length-1;
173 d->wascrlf = false;
175 if (d->EditMode) {
176 if (strlen(d->Msg.Buffer+d->LineStart) == 2 && strncmp(d->Msg.Buffer+d->LineStart,"> ",2)==0) {
177 s->Phone.Data.RequestMsg = &d->Msg;
178 s->Phone.Data.DispatchError = s->Phone.Functions->DispatchMessage(s);
182 return GE_NONE;
185 static GSM_Error AT_Initialise(GSM_StateMachine *s)
187 GSM_Protocol_ATData *d = &s->Protocol.Data.AT;
189 d->Msg.Buffer = NULL;
190 d->Msg.BufferUsed = 0;
191 d->Msg.Length = 0;
192 d->Msg.Type = 0;
194 d->SpecialAnswerLines = 0;
195 d->LineStart = -1;
196 d->LineEnd = -1;
197 d->wascrlf = false;
198 d->EditMode = false;
199 d->FastWrite = false;
201 s->Device.Functions->DeviceSetDtrRts(s,true,true);
203 return s->Device.Functions->DeviceSetSpeed(s,s->Speed);
206 static GSM_Error AT_Terminate(GSM_StateMachine *s)
208 free(s->Protocol.Data.AT.Msg.Buffer);
209 return GE_NONE;
212 GSM_Protocol_Functions ATProtocol = {
213 AT_WriteMessage,
214 AT_StateMachine,
215 AT_Initialise,
216 AT_Terminate
219 #endif
221 /* How should editor hadle tabs in this file? Add editor commands here.
222 * vim: noexpandtab sw=8 ts=8 sts=8: