7 A Linux/Unix toolset and driver for Nokia mobile phones.
9 Copyright (C) 2000 Hugh Blemings & Pavel JanÃk ml.
10 Copyright (C) 2000 Chris Kemp
12 Released under the terms of the GNU GPL, see file COPYING for more details.
14 This file provides an API for accessing functions via fbus.
15 See README for more details on supported mobile phones.
17 The various routines are called FBUS_(whatever).
20 Revision 1.1.1.1.12.1 2001/11/27 23:34:48 short
21 Update: orig2001_11_27_05_17 -> orig2001_11_27_22_58
23 Revision 1.1.1.1.8.1 2001/11/27 23:06:09 short
24 Update: orig2001_11_27_05_17 -> orig2001_11_27_22_58
26 Revision 1.1.1.1.2.1 2001/11/27 22:48:37 short
27 Update: orig2001_11_27_05_17 -> orig2001_11_27_22_58
29 Revision 1.1.1.2 2001/11/27 22:01:16 short
30 :pserver:cvs@pserver.samba.org:/cvsroot - gnokii - Tue Nov 27 22:58 CET 2001
32 Revision 1.14 2001/11/27 12:19:01 pkot
33 Cleanup, indentation, ANSI complaint preprocesor symbols (Jan Kratochvil, me)
35 Revision 1.13 2001/11/17 20:14:15 pkot
36 Nasty bug with counting message length. Workaround applied. Needs fixing.
38 Revision 1.12 2001/11/15 12:04:05 pkot
39 Faster initialization for 6100 series (don't check for dlr3 cable)
41 Revision 1.11 2001/09/09 21:45:49 machek
42 Cleanups from Ladislav Michl <ladis@psi.cz>:
44 *) do *not* internationalize debug messages
46 *) some whitespace fixes, do not use //
48 *) break is unneccessary after return
50 Revision 1.10 2001/08/20 23:27:37 pkot
51 Add hardware shakehand to the link layer (Manfred Jonsson)
53 Revision 1.9 2001/05/28 09:25:16 pkot
54 Fixed autodetecting of the cable type in 6110 and 7110 series. DLR-3 is
55 tried first now. Seems to work ok with either 6130 or 6210.
57 Revision 1.8 2001/05/07 16:24:03 pkot
58 DLR-3P temporary fix. How should I do it better?
60 Revision 1.7 2001/03/22 16:17:05 chris
61 Tidy-ups and fixed gnokii/Makefile and gnokii/ChangeLog which I somehow corrupted.
63 Revision 1.6 2001/03/21 23:36:05 chris
64 Added the statemachine
65 This will break gnokii --identify and --monitor except for 6210/7110
67 Revision 1.5 2001/03/19 23:44:56 pkot
70 Revision 1.4 2001/03/13 01:24:02 pkot
71 Code cleanup - no warnings during compilation
73 Revision 1.3 2001/03/13 01:23:18 pkot
74 Windows updates (Manfred Jonsson)
76 Revision 1.2 2001/03/11 11:18:39 machek
77 Made fbus link_dispatch (and fixed minor memory leak)
79 Revision 1.1 2001/02/21 19:57:06 chris
80 More fiddling with the directory layout
82 Revision 1.1 2001/02/16 14:29:52 chris
83 Restructure of common/. Fixed a problem in fbus-phonet.c
84 Lots of dprintfs for Marcin
85 Any size xpm can now be loaded (eg for 7110 startup logos)
86 nk7110 code detects 7110/6210 and alters startup logo size to suit
87 Moved Marcin's extended phonebook code into gnokii.c
89 Revision 1.3 2001/02/06 21:15:34 chris
90 Preliminary irda support for 7110 etc. Not well tested!
92 Revision 1.2 2001/02/03 23:56:14 chris
93 Start of work on irda support (now we just need fbus-irda.c!)
94 Proper unicode support in 7110 code (from pkot)
96 Revision 1.1 2001/01/14 22:46:59 chris
97 Preliminary 7110 support (dlr9 only) and the beginnings of a new structure
102 /* System header files */
108 /* Various header file */
112 #include "gsm-common.h"
113 #include "gsm-ringtones.h"
114 #include "gsm-networks.h"
115 #include "gsm-statemachine.h"
116 #include "links/utils.h"
121 # include "win32/winserial.h"
122 # define device_write(a, b) WriteCommBlock(a, b)
123 # define device_read(a, b) ReadCommBlock(a, b)
124 # define sleep(x) Sleep((x) * 1000)
125 # define usleep(x) Sleep(((x) < 1000) ? 1 : ((x) / 1000))
128 #define __links_fbus_c
129 #include "links/fbus.h"
131 /* FIXME - pass device_* the link stuff?? */
132 /* FIXME - win32 stuff! */
137 static GSM_Link *glink;
138 static GSM_Statemachine *statemachine;
139 static FBUS_Link flink; /* FBUS specific stuff, internal to this file */
142 /*--------------------------------------------*/
144 bool FBUS_OpenSerial(bool dlr3)
149 if (OpenConnection(glink->PortDevice, FBUS_RX_StateMachine, NULL)) {
151 if (!device_open(glink->PortDevice, false, false, false, GCT_Serial)) {
153 perror(_("Couldn't open FBUS device"));
156 device_changespeed(115200);
158 /* clearing the RTS bit and setting the DTR bit */
159 device_setdtrrts((1-dlr3), 0);
165 /* RX_State machine for receive handling. Called once for each character
166 received from the phone. */
168 void FBUS_RX_StateMachine(unsigned char rx_byte)
171 struct timeval time_diff;
172 FBUS_IncomingFrame *i = &flink.i;
173 int frm_num, seq_num;
174 FBUS_IncomingMessage *m;
177 if (isprint(rx_byte))
178 dprintf("[%02x%c]", (unsigned char) rx_byte, rx_byte);
180 dprintf("[%02x ]", (unsigned char) rx_byte);
183 /* XOR the byte with the current checksum */
184 i->checksum[i->BufferCount & 1] ^= rx_byte;
188 /* Messages from the phone start with an 0x1e (cable) or 0x1c (IR).
189 We use this to "synchronise" with the incoming data stream. However,
190 if we see something else, we assume we have lost sync and we require
191 a gap of at least 5ms before we start looking again. This is because
192 the data part of the frame could contain a byte which looks like the
195 case FBUS_RX_Discarding:
196 gettimeofday(&i->time_now, NULL);
197 timersub(&i->time_now, &i->time_last, &time_diff);
198 if (time_diff.tv_sec == 0 && time_diff.tv_usec < 5000) {
199 i->time_last = i->time_now; /* no gap seen, continue discarding */
203 /* else fall through to... */
206 if (glink->ConnectionType == GCT_Infrared) {
207 if (rx_byte == FBUS_IR_FRAME_ID) {
208 /* Initialize checksums. */
209 i->checksum[0] = FBUS_IR_FRAME_ID;
211 i->state = FBUS_RX_GetDestination;
213 /* Lost frame sync */
214 i->state = FBUS_RX_Discarding;
215 gettimeofday(&i->time_last, NULL);
218 } else { /* glink->ConnectionType == GCT_Serial */
219 if (rx_byte == FBUS_FRAME_ID) {
220 /* Initialize checksums. */
221 i->checksum[0] = FBUS_FRAME_ID;
223 i->state = FBUS_RX_GetDestination;
225 /* Lost frame sync */
226 i->state = FBUS_RX_Discarding;
227 gettimeofday(&i->time_last, NULL);
233 case FBUS_RX_GetDestination:
235 i->MessageDestination = rx_byte;
236 i->state = FBUS_RX_GetSource;
238 /* When there is a checksum error and things get out of sync we have to manage to resync */
239 /* If doing a data call at the time, finding a 0x1e etc is really quite likely in the data stream */
240 /* Then all sorts of horrible things happen because the packet length etc is wrong... */
241 /* Therefore we test here for a destination of 0x0c and return to the top if it is not */
243 if (rx_byte != 0x0c) {
244 i->state = FBUS_RX_Sync;
245 dprintf("The fbus stream is out of sync - expected 0x0c, got %2x\n", rx_byte);
250 case FBUS_RX_GetSource:
252 i->MessageSource = rx_byte;
253 i->state = FBUS_RX_GetType;
255 /* Source should be 0x00 */
257 if (rx_byte != 0x00) {
258 i->state = FBUS_RX_Sync;
259 dprintf("The fbus stream is out of sync - expected 0x00, got %2x\n",rx_byte);
264 case FBUS_RX_GetType:
266 i->MessageType = rx_byte;
267 i->state = FBUS_RX_GetLength1;
271 case FBUS_RX_GetLength1:
273 i->FrameLength = rx_byte << 8;
274 i->state = FBUS_RX_GetLength2;
278 case FBUS_RX_GetLength2:
280 i->FrameLength = i->FrameLength + rx_byte;
281 i->state = FBUS_RX_GetMessage;
286 case FBUS_RX_GetMessage:
288 i->MessageBuffer[i->BufferCount] = rx_byte;
291 if (i->BufferCount > FBUS_MAX_FRAME_LENGTH) {
292 dprintf("FBUS: Message buffer overun - resetting\n");
293 i->state = FBUS_RX_Sync;
297 /* If this is the last byte, it's the checksum. */
299 if (i->BufferCount == i->FrameLength + (i->FrameLength % 2) + 2) {
300 /* Is the checksum correct? */
301 if (i->checksum[0] == i->checksum[1]) {
303 /* Deal with exceptions to the rules - acks and rlp.. */
305 if (i->MessageType == 0x7f) {
306 dprintf("[Received Ack of type %02x, seq: %2x]\n",
307 i->MessageBuffer[0],(unsigned char) i->MessageBuffer[1]);
309 } else { /* Normal message type */
311 /* Add data to the relevant Message buffer */
312 /* having checked the sequence number */
314 m = &flink.messages[i->MessageType];
316 frm_num = i->MessageBuffer[i->FrameLength - 2];
317 seq_num = i->MessageBuffer[i->FrameLength - 1];
320 /* 0x40 in the sequence number indicates first frame of a message */
322 if ((seq_num & 0x40) == 0x40) {
323 /* Fiddle around and malloc some memory */
324 m->MessageLength = 0;
325 m->FramesToGo = frm_num;
326 if (m->Malloced != 0) {
327 free(m->MessageBuffer);
329 m->MessageBuffer = NULL;
331 m->Malloced = frm_num * m->MessageLength;
332 m->MessageBuffer = (char *) malloc(m->Malloced);
334 } else if (m->FramesToGo != frm_num) {
335 dprintf("Missed a frame in a multiframe message.\n");
336 /* FIXME - we should make sure we don't ack the rest etc */
339 if (m->Malloced < m->MessageLength + i->FrameLength) {
340 m->Malloced = m->MessageLength + i->FrameLength;
341 m->MessageBuffer = (char *) realloc(m->MessageBuffer, m->Malloced);
344 memcpy(m->MessageBuffer + m->MessageLength, i->MessageBuffer,
345 i->FrameLength - 2);/* - (i->FrameLength % 2)); */
347 m->MessageLength += i->FrameLength - 2;/* - (i->FrameLength % 2); */
351 /* Finally dispatch if ready */
353 if (m->FramesToGo == 0) {
354 SM_IncomingFunction(statemachine, i->MessageType, m->MessageBuffer, m->MessageLength);
355 free(m->MessageBuffer);
356 m->MessageBuffer = NULL;
360 /* Send an ack (for all for now) */
362 FBUS_TX_SendAck(i->MessageType, seq_num & 0x0f);
366 dprintf("Bad checksum!\n");
368 i->state = FBUS_RX_Sync;
375 /* This is the main loop function which must be called regularly */
376 /* timeout can be used to make it 'busy' or not */
378 GSM_Error FBUS_Loop(struct timeval *timeout)
381 unsigned char buffer[255];
384 res = device_select(timeout);
386 res = device_read(buffer, 255);
387 for (count = 0; count < res; count++)
388 FBUS_RX_StateMachine(buffer[count]);
392 /* This traps errors from device_read */
396 return GE_INTERNALERROR;
404 /* Prepares the message header and sends it, prepends the message start byte
405 (0x1e) and other values according the value specified when called.
406 Calculates checksum and then sends the lot down the pipe... */
408 int FBUS_TX_SendFrame(u8 message_length, u8 message_type, u8 * buffer)
411 u8 out_buffer[FBUS_MAX_TRANSMIT_LENGTH + 5];
412 int count, current = 0;
413 unsigned char checksum;
415 /* FIXME - we should check for the message length ... */
417 /* Now construct the message header. */
419 if (glink->ConnectionType == GCT_Infrared)
420 out_buffer[current++] = FBUS_IR_FRAME_ID; /* Start of the IR frame indicator */
421 else /* ConnectionType == GCT_Serial */
422 out_buffer[current++] = FBUS_FRAME_ID; /* Start of the frame indicator */
424 out_buffer[current++] = FBUS_DEVICE_PHONE; /* Destination */
425 out_buffer[current++] = FBUS_DEVICE_PC; /* Source */
427 out_buffer[current++] = message_type; /* Type */
429 out_buffer[current++] = 0; /* Length */
431 out_buffer[current++] = message_length; /* Length */
433 /* Copy in data if any. */
435 if (message_length != 0) {
436 memcpy(out_buffer + current, buffer, message_length);
437 current += message_length;
440 /* If the message length is odd we should add pad byte 0x00 */
441 if (message_length % 2)
442 out_buffer[current++] = 0x00;
444 /* Now calculate checksums over entire message and append to message. */
449 for (count = 0; count < current; count += 2)
450 checksum ^= out_buffer[count];
452 out_buffer[current++] = checksum;
457 for (count = 1; count < current; count += 2)
458 checksum ^= out_buffer[count];
460 out_buffer[current++] = checksum;
463 fprintf(stderr, _("PC: "));
465 for (count = 0; count < current; count++)
466 fprintf(stderr, "%02x:", out_buffer[count]);
468 fprintf(stderr, "\n");
473 if (device_write(out_buffer, current) != current)
480 /* Main function to send an fbus message */
481 /* Splits up the message into frames if necessary */
483 GSM_Error FBUS_SendMessage(u16 messagesize, u8 messagetype, void *message)
486 u8 seqnum, frame_buffer[FBUS_MAX_CONTENT_LENGTH + 2];
487 u8 nom, lml; /* number of messages, last message len */
490 seqnum = 0x40 + flink.RequestSequenceNumber;
491 flink.RequestSequenceNumber =
492 (flink.RequestSequenceNumber + 1) & 0x07;
494 if (messagesize > FBUS_MAX_CONTENT_LENGTH) {
496 nom = (messagesize + FBUS_MAX_CONTENT_LENGTH - 1)
497 / FBUS_MAX_CONTENT_LENGTH;
498 lml = messagesize - ((nom - 1) * FBUS_MAX_CONTENT_LENGTH);
500 for (i = 0; i < nom - 1; i++) {
502 memcpy(frame_buffer, message + (i * FBUS_MAX_CONTENT_LENGTH),
503 FBUS_MAX_CONTENT_LENGTH);
504 frame_buffer[FBUS_MAX_CONTENT_LENGTH] = nom - i;
505 frame_buffer[FBUS_MAX_CONTENT_LENGTH + 1] = seqnum;
507 FBUS_TX_SendFrame(FBUS_MAX_CONTENT_LENGTH + 2,
508 messagetype, frame_buffer);
510 seqnum = flink.RequestSequenceNumber;
511 flink.RequestSequenceNumber = (flink.RequestSequenceNumber + 1) & 0x07;
514 memcpy(frame_buffer, message + ((nom - 1) * FBUS_MAX_CONTENT_LENGTH), lml);
515 frame_buffer[lml] = 0x01;
516 frame_buffer[lml + 1] = seqnum;
517 FBUS_TX_SendFrame(lml + 2, messagetype, frame_buffer);
521 memcpy(frame_buffer, message, messagesize);
522 frame_buffer[messagesize] = 0x01;
523 frame_buffer[messagesize + 1] = seqnum;
524 FBUS_TX_SendFrame(messagesize + 2, messagetype,
531 int FBUS_TX_SendAck(u8 message_type, u8 message_seq)
534 unsigned char request[2];
536 request[0] = message_type;
537 request[1] = message_seq;
539 dprintf("[Sending Ack of type %02x, seq: %x]\n",message_type, message_seq);
541 return FBUS_TX_SendFrame(2, 0x7f, request);
545 /* Initialise variables and start the link */
546 /* newlink is actually part of state - but the link code should not anything about state */
547 /* state is only passed around to allow for muliple state machines (one day...) */
549 GSM_Error FBUS_Initialise(GSM_Link *newlink, GSM_Statemachine *state, int type)
551 unsigned char init_char = 0x55;
554 if (type > 2) return GE_DEVICEOPENFAILED;
555 /* 'Copy in' the global structures */
557 statemachine = state;
559 /* Fill in the link functions */
560 glink->Loop = &FBUS_Loop;
561 glink->SendMessage = &FBUS_SendMessage;
563 /* Check for a valid init length */
564 if (glink->InitLength == 0)
565 glink->InitLength = 250;
567 /* Start up the link */
568 flink.RequestSequenceNumber = 0;
570 if (glink->ConnectionType == GCT_Infrared) {
572 return GE_DEVICEOPENFAILED;
573 } else { /* ConnectionType == GCT_Serial */
574 /* FBUS_OpenSerial(0) - try dau-9p
575 * FBUS_OpenSerial(n != 0) - try dlr-3p */
576 if (!FBUS_OpenSerial(type))
577 return GE_DEVICEOPENFAILED;
580 /* Send init string to phone, this is a bunch of 0x55 characters. Timing is
582 /* I believe that we need/can do this for any phone to get the UART synced */
584 for (count = 0; count < glink->InitLength; count++) {
586 device_write(&init_char, 1);
590 flink.i.state = FBUS_RX_Sync;
591 flink.i.BufferCount = 0;
592 for (count = 0; count < FBUS_MAX_MESSAGE_TYPES; count++) {
593 flink.messages[count].Malloced = 0;
594 flink.messages[count].FramesToGo = 0;
595 flink.messages[count].MessageLength = 0;