Update: orig2001_11_27_05_17 -> orig2001_11_27_22_58
[gnokii.git] / common / links / fbus-3110.c
1 /*
2
3   $Id$
4
5   G N O K I I
6
7   A Linux/Unix toolset and driver for Nokia mobile phones.
8
9   Copyright (C) 2000 Hugh Blemings & Pavel Janík ml.
10
11   Released under the terms of the GNU GPL, see file COPYING for more details.
12
13   This file provides an API for accessing functions via fbus. 
14   See README for more details on supported mobile phones.
15
16   The various routines are called FBUS_(whatever).
17
18   $Log$
19   Revision 1.1.1.1.2.1  2001/11/27 22:48:37  short
20   Update: orig2001_11_27_05_17 -> orig2001_11_27_22_58
21
22   Revision 1.1.1.2  2001/11/27 22:01:16  short
23   :pserver:cvs@pserver.samba.org:/cvsroot - gnokii - Tue Nov 27 22:58 CET 2001
24
25   Revision 1.3  2001/11/27 12:19:01  pkot
26   Cleanup, indentation, ANSI complaint preprocesor symbols (Jan Kratochvil, me)
27
28   Revision 1.2  2001/11/09 14:25:04  pkot
29   DEBUG cleanups
30
31   Revision 1.1  2001/11/09 12:55:07  pkot
32   Forgot about fbus support for 3110. FIXME: is it really needed?
33
34
35 */
36
37 /* System header files */
38
39 #include <stdio.h>
40 #include <string.h>
41 #include <stdlib.h>
42
43 /* Various header file */
44
45 #include "config.h"
46 #include "misc.h"
47 #include "gsm-common.h"
48 #include "gsm-ringtones.h"
49 #include "gsm-networks.h"
50 #include "gsm-statemachine.h"
51 #include "links/utils.h"
52
53 #ifndef WIN32
54 #  include "device.h"
55 #else
56 #  include "win32/winserial.h"
57 #  define device_write(a, b) WriteCommBlock(a, b)
58 #  define device_read(a, b) ReadCommBlock(a, b)
59 #  define sleep(x) Sleep((x) * 1000)
60 #  define usleep(x) Sleep(((x) < 1000) ? 1 : ((x) / 1000))
61 #endif
62
63 #define __links_fbus_3110_c
64 #include "links/fbus-3110.h"
65
66 /* FIXME - pass device_* the link stuff?? */
67 /* FIXME - win32 stuff! */
68
69
70 /* Some globals */
71
72 static GSM_Link *glink;
73 static GSM_Statemachine *statemachine;
74 static FB3110_Link flink;               /* FBUS specific stuff, internal to this file */
75
76
77 /*--------------------------------------------*/
78
79 bool FB3110_OpenSerial(void)
80 {
81         /* Open device. */
82 #ifdef WIN32
83         if (OpenConnection(glink->PortDevice, FB3110_RX_StateMachine, NULL)) {
84 #else
85         if (!device_open(glink->PortDevice, false, false, false, GCT_Serial)) {
86 #endif
87                 perror(_("Couldn't open FBUS device"));
88                 return false;
89         }
90         device_changespeed(115200);
91
92         return (true);
93 }
94
95
96 /* RX_State machine for receive handling.  Called once for each character
97    received from the phone. */
98
99 void FB3110_RX_StateMachine(unsigned char rx_byte)
100 {
101         FB3110_IncomingFrame *i = &flink.i;
102         int count;
103
104         switch (i->State) {
105
106                 /* Phone is currently off.  Wait for 0x55 before
107                    restarting */
108         case FB3110_RX_Discarding:
109                 if (rx_byte != 0x55)
110                         break;
111
112                 /* Seen 0x55, restart at 0x04 */
113                 i->State = FB3110_RX_Sync;
114
115                 dprintf("restarting.\n");
116
117                 /* FALLTHROUGH */
118
119                 /* Messages from the phone start with an 0x04 during
120                    "normal" operation, 0x03 when in data/fax mode.  We
121                    use this to "synchronise" with the incoming data
122                    stream. */
123         case FB3110_RX_Sync:
124                 if (rx_byte == 0x04 || rx_byte == 0x03) {
125                         i->FrameType = rx_byte;
126                         i->Checksum = rx_byte;
127                         i->State = FB3110_RX_GetLength;
128                 }
129                 break;
130
131                 /* Next byte is the length of the message including
132                    the message type byte but not including the checksum. */
133         case FB3110_RX_GetLength:
134                 i->FrameLength = rx_byte;
135                 i->BufferCount = 0;
136                 i->Checksum ^= rx_byte;
137                 i->State = FB3110_RX_GetMessage;
138                 break;
139
140                 /* Get each byte of the message.  We deliberately
141                    get one too many bytes so we get the checksum
142                    here as well. */
143         case FB3110_RX_GetMessage:
144                 i->Buffer[i->BufferCount] = rx_byte;
145                 i->BufferCount++;
146
147                 if (i->BufferCount > FB3110_MAX_FRAME_LENGTH) {
148                         dprintf("FBUS: Message buffer overun - resetting\n");
149                         i->State = FB3110_RX_Sync;
150                         break;
151                 }
152
153                 /* If this is the last byte, it's the checksum. */
154                 if (i->BufferCount > i->FrameLength) {
155
156                         /* Is the checksum correct? */
157                         if (rx_byte == i->Checksum) {
158
159                                 if (i->FrameType == 0x03) {
160                                         /* FIXME: modify Buffer[0] to code FAX frame types */
161                                 }
162
163                                 dprintf("--> %02x:%02x:", i->FrameType, i->FrameLength);
164                                 for (count = 0; count < i->BufferCount; count++)
165                                         dprintf("%02hhx:", i->Buffer[count]);
166                                 dprintf("\n");
167                                 /* Transfer message to state machine */
168                                 SM_IncomingFunction(statemachine, i->Buffer[0], i->Buffer, i->FrameLength);
169
170                                 /* Send an ack */
171                                 FB3110_TX_SendAck(i->Buffer, i->FrameLength);
172
173                         } else {
174                                 /* Checksum didn't match so ignore. */
175                                 dprintf("Bad checksum!\n");
176                         }
177                         i->State = FB3110_RX_Sync;
178                 }
179                 i->Checksum ^= rx_byte;
180                 break;
181         }
182 }
183
184
185 /* This is the main loop function which must be called regularly */
186 /* timeout can be used to make it 'busy' or not */
187
188 GSM_Error FB3110_Loop(struct timeval *timeout)
189 {
190 #ifndef WIN32
191         unsigned char buffer[255];
192         int count, res;
193
194         res = device_select(timeout);
195         if (res > 0) {
196                 res = device_read(buffer, 255);
197                 for (count = 0; count < res; count++)
198                         FB3110_RX_StateMachine(buffer[count]);
199         } else
200                 return GE_TIMEOUT;
201
202         /* This traps errors from device_read */
203         if (res > 0)
204                 return GE_NONE;
205         else
206                 return GE_INTERNALERROR;
207 #else
208         return GE_NONE;
209 #endif
210 }
211
212
213
214 /* Prepares the message header and sends it, prepends the
215    message start byte (0x01) and other values according
216    the value specified when called.  Calculates checksum
217    and then sends the lot down the pipe... */
218
219 GSM_Error FB3110_TX_SendFrame(u8 message_length, u8 message_type, u8 sequence_byte, u8 * buffer)
220 {
221
222         u8 out_buffer[FB3110_MAX_TRANSMIT_LENGTH];
223         int count, current = 0;
224         unsigned char checksum;
225
226         /* Check message isn't too long, once the necessary
227            header and trailer bytes are included. */
228         if ((message_length + 5) > FB3110_MAX_TRANSMIT_LENGTH) {
229                 fprintf(stderr, _("FB3110_TX_SendFrame - message too long!\n"));
230                 return (GE_INTERNALERROR);
231         }
232
233         /* Now construct the message header. */
234         out_buffer[current++] = FB3110_FRAME_ID;    /* Start of frame */
235         out_buffer[current++] = message_length + 2; /* Length */
236         out_buffer[current++] = message_type;       /* Type */
237         out_buffer[current++] = sequence_byte;      /* Sequence number */
238
239         /* Copy in data if any. */
240         if (message_length != 0) {
241                 memcpy(out_buffer + current, buffer, message_length);
242                 current += message_length;
243         }
244
245         /* Now calculate checksum over entire message 
246            and append to message. */
247         checksum = 0;
248         for (count = 0; count < current; count++)
249                 checksum ^= out_buffer[count];
250         out_buffer[current++] = checksum;
251
252         dprintf("<-- ");
253         for (count = 0; count < current; count++)
254                 dprintf("%02hhx:", out_buffer[count]);
255         dprintf("\n");
256
257         /* Send it out... */
258         if (device_write(out_buffer, current) != current)
259                 return (GE_INTERNALERROR);
260
261         return (GE_NONE);
262 }
263
264
265 /* Main function to send an fbus message */
266
267 GSM_Error FB3110_SendMessage(u16 messagesize, u8 messagetype, void *message)
268 {
269         u8 seqnum;
270
271         FB3110_UpdateSequenceNumber();
272         seqnum = flink.RequestSequenceNumber;
273
274         return FB3110_TX_SendFrame(messagesize, messagetype, seqnum, message);
275 }
276
277
278 /* Sends the "standard" acknowledge message back to the phone in
279    response to a message it sent automatically or in response to
280    a command sent to it.  The ack. algorithm isn't 100% understood
281    at this time. */
282
283 void FB3110_TX_SendAck(u8 *message, int length)
284 {
285         u8 t = message[0];
286
287         switch (t) {
288         case 0x0a:
289                 /* We send 0x0a messages to make a call so don't ack. */
290         case 0x0c:
291                 /* We send 0x0c message to answer to incoming call 
292                    so don't ack */
293         case 0x0f:
294                 /* We send 0x0f message to hang up so don't ack */
295         case 0x15:
296                 /* 0x15 messages are sent by the phone in response to the
297                    init sequence sent so we don't acknowledge them! */
298         case 0x20:
299                 /* We send 0x20 message to phone to send DTFM, so don't ack */
300         case 0x23:
301                 /* We send 0x23 messages to phone as a header for outgoing SMS
302                    messages.  So we don't acknowledge it. */
303         case 0x24:
304                 /* We send 0x24 messages to phone as a header for storing SMS
305                    messages in memory. So we don't acknowledge it. :) */
306         case 0x25:
307                 /* We send 0x25 messages to phone to request an SMS message
308                    be dumped.  Thus we don't acknowledge it. */
309         case 0x26:
310                 /* We send 0x26 messages to phone to delete an SMS message
311                    so it's not acknowledged. */
312         case 0x3f:
313                 /* We send an 0x3f message to the phone to request a different
314                    type of status dump - this one seemingly concerned with 
315                    SMS message center details.  Phone responds with an ack to
316                    our 0x3f request then sends an 0x41 message that has the
317                    actual data in it. */
318         case 0x4a:
319                 /* 0x4a message is a response to our 0x4a request, assumed to
320                    be a keepalive message of sorts.  No response required. */
321         case 0x4c:
322                 /* We send 0x4c to request IMEI, Revision and Model info. */
323                 break;
324         case 0x27:
325                 /* 0x27 messages are a little different in that both ends of
326                    the link send them.  So, first we have to check if this
327                    is an acknowledgement or a message to be acknowledged */
328                 if (length == 0x02) break;
329         default:
330                 /* Standard acknowledge seems to be to return an empty message
331                    with the sequence number set to equal the sequence number
332                    sent minus 0x08. */
333                 if (FB3110_TX_SendFrame(0, t, (message[1] & 0x1f) - 0x08, NULL) != GE_NONE)
334                         dprintf("Failed to acknowledge message type %02x.\n", t);
335                 else
336                         dprintf("Acknowledged message type %02x.\n", t);
337         }
338 }
339
340
341 /* Initialise variables and start the link */
342 /* newlink is actually part of state - but the link code should not anything about state */
343 /* state is only passed around to allow for muliple state machines (one day...) */
344
345 GSM_Error FB3110_Initialise(GSM_Link *newlink, GSM_Statemachine *state)
346 {
347         unsigned char init_char = 0x55;
348         unsigned char count;
349         static int try = 0;
350
351         try++;
352         if (try > 2) return GE_DEVICEOPENFAILED;
353         /* 'Copy in' the global structures */
354         glink = newlink;
355         statemachine = state;
356
357         /* Fill in the link functions */
358         glink->Loop = &FB3110_Loop;
359         glink->SendMessage = &FB3110_SendMessage;
360
361         /* Check for a valid init length */
362         if (glink->InitLength == 0)
363                 glink->InitLength = 100;
364
365         /* Start up the link */
366
367         flink.RequestSequenceNumber = 0x10;
368
369         if (!FB3110_OpenSerial()) return GE_DEVICEOPENFAILED;
370
371         /* Send init string to phone, this is a bunch of 0x55 characters. 
372            Timing is empirical. I believe that we need/can do this for any 
373            phone to get the UART synced */
374         for (count = 0; count < glink->InitLength; count++) {
375                 usleep(1000);
376                 device_write(&init_char, 1);
377         }
378
379         /* Init variables */
380         flink.i.State = FB3110_RX_Sync;
381
382         return GE_NONE;
383 }
384
385
386 /* Any command we originate must have a unique SequenceNumber.
387    Observation to date suggests that these values startx at 0x10
388    and cycle up to 0x17 before repeating again.  Perhaps more
389    accurately, the numbers cycle 0,1,2,3..7 with bit 4 of the byte
390    premanently set. */
391
392 void FB3110_UpdateSequenceNumber(void)
393 {
394     flink.RequestSequenceNumber++;
395
396     if (flink.RequestSequenceNumber > 0x17 || flink.RequestSequenceNumber < 0x10) {
397         flink.RequestSequenceNumber = 0x10;
398     }
399 }