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