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