1 /* (c) 2002-2003 by Michal Cihar
2 *
3 * Low level functions for communication with Alcatel One Touch phones.
4 *
5 * This code implements the protocol used for synchronisation with PC.
6 */
7 #include "../../gsmstate.h"
8
9 #if defined(GSM_ENABLE_ALCABUS)
10
11 #include <stdio.h>
12 #include <string.h>
13 #include <stdlib.h>
14
15 #include "../../gsmcomon.h"
16 #include "alcabus.h"
17
ALCABUS_WriteMessage(GSM_StateMachine * s,unsigned const char * data,size_t len,int type)18 static GSM_Error ALCABUS_WriteMessage (GSM_StateMachine *s, unsigned const char *data, size_t len, int type)
19 {
20 GSM_Protocol_ALCABUSData *d = &s->Protocol.Data.ALCABUS;
21 unsigned char buffer[1024];
22 int size = 0;
23 int sent = 0;
24 int i = 0, checksum = 0;
25
26 if ((type == 0) && (len == 0)) return ERR_NONE;
27
28 buffer[0] = ALCATEL_HEADER;
29 buffer[1] = type;
30 switch (type) {
31 case ALCATEL_CONNECT:
32 buffer[2] = 0x0A;
33 buffer[3] = 0x04;
34 buffer[4] = 0x00;
35 size = 5;
36 d->next_frame = ALCATEL_CONNECT_ACK;
37 d->busy = TRUE;
38 break;
39 case ALCATEL_DISCONNECT:
40 size = 2;
41 d->next_frame = ALCATEL_DISCONNECT_ACK;
42 d->busy = TRUE;
43 break;
44 case ALCATEL_DATA:
45 buffer[2] = d->out_counter;
46
47 /* Increase outgoing packet counter */
48 if (d->out_counter == ALCATEL_MAX_COUNTER) d->out_counter = 0;
49 else d->out_counter++;
50
51 buffer[3] = '\0';
52 buffer[4] = len;
53 memcpy(buffer+5, data, len);
54 size = 5 + len;
55 d->next_frame = ALCATEL_ACK;
56 d->busy = TRUE;
57 break;
58 case ALCATEL_ACK:
59 buffer[2] = d->in_counter;
60 if (d->in_counter == 0) d->in_counter = 1;
61 size = 3;
62 d->next_frame = ALCATEL_DATA;
63 break;
64 default:
65 /* In fact, other types probably can came just from mobile... */
66 smprintf(s,"WARNING: Wanted to send some unknown packet (%02X)\n", type);
67 return ERR_NOTIMPLEMENTED;
68 }
69
70 /* Calculate packet checksum */
71 for (i=0; i<size; i++) checksum ^= buffer[i];
72
73 buffer[size] = checksum;
74 size ++;
75
76 GSM_DumpMessageText(s, buffer, size, type);
77 GSM_DumpMessageBinary(s, buffer, size, type);
78
79 while (sent != size ) {
80 i = s->Device.Functions->WriteDevice(s,buffer + sent, size - sent);
81
82 if (!i) {
83 return ERR_DEVICEWRITEERROR;
84 }
85 sent += i;
86 }
87
88 if (type == ALCATEL_CONNECT || type == ALCATEL_DISCONNECT) {
89 /* For connect and disconnect we need a bit larger delay */
90 while (d->busy) {
91 GSM_ReadDevice(s,TRUE);
92 usleep(1000);
93
94 if (++i == 10) {
95 return ERR_TIMEOUT;
96 }
97 }
98 }
99 return ERR_NONE;
100 }
101
ALCABUS_StateMachine(GSM_StateMachine * s,unsigned char rx_char)102 static GSM_Error ALCABUS_StateMachine(GSM_StateMachine *s, unsigned char rx_char)
103 {
104 GSM_Protocol_ALCABUSData *d = &s->Protocol.Data.ALCABUS;
105 size_t i;
106 int checksum = 0;
107
108 if (d->Msg.BufferUsed < d->Msg.Length + 1) {
109 d->Msg.BufferUsed = d->Msg.Length + 1;
110 d->Msg.Buffer = (unsigned char *)realloc(d->Msg.Buffer,d->Msg.BufferUsed);
111 }
112
113 /* Check for header */
114 if ((d->Msg.Length == 0) && (rx_char != ALCATEL_HEADER)) {
115 smprintf(s,"WARNING: Expecting alcatel header (%02X) but got (%02X)\n", ALCATEL_HEADER, rx_char);
116 return ERR_UNKNOWNRESPONSE;
117 /* Check for packet type */
118 } else if (d->Msg.Length == 1){
119 d->Msg.Type = rx_char;
120 /* Was it unexpected packet? */
121 if ((rx_char != d->next_frame) && (rx_char != ALCATEL_CONTROL)) {
122 smprintf(s,"WARNING: Expecting alcatel packet type (%02X) but got (%02X)\n", d->next_frame, rx_char);
123 }
124 /* Determine packet size */
125 switch (rx_char) {
126 case ALCATEL_ACK:
127 d->expected_size = 4;
128 break;
129 case ALCATEL_DATA:
130 /* Packet length is in it's header */
131 d->expected_size = -1;
132 break;
133 case ALCATEL_CONTROL:
134 d->expected_size = 4;
135 break;
136 case ALCATEL_CONNECT_ACK:
137 d->expected_size = 6;
138 break;
139 case ALCATEL_DISCONNECT_ACK:
140 d->expected_size = 3;
141 break;
142 default:
143 smprintf(s,"WARNING: Something went wrong, unknown packet received (%02X)\n", rx_char);
144 return ERR_UNKNOWNRESPONSE;
145 }
146 /* Check counter, we can probably ignore error here ;-) */
147 } else if ((d->Msg.Length == 2) && (d->Msg.Type == ALCATEL_DATA)) {
148 if (rx_char != d->in_counter) {
149 smprintf(s,"WARNING: Unexpected packet number, ignoring (expected %02X, received %02X)\n", d->in_counter, rx_char);
150 d->in_counter = rx_char;
151 }
152 /* Increase incoming packet counter */
153 if (d->in_counter == ALCATEL_MAX_COUNTER) d->in_counter = 0;
154 else d->in_counter++;
155 /* Read size for data packet */
156 } else if ((d->Msg.Length == 4) && (d->Msg.Type == ALCATEL_DATA)) {
157 /* Header till now + checksum */
158 d->expected_size = (int)rx_char + 6;
159 }
160
161 /* Write received byte into buffer */
162 d->Msg.Buffer[d->Msg.Length++] = rx_char;
163
164 /* Did we received whole packet? */
165 if (d->expected_size == d->Msg.Length) {
166 /* Check checksum */
167 for (i=0; i< (d->Msg.Length - 1); i++) checksum ^= d->Msg.Buffer[i];
168 if (checksum != d->Msg.Buffer[d->Msg.Length - 1]) {
169 /* We can only warn, as we don't know what should happend now... */
170 smprintf(s,"WARNING: Ignoring incorrect packet checksum!\n");
171 }
172
173 /* Was it data? */
174 if (d->Msg.Type == ALCATEL_DATA) {
175 /* Dispatch message */
176 s->Phone.Data.RequestMsg = &d->Msg;
177 s->Phone.Data.DispatchError = s->Phone.Functions->DispatchMessage(s);
178 /* Send ack */
179 ALCABUS_WriteMessage (s, 0, 0, ALCATEL_ACK);
180 /* Reset message length */
181 d->Msg.Length = 0;
182 /* Was it ack? */
183 } else if ((d->Msg.Type == ALCATEL_ACK) ||
184 (d->Msg.Type == ALCATEL_CONTROL) ||
185 (d->Msg.Type == ALCATEL_CONNECT_ACK) ||
186 (d->Msg.Type == ALCATEL_DISCONNECT_ACK)) {
187 /* TODO: check counter of ack? */
188 if (s->di.dl==DL_TEXT || s->di.dl==DL_TEXTALL ||
189 s->di.dl==DL_TEXTDATE || s->di.dl==DL_TEXTALLDATE) {
190 smprintf(s, "Received %s ack ",
191 (d->Msg.Type == ALCATEL_ACK) ? "normal" :
192 (d->Msg.Type == ALCATEL_CONTROL) ? "control" :
193 (d->Msg.Type == ALCATEL_CONNECT_ACK) ? "connect" :
194 (d->Msg.Type == ALCATEL_DISCONNECT_ACK) ? "disconnect" :
195 "BUG");
196 smprintf(s, "0x%02x / 0x%04lX", d->Msg.Type, (long)d->Msg.Length);
197 DumpMessage(&s->di, d->Msg.Buffer, d->Msg.Length);
198 }
199 if (s->di.dl==DL_BINARY) {
200 smprintf(s,"%c",0x02); /* Receiving */
201 smprintf(s,"%c",d->Msg.Type);
202 smprintf(s,"%c",(int)d->Msg.Length/256);
203 smprintf(s,"%c",(int)d->Msg.Length%256);
204 for (i=0;i<d->Msg.Length;i++) smprintf(s,"%c",d->Msg.Buffer[i]);
205 }
206 if (d->Msg.Type != ALCATEL_CONTROL) {
207 d->next_frame = ALCATEL_DATA;
208 d->busy = FALSE;
209 }
210 /* Reset message length */
211 d->Msg.Length = 0;
212 }
213
214 /* Was it unexpected type? */
215 if ((d->Msg.Type != d->next_frame) && (d->Msg.Type != ALCATEL_CONTROL)) {
216 return ERR_FRAMENOTREQUESTED;
217 }
218 } /* Last byte of packet */
219
220 return ERR_NONE;
221 }
222
ALCABUS_Initialise(GSM_StateMachine * s)223 static GSM_Error ALCABUS_Initialise(GSM_StateMachine *s)
224 {
225 GSM_Protocol_ALCABUSData *d = &s->Protocol.Data.ALCABUS;
226
227 /* Initialise some variables */
228 d->Msg.BufferUsed = 0;
229 d->Msg.Buffer = NULL;
230 d->Msg.Length = 0;
231 d->Msg.Type = 0;
232 d->in_counter = 1;
233 d->out_counter = 0;
234 d->busy = FALSE;
235
236 /* Initialise protocol */
237 smprintf(s, "Initializing binary mode\n");
238 return ALCABUS_WriteMessage (s, 0, 0, ALCATEL_CONNECT);
239 }
240
ALCABUS_Terminate(GSM_StateMachine * s)241 static GSM_Error ALCABUS_Terminate(GSM_StateMachine *s)
242 {
243 /* Terminate protocol */
244 smprintf(s, "Closing binary mode\n");
245 return ALCABUS_WriteMessage (s, 0, 0, ALCATEL_DISCONNECT);
246 }
247
248 GSM_Protocol_Functions ALCABUSProtocol = {
249 ALCABUS_WriteMessage,
250 ALCABUS_StateMachine,
251 ALCABUS_Initialise,
252 ALCABUS_Terminate
253 };
254
255 #endif
256
257 /* How should editor hadle tabs in this file? Add editor commands here.
258 * vim: noexpandtab sw=8 ts=8 sts=8:
259 */
260