\r\n -> \n
[gnokii.git] / common / links / fbus.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   Copyright (C) 2000 Chris Kemp
11
12   Released under the terms of the GNU GPL, see file COPYING for more details.
13
14   This file provides an API for accessing functions via fbus. 
15   See README for more details on supported mobile phones.
16
17   The various routines are called FBUS_(whatever).
18
19   $Log$
20   Revision 1.1.1.2  2001/11/27 22:01:16  short
21   :pserver:cvs@pserver.samba.org:/cvsroot - gnokii - Tue Nov 27 22:58 CET 2001
22
23   Revision 1.14  2001/11/27 12:19:01  pkot
24   Cleanup, indentation, ANSI complaint preprocesor symbols (Jan Kratochvil, me)
25
26   Revision 1.13  2001/11/17 20:14:15  pkot
27   Nasty bug with counting message length. Workaround applied. Needs fixing.
28
29   Revision 1.12  2001/11/15 12:04:05  pkot
30   Faster initialization for 6100 series (don't check for dlr3 cable)
31
32   Revision 1.11  2001/09/09 21:45:49  machek
33   Cleanups from Ladislav Michl <ladis@psi.cz>:
34
35   *) do *not* internationalize debug messages
36
37   *) some whitespace fixes, do not use //
38
39   *) break is unneccessary after return
40
41   Revision 1.10  2001/08/20 23:27:37  pkot
42   Add hardware shakehand to the link layer (Manfred Jonsson)
43
44   Revision 1.9  2001/05/28 09:25:16  pkot
45   Fixed autodetecting of the cable type in 6110 and 7110 series. DLR-3 is
46   tried first now. Seems to work ok with either 6130 or 6210.
47
48   Revision 1.8  2001/05/07 16:24:03  pkot
49   DLR-3P temporary fix. How should I do it better?
50
51   Revision 1.7  2001/03/22 16:17:05  chris
52   Tidy-ups and fixed gnokii/Makefile and gnokii/ChangeLog which I somehow corrupted.
53
54   Revision 1.6  2001/03/21 23:36:05  chris
55   Added the statemachine
56   This will break gnokii --identify and --monitor except for 6210/7110
57
58   Revision 1.5  2001/03/19 23:44:56  pkot
59   DLR3 cable support
60
61   Revision 1.4  2001/03/13 01:24:02  pkot
62   Code cleanup - no warnings during compilation
63
64   Revision 1.3  2001/03/13 01:23:18  pkot
65   Windows updates (Manfred Jonsson)
66
67   Revision 1.2  2001/03/11 11:18:39  machek
68   Made fbus link_dispatch (and fixed minor memory leak)
69
70   Revision 1.1  2001/02/21 19:57:06  chris
71   More fiddling with the directory layout
72
73   Revision 1.1  2001/02/16 14:29:52  chris
74   Restructure of common/.  Fixed a problem in fbus-phonet.c
75   Lots of dprintfs for Marcin
76   Any size xpm can now be loaded (eg for 7110 startup logos)
77   nk7110 code detects 7110/6210 and alters startup logo size to suit
78   Moved Marcin's extended phonebook code into gnokii.c
79
80   Revision 1.3  2001/02/06 21:15:34  chris
81   Preliminary irda support for 7110 etc.  Not well tested!
82
83   Revision 1.2  2001/02/03 23:56:14  chris
84   Start of work on irda support (now we just need fbus-irda.c!)
85   Proper unicode support in 7110 code (from pkot)
86
87   Revision 1.1  2001/01/14 22:46:59  chris
88   Preliminary 7110 support (dlr9 only) and the beginnings of a new structure
89
90
91 */
92
93 /* System header files */
94
95 #include <stdio.h>
96 #include <string.h>
97 #include <stdlib.h>
98
99 /* Various header file */
100
101 #include "config.h"
102 #include "misc.h"
103 #include "gsm-common.h"
104 #include "gsm-ringtones.h"
105 #include "gsm-networks.h"
106 #include "gsm-statemachine.h"
107 #include "links/utils.h"
108
109 #ifndef WIN32
110 #  include "device.h"
111 #else
112 #  include "win32/winserial.h"
113 #  define device_write(a, b) WriteCommBlock(a, b)
114 #  define device_read(a, b) ReadCommBlock(a, b)
115 #  define sleep(x) Sleep((x) * 1000)
116 #  define usleep(x) Sleep(((x) < 1000) ? 1 : ((x) / 1000))
117 #endif
118
119 #define __links_fbus_c
120 #include "links/fbus.h"
121
122 /* FIXME - pass device_* the link stuff?? */
123 /* FIXME - win32 stuff! */
124
125
126 /* Some globals */
127
128 static GSM_Link *glink;
129 static GSM_Statemachine *statemachine;
130 static FBUS_Link flink;         /* FBUS specific stuff, internal to this file */
131
132
133 /*--------------------------------------------*/
134
135 bool FBUS_OpenSerial(bool dlr3)
136 {
137         if (dlr3) dlr3 = 1;
138         /* Open device. */
139 #ifdef WIN32
140         if (OpenConnection(glink->PortDevice, FBUS_RX_StateMachine, NULL)) {
141 #else
142         if (!device_open(glink->PortDevice, false, false, false, GCT_Serial)) {
143 #endif
144                 perror(_("Couldn't open FBUS device"));
145                 return false;
146         }
147         device_changespeed(115200);
148
149         /* clearing the RTS bit and setting the DTR bit */
150         device_setdtrrts((1-dlr3), 0);
151
152         return (true);
153 }
154
155
156 /* RX_State machine for receive handling.  Called once for each character
157    received from the phone. */
158
159 void FBUS_RX_StateMachine(unsigned char rx_byte)
160 {
161
162         struct timeval time_diff;
163         FBUS_IncomingFrame *i = &flink.i;
164         int frm_num, seq_num;
165         FBUS_IncomingMessage *m;
166
167 #if 0
168         if (isprint(rx_byte))
169                 dprintf("[%02x%c]", (unsigned char) rx_byte, rx_byte);
170         else
171                 dprintf("[%02x ]", (unsigned char) rx_byte);
172 #endif
173
174         /* XOR the byte with the current checksum */
175         i->checksum[i->BufferCount & 1] ^= rx_byte;
176
177         switch (i->state) {
178
179                 /* Messages from the phone start with an 0x1e (cable) or 0x1c (IR).
180                    We use this to "synchronise" with the incoming data stream. However,
181                    if we see something else, we assume we have lost sync and we require
182                    a gap of at least 5ms before we start looking again. This is because
183                    the data part of the frame could contain a byte which looks like the
184                    sync byte */
185
186         case FBUS_RX_Discarding:
187                 gettimeofday(&i->time_now, NULL);
188                 timersub(&i->time_now, &i->time_last, &time_diff);
189                 if (time_diff.tv_sec == 0 && time_diff.tv_usec < 5000) {
190                         i->time_last = i->time_now;     /* no gap seen, continue discarding */
191                         break;
192                 }
193
194                 /* else fall through to... */
195
196         case FBUS_RX_Sync:
197                 if (glink->ConnectionType == GCT_Infrared) {
198                         if (rx_byte == FBUS_IR_FRAME_ID) {
199                                 /* Initialize checksums. */
200                                 i->checksum[0] = FBUS_IR_FRAME_ID;
201                                 i->checksum[1] = 0;
202                                 i->state = FBUS_RX_GetDestination;
203                         } else {
204                                 /* Lost frame sync */
205                                 i->state = FBUS_RX_Discarding;
206                                 gettimeofday(&i->time_last, NULL);
207                         }
208
209                 } else {        /* glink->ConnectionType == GCT_Serial */
210                         if (rx_byte == FBUS_FRAME_ID) {
211                                 /* Initialize checksums. */
212                                 i->checksum[0] = FBUS_FRAME_ID;
213                                 i->checksum[1] = 0;
214                                 i->state = FBUS_RX_GetDestination;
215                         } else {
216                                 /* Lost frame sync */
217                                 i->state = FBUS_RX_Discarding;
218                                 gettimeofday(&i->time_last, NULL);
219                         }
220                 }
221
222                 break;
223
224         case FBUS_RX_GetDestination:
225
226                 i->MessageDestination = rx_byte;
227                 i->state = FBUS_RX_GetSource;
228
229                 /* When there is a checksum error and things get out of sync we have to manage to resync */
230                 /* If doing a data call at the time, finding a 0x1e etc is really quite likely in the data stream */
231                 /* Then all sorts of horrible things happen because the packet length etc is wrong... */
232                 /* Therefore we test here for a destination of 0x0c and return to the top if it is not */
233
234                 if (rx_byte != 0x0c) {
235                         i->state = FBUS_RX_Sync;
236                         dprintf("The fbus stream is out of sync - expected 0x0c, got %2x\n", rx_byte);
237                 }
238
239                 break;
240
241         case FBUS_RX_GetSource:
242
243                 i->MessageSource = rx_byte;
244                 i->state = FBUS_RX_GetType;
245
246                 /* Source should be 0x00 */
247
248                 if (rx_byte != 0x00) {
249                         i->state = FBUS_RX_Sync;
250                         dprintf("The fbus stream is out of sync - expected 0x00, got %2x\n",rx_byte);
251                 }
252
253                 break;
254
255         case FBUS_RX_GetType:
256
257                 i->MessageType = rx_byte;
258                 i->state = FBUS_RX_GetLength1;
259
260                 break;
261
262         case FBUS_RX_GetLength1:
263
264                 i->FrameLength = rx_byte << 8;
265                 i->state = FBUS_RX_GetLength2;
266
267                 break;
268
269         case FBUS_RX_GetLength2:
270
271                 i->FrameLength = i->FrameLength + rx_byte;
272                 i->state = FBUS_RX_GetMessage;
273                 i->BufferCount = 0;
274
275                 break;
276
277         case FBUS_RX_GetMessage:
278
279                 i->MessageBuffer[i->BufferCount] = rx_byte;
280                 i->BufferCount++;
281                 
282                 if (i->BufferCount > FBUS_MAX_FRAME_LENGTH) {
283                         dprintf("FBUS: Message buffer overun - resetting\n");
284                         i->state = FBUS_RX_Sync;
285                         break;
286                 }
287
288                 /* If this is the last byte, it's the checksum. */
289
290                 if (i->BufferCount == i->FrameLength + (i->FrameLength % 2) + 2) {
291                         /* Is the checksum correct? */
292                         if (i->checksum[0] == i->checksum[1]) {
293
294                                 /* Deal with exceptions to the rules - acks and rlp.. */
295
296                                 if (i->MessageType == 0x7f) {
297                                         dprintf("[Received Ack of type %02x, seq: %2x]\n",
298                                                 i->MessageBuffer[0],(unsigned char) i->MessageBuffer[1]);
299
300                                 } else {        /* Normal message type */
301
302                                         /* Add data to the relevant Message buffer */
303                                         /* having checked the sequence number */
304
305                                         m = &flink.messages[i->MessageType];
306
307                                         frm_num = i->MessageBuffer[i->FrameLength - 2];
308                                         seq_num = i->MessageBuffer[i->FrameLength - 1];
309
310
311                                         /* 0x40 in the sequence number indicates first frame of a message */
312
313                                         if ((seq_num & 0x40) == 0x40) {
314                                                 /* Fiddle around and malloc some memory */
315                                                 m->MessageLength = 0;
316                                                 m->FramesToGo = frm_num;
317                                                 if (m->Malloced != 0) {
318                                                         free(m->MessageBuffer);
319                                                         m->Malloced = 0;
320                                                         m->MessageBuffer = NULL;
321                                                 }
322                                                 m->Malloced = frm_num * m->MessageLength;
323                                                 m->MessageBuffer = (char *) malloc(m->Malloced);
324
325                                         } else if (m->FramesToGo != frm_num) {
326                                                 dprintf("Missed a frame in a multiframe message.\n");
327                                                 /* FIXME - we should make sure we don't ack the rest etc */
328                                         }
329
330                                         if (m->Malloced < m->MessageLength + i->FrameLength) {
331                                                 m->Malloced = m->MessageLength + i->FrameLength;
332                                                 m->MessageBuffer = (char *) realloc(m->MessageBuffer, m->Malloced);
333                                         }
334
335                                         memcpy(m->MessageBuffer + m->MessageLength, i->MessageBuffer,
336                                                i->FrameLength - 2);/* - (i->FrameLength % 2)); */
337
338                                         m->MessageLength += i->FrameLength - 2;/* - (i->FrameLength % 2); */
339
340                                         m->FramesToGo--;
341
342                                         /* Finally dispatch if ready */
343
344                                         if (m->FramesToGo == 0) {
345                                                 SM_IncomingFunction(statemachine, i->MessageType, m->MessageBuffer, m->MessageLength);
346                                                 free(m->MessageBuffer);
347                                                 m->MessageBuffer = NULL;
348                                                 m->Malloced = 0;
349                                         }
350
351                                         /* Send an ack (for all for now) */
352
353                                         FBUS_TX_SendAck(i->MessageType, seq_num & 0x0f);
354                                         
355                                 }
356                         } else {
357                                 dprintf("Bad checksum!\n");
358                         }
359                         i->state = FBUS_RX_Sync;
360                 }
361                 break;
362         }
363 }
364
365
366 /* This is the main loop function which must be called regularly */
367 /* timeout can be used to make it 'busy' or not */
368
369 GSM_Error FBUS_Loop(struct timeval *timeout)
370 {
371 #ifndef WIN32
372         unsigned char buffer[255];
373         int count, res;
374
375         res = device_select(timeout);
376         if (res > 0) {
377                 res = device_read(buffer, 255);
378                 for (count = 0; count < res; count++)
379                         FBUS_RX_StateMachine(buffer[count]);
380         } else
381                 return GE_TIMEOUT;
382
383         /* This traps errors from device_read */
384         if (res > 0)
385                 return GE_NONE;
386         else
387                 return GE_INTERNALERROR;
388 #else
389         return GE_NONE;
390 #endif
391 }
392
393
394
395 /* Prepares the message header and sends it, prepends the message start byte
396            (0x1e) and other values according the value specified when called.
397            Calculates checksum and then sends the lot down the pipe... */
398
399 int FBUS_TX_SendFrame(u8 message_length, u8 message_type, u8 * buffer)
400 {
401
402         u8 out_buffer[FBUS_MAX_TRANSMIT_LENGTH + 5];
403         int count, current = 0;
404         unsigned char checksum;
405
406         /* FIXME - we should check for the message length ... */
407
408         /* Now construct the message header. */
409
410         if (glink->ConnectionType == GCT_Infrared)
411                 out_buffer[current++] = FBUS_IR_FRAME_ID;       /* Start of the IR frame indicator */
412         else                    /* ConnectionType == GCT_Serial */
413                 out_buffer[current++] = FBUS_FRAME_ID;  /* Start of the frame indicator */
414
415         out_buffer[current++] = FBUS_DEVICE_PHONE;      /* Destination */
416         out_buffer[current++] = FBUS_DEVICE_PC; /* Source */
417
418         out_buffer[current++] = message_type;   /* Type */
419
420         out_buffer[current++] = 0;      /* Length */
421
422         out_buffer[current++] = message_length; /* Length */
423
424         /* Copy in data if any. */
425
426         if (message_length != 0) {
427                 memcpy(out_buffer + current, buffer, message_length);
428                 current += message_length;
429         }
430
431         /* If the message length is odd we should add pad byte 0x00 */
432         if (message_length % 2)
433                 out_buffer[current++] = 0x00;
434
435         /* Now calculate checksums over entire message and append to message. */
436
437         /* Odd bytes */
438
439         checksum = 0;
440         for (count = 0; count < current; count += 2)
441                 checksum ^= out_buffer[count];
442
443         out_buffer[current++] = checksum;
444
445         /* Even bytes */
446
447         checksum = 0;
448         for (count = 1; count < current; count += 2)
449                 checksum ^= out_buffer[count];
450
451         out_buffer[current++] = checksum;
452
453 #ifdef DEBUG
454         fprintf(stderr, _("PC: "));
455
456         for (count = 0; count < current; count++)
457                 fprintf(stderr, "%02x:", out_buffer[count]);
458
459         fprintf(stderr, "\n");
460 #endif                          /* DEBUG */
461
462         /* Send it out... */
463
464         if (device_write(out_buffer, current) != current)
465                 return (false);
466
467         return (true);
468 }
469
470
471 /* Main function to send an fbus message */
472 /* Splits up the message into frames if necessary */
473
474 GSM_Error FBUS_SendMessage(u16 messagesize, u8 messagetype, void *message)
475 {
476
477         u8 seqnum, frame_buffer[FBUS_MAX_CONTENT_LENGTH + 2];
478         u8 nom, lml;            /* number of messages, last message len */
479         int i;
480
481         seqnum = 0x40 + flink.RequestSequenceNumber;
482         flink.RequestSequenceNumber =
483             (flink.RequestSequenceNumber + 1) & 0x07;
484
485         if (messagesize > FBUS_MAX_CONTENT_LENGTH) {
486
487                 nom = (messagesize + FBUS_MAX_CONTENT_LENGTH - 1)
488                     / FBUS_MAX_CONTENT_LENGTH;
489                 lml = messagesize - ((nom - 1) * FBUS_MAX_CONTENT_LENGTH);
490
491                 for (i = 0; i < nom - 1; i++) {
492
493                         memcpy(frame_buffer, message + (i * FBUS_MAX_CONTENT_LENGTH),
494                                FBUS_MAX_CONTENT_LENGTH);
495                         frame_buffer[FBUS_MAX_CONTENT_LENGTH] = nom - i;
496                         frame_buffer[FBUS_MAX_CONTENT_LENGTH + 1] = seqnum;
497
498                         FBUS_TX_SendFrame(FBUS_MAX_CONTENT_LENGTH + 2,
499                                           messagetype, frame_buffer);
500
501                         seqnum = flink.RequestSequenceNumber;
502                         flink.RequestSequenceNumber = (flink.RequestSequenceNumber + 1) & 0x07;
503                 }
504
505                 memcpy(frame_buffer, message + ((nom - 1) * FBUS_MAX_CONTENT_LENGTH), lml);
506                 frame_buffer[lml] = 0x01;
507                 frame_buffer[lml + 1] = seqnum;
508                 FBUS_TX_SendFrame(lml + 2, messagetype, frame_buffer);
509
510         } else {
511
512                 memcpy(frame_buffer, message, messagesize);
513                 frame_buffer[messagesize] = 0x01;
514                 frame_buffer[messagesize + 1] = seqnum;
515                 FBUS_TX_SendFrame(messagesize + 2, messagetype,
516                                   frame_buffer);
517         }
518         return (GE_NONE);
519 }
520
521
522 int FBUS_TX_SendAck(u8 message_type, u8 message_seq)
523 {
524
525         unsigned char request[2];
526
527         request[0] = message_type;
528         request[1] = message_seq;
529
530         dprintf("[Sending Ack of type %02x, seq: %x]\n",message_type, message_seq);
531
532         return FBUS_TX_SendFrame(2, 0x7f, request);
533 }
534
535
536 /* Initialise variables and start the link */
537 /* newlink is actually part of state - but the link code should not anything about state */
538 /* state is only passed around to allow for muliple state machines (one day...) */
539
540 GSM_Error FBUS_Initialise(GSM_Link *newlink, GSM_Statemachine *state, int type)
541 {
542         unsigned char init_char = 0x55;
543         unsigned char count;
544
545         if (type > 2) return GE_DEVICEOPENFAILED;
546         /* 'Copy in' the global structures */
547         glink = newlink;
548         statemachine = state;
549
550         /* Fill in the link functions */
551         glink->Loop = &FBUS_Loop;
552         glink->SendMessage = &FBUS_SendMessage;
553
554         /* Check for a valid init length */
555         if (glink->InitLength == 0)
556                 glink->InitLength = 250;
557
558         /* Start up the link */
559         flink.RequestSequenceNumber = 0;
560
561         if (glink->ConnectionType == GCT_Infrared) {
562                 /* FIXME!! */
563                 return GE_DEVICEOPENFAILED;
564         } else {                /* ConnectionType == GCT_Serial */
565                 /* FBUS_OpenSerial(0) - try dau-9p
566                  * FBUS_OpenSerial(n != 0) - try dlr-3p */
567                 if (!FBUS_OpenSerial(type))
568                         return GE_DEVICEOPENFAILED;
569         }
570
571         /* Send init string to phone, this is a bunch of 0x55 characters. Timing is
572            empirical. */
573         /* I believe that we need/can do this for any phone to get the UART synced */
574
575         for (count = 0; count < glink->InitLength; count++) {
576                 usleep(100);
577                 device_write(&init_char, 1);
578         }
579
580         /* Init variables */
581         flink.i.state = FBUS_RX_Sync;
582         flink.i.BufferCount = 0;
583         for (count = 0; count < FBUS_MAX_MESSAGE_TYPES; count++) {
584                 flink.messages[count].Malloced = 0;
585                 flink.messages[count].FramesToGo = 0;
586                 flink.messages[count].MessageLength = 0;
587         }
588
589         return GE_NONE;
590 }