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