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