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