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.8.1 2001/11/27 23:06:09 short
21 Update: orig2001_11_27_05_17 -> orig2001_11_27_22_58
23 Revision 1.1.1.1.2.1 2001/11/27 22:48:37 short
24 Update: orig2001_11_27_05_17 -> orig2001_11_27_22_58
26 Revision 1.1.1.2 2001/11/27 22:01:16 short
27 :pserver:cvs@pserver.samba.org:/cvsroot - gnokii - Tue Nov 27 22:58 CET 2001
29 Revision 1.14 2001/11/27 12:19:01 pkot
30 Cleanup, indentation, ANSI complaint preprocesor symbols (Jan Kratochvil, me)
32 Revision 1.13 2001/11/17 20:14:15 pkot
33 Nasty bug with counting message length. Workaround applied. Needs fixing.
35 Revision 1.12 2001/11/15 12:04:05 pkot
36 Faster initialization for 6100 series (don't check for dlr3 cable)
38 Revision 1.11 2001/09/09 21:45:49 machek
39 Cleanups from Ladislav Michl <ladis@psi.cz>:
41 *) do *not* internationalize debug messages
43 *) some whitespace fixes, do not use //
45 *) break is unneccessary after return
47 Revision 1.10 2001/08/20 23:27:37 pkot
48 Add hardware shakehand to the link layer (Manfred Jonsson)
50 Revision 1.9 2001/05/28 09:25:16 pkot
51 Fixed autodetecting of the cable type in 6110 and 7110 series. DLR-3 is
52 tried first now. Seems to work ok with either 6130 or 6210.
54 Revision 1.8 2001/05/07 16:24:03 pkot
55 DLR-3P temporary fix. How should I do it better?
57 Revision 1.7 2001/03/22 16:17:05 chris
58 Tidy-ups and fixed gnokii/Makefile and gnokii/ChangeLog which I somehow corrupted.
60 Revision 1.6 2001/03/21 23:36:05 chris
61 Added the statemachine
62 This will break gnokii --identify and --monitor except for 6210/7110
64 Revision 1.5 2001/03/19 23:44:56 pkot
67 Revision 1.4 2001/03/13 01:24:02 pkot
68 Code cleanup - no warnings during compilation
70 Revision 1.3 2001/03/13 01:23:18 pkot
71 Windows updates (Manfred Jonsson)
73 Revision 1.2 2001/03/11 11:18:39 machek
74 Made fbus link_dispatch (and fixed minor memory leak)
76 Revision 1.1 2001/02/21 19:57:06 chris
77 More fiddling with the directory layout
79 Revision 1.1 2001/02/16 14:29:52 chris
80 Restructure of common/. Fixed a problem in fbus-phonet.c
81 Lots of dprintfs for Marcin
82 Any size xpm can now be loaded (eg for 7110 startup logos)
83 nk7110 code detects 7110/6210 and alters startup logo size to suit
84 Moved Marcin's extended phonebook code into gnokii.c
86 Revision 1.3 2001/02/06 21:15:34 chris
87 Preliminary irda support for 7110 etc. Not well tested!
89 Revision 1.2 2001/02/03 23:56:14 chris
90 Start of work on irda support (now we just need fbus-irda.c!)
91 Proper unicode support in 7110 code (from pkot)
93 Revision 1.1 2001/01/14 22:46:59 chris
94 Preliminary 7110 support (dlr9 only) and the beginnings of a new structure
99 /* System header files */
105 /* Various header file */
109 #include "gsm-common.h"
110 #include "gsm-ringtones.h"
111 #include "gsm-networks.h"
112 #include "gsm-statemachine.h"
113 #include "links/utils.h"
118 # include "win32/winserial.h"
119 # define device_write(a, b) WriteCommBlock(a, b)
120 # define device_read(a, b) ReadCommBlock(a, b)
121 # define sleep(x) Sleep((x) * 1000)
122 # define usleep(x) Sleep(((x) < 1000) ? 1 : ((x) / 1000))
125 #define __links_fbus_c
126 #include "links/fbus.h"
128 /* FIXME - pass device_* the link stuff?? */
129 /* FIXME - win32 stuff! */
134 static GSM_Link *glink;
135 static GSM_Statemachine *statemachine;
136 static FBUS_Link flink; /* FBUS specific stuff, internal to this file */
139 /*--------------------------------------------*/
141 bool FBUS_OpenSerial(bool dlr3)
146 if (OpenConnection(glink->PortDevice, FBUS_RX_StateMachine, NULL)) {
148 if (!device_open(glink->PortDevice, false, false, false, GCT_Serial)) {
150 perror(_("Couldn't open FBUS device"));
153 device_changespeed(115200);
155 /* clearing the RTS bit and setting the DTR bit */
156 device_setdtrrts((1-dlr3), 0);
162 /* RX_State machine for receive handling. Called once for each character
163 received from the phone. */
165 void FBUS_RX_StateMachine(unsigned char rx_byte)
168 struct timeval time_diff;
169 FBUS_IncomingFrame *i = &flink.i;
170 int frm_num, seq_num;
171 FBUS_IncomingMessage *m;
174 if (isprint(rx_byte))
175 dprintf("[%02x%c]", (unsigned char) rx_byte, rx_byte);
177 dprintf("[%02x ]", (unsigned char) rx_byte);
180 /* XOR the byte with the current checksum */
181 i->checksum[i->BufferCount & 1] ^= rx_byte;
185 /* Messages from the phone start with an 0x1e (cable) or 0x1c (IR).
186 We use this to "synchronise" with the incoming data stream. However,
187 if we see something else, we assume we have lost sync and we require
188 a gap of at least 5ms before we start looking again. This is because
189 the data part of the frame could contain a byte which looks like the
192 case FBUS_RX_Discarding:
193 gettimeofday(&i->time_now, NULL);
194 timersub(&i->time_now, &i->time_last, &time_diff);
195 if (time_diff.tv_sec == 0 && time_diff.tv_usec < 5000) {
196 i->time_last = i->time_now; /* no gap seen, continue discarding */
200 /* else fall through to... */
203 if (glink->ConnectionType == GCT_Infrared) {
204 if (rx_byte == FBUS_IR_FRAME_ID) {
205 /* Initialize checksums. */
206 i->checksum[0] = FBUS_IR_FRAME_ID;
208 i->state = FBUS_RX_GetDestination;
210 /* Lost frame sync */
211 i->state = FBUS_RX_Discarding;
212 gettimeofday(&i->time_last, NULL);
215 } else { /* glink->ConnectionType == GCT_Serial */
216 if (rx_byte == FBUS_FRAME_ID) {
217 /* Initialize checksums. */
218 i->checksum[0] = FBUS_FRAME_ID;
220 i->state = FBUS_RX_GetDestination;
222 /* Lost frame sync */
223 i->state = FBUS_RX_Discarding;
224 gettimeofday(&i->time_last, NULL);
230 case FBUS_RX_GetDestination:
232 i->MessageDestination = rx_byte;
233 i->state = FBUS_RX_GetSource;
235 /* When there is a checksum error and things get out of sync we have to manage to resync */
236 /* If doing a data call at the time, finding a 0x1e etc is really quite likely in the data stream */
237 /* Then all sorts of horrible things happen because the packet length etc is wrong... */
238 /* Therefore we test here for a destination of 0x0c and return to the top if it is not */
240 if (rx_byte != 0x0c) {
241 i->state = FBUS_RX_Sync;
242 dprintf("The fbus stream is out of sync - expected 0x0c, got %2x\n", rx_byte);
247 case FBUS_RX_GetSource:
249 i->MessageSource = rx_byte;
250 i->state = FBUS_RX_GetType;
252 /* Source should be 0x00 */
254 if (rx_byte != 0x00) {
255 i->state = FBUS_RX_Sync;
256 dprintf("The fbus stream is out of sync - expected 0x00, got %2x\n",rx_byte);
261 case FBUS_RX_GetType:
263 i->MessageType = rx_byte;
264 i->state = FBUS_RX_GetLength1;
268 case FBUS_RX_GetLength1:
270 i->FrameLength = rx_byte << 8;
271 i->state = FBUS_RX_GetLength2;
275 case FBUS_RX_GetLength2:
277 i->FrameLength = i->FrameLength + rx_byte;
278 i->state = FBUS_RX_GetMessage;
283 case FBUS_RX_GetMessage:
285 i->MessageBuffer[i->BufferCount] = rx_byte;
288 if (i->BufferCount > FBUS_MAX_FRAME_LENGTH) {
289 dprintf("FBUS: Message buffer overun - resetting\n");
290 i->state = FBUS_RX_Sync;
294 /* If this is the last byte, it's the checksum. */
296 if (i->BufferCount == i->FrameLength + (i->FrameLength % 2) + 2) {
297 /* Is the checksum correct? */
298 if (i->checksum[0] == i->checksum[1]) {
300 /* Deal with exceptions to the rules - acks and rlp.. */
302 if (i->MessageType == 0x7f) {
303 dprintf("[Received Ack of type %02x, seq: %2x]\n",
304 i->MessageBuffer[0],(unsigned char) i->MessageBuffer[1]);
306 } else { /* Normal message type */
308 /* Add data to the relevant Message buffer */
309 /* having checked the sequence number */
311 m = &flink.messages[i->MessageType];
313 frm_num = i->MessageBuffer[i->FrameLength - 2];
314 seq_num = i->MessageBuffer[i->FrameLength - 1];
317 /* 0x40 in the sequence number indicates first frame of a message */
319 if ((seq_num & 0x40) == 0x40) {
320 /* Fiddle around and malloc some memory */
321 m->MessageLength = 0;
322 m->FramesToGo = frm_num;
323 if (m->Malloced != 0) {
324 free(m->MessageBuffer);
326 m->MessageBuffer = NULL;
328 m->Malloced = frm_num * m->MessageLength;
329 m->MessageBuffer = (char *) malloc(m->Malloced);
331 } else if (m->FramesToGo != frm_num) {
332 dprintf("Missed a frame in a multiframe message.\n");
333 /* FIXME - we should make sure we don't ack the rest etc */
336 if (m->Malloced < m->MessageLength + i->FrameLength) {
337 m->Malloced = m->MessageLength + i->FrameLength;
338 m->MessageBuffer = (char *) realloc(m->MessageBuffer, m->Malloced);
341 memcpy(m->MessageBuffer + m->MessageLength, i->MessageBuffer,
342 i->FrameLength - 2);/* - (i->FrameLength % 2)); */
344 m->MessageLength += i->FrameLength - 2;/* - (i->FrameLength % 2); */
348 /* Finally dispatch if ready */
350 if (m->FramesToGo == 0) {
351 SM_IncomingFunction(statemachine, i->MessageType, m->MessageBuffer, m->MessageLength);
352 free(m->MessageBuffer);
353 m->MessageBuffer = NULL;
357 /* Send an ack (for all for now) */
359 FBUS_TX_SendAck(i->MessageType, seq_num & 0x0f);
363 dprintf("Bad checksum!\n");
365 i->state = FBUS_RX_Sync;
372 /* This is the main loop function which must be called regularly */
373 /* timeout can be used to make it 'busy' or not */
375 GSM_Error FBUS_Loop(struct timeval *timeout)
378 unsigned char buffer[255];
381 res = device_select(timeout);
383 res = device_read(buffer, 255);
384 for (count = 0; count < res; count++)
385 FBUS_RX_StateMachine(buffer[count]);
389 /* This traps errors from device_read */
393 return GE_INTERNALERROR;
401 /* Prepares the message header and sends it, prepends the message start byte
402 (0x1e) and other values according the value specified when called.
403 Calculates checksum and then sends the lot down the pipe... */
405 int FBUS_TX_SendFrame(u8 message_length, u8 message_type, u8 * buffer)
408 u8 out_buffer[FBUS_MAX_TRANSMIT_LENGTH + 5];
409 int count, current = 0;
410 unsigned char checksum;
412 /* FIXME - we should check for the message length ... */
414 /* Now construct the message header. */
416 if (glink->ConnectionType == GCT_Infrared)
417 out_buffer[current++] = FBUS_IR_FRAME_ID; /* Start of the IR frame indicator */
418 else /* ConnectionType == GCT_Serial */
419 out_buffer[current++] = FBUS_FRAME_ID; /* Start of the frame indicator */
421 out_buffer[current++] = FBUS_DEVICE_PHONE; /* Destination */
422 out_buffer[current++] = FBUS_DEVICE_PC; /* Source */
424 out_buffer[current++] = message_type; /* Type */
426 out_buffer[current++] = 0; /* Length */
428 out_buffer[current++] = message_length; /* Length */
430 /* Copy in data if any. */
432 if (message_length != 0) {
433 memcpy(out_buffer + current, buffer, message_length);
434 current += message_length;
437 /* If the message length is odd we should add pad byte 0x00 */
438 if (message_length % 2)
439 out_buffer[current++] = 0x00;
441 /* Now calculate checksums over entire message and append to message. */
446 for (count = 0; count < current; count += 2)
447 checksum ^= out_buffer[count];
449 out_buffer[current++] = checksum;
454 for (count = 1; count < current; count += 2)
455 checksum ^= out_buffer[count];
457 out_buffer[current++] = checksum;
460 fprintf(stderr, _("PC: "));
462 for (count = 0; count < current; count++)
463 fprintf(stderr, "%02x:", out_buffer[count]);
465 fprintf(stderr, "\n");
470 if (device_write(out_buffer, current) != current)
477 /* Main function to send an fbus message */
478 /* Splits up the message into frames if necessary */
480 GSM_Error FBUS_SendMessage(u16 messagesize, u8 messagetype, void *message)
483 u8 seqnum, frame_buffer[FBUS_MAX_CONTENT_LENGTH + 2];
484 u8 nom, lml; /* number of messages, last message len */
487 seqnum = 0x40 + flink.RequestSequenceNumber;
488 flink.RequestSequenceNumber =
489 (flink.RequestSequenceNumber + 1) & 0x07;
491 if (messagesize > FBUS_MAX_CONTENT_LENGTH) {
493 nom = (messagesize + FBUS_MAX_CONTENT_LENGTH - 1)
494 / FBUS_MAX_CONTENT_LENGTH;
495 lml = messagesize - ((nom - 1) * FBUS_MAX_CONTENT_LENGTH);
497 for (i = 0; i < nom - 1; i++) {
499 memcpy(frame_buffer, message + (i * FBUS_MAX_CONTENT_LENGTH),
500 FBUS_MAX_CONTENT_LENGTH);
501 frame_buffer[FBUS_MAX_CONTENT_LENGTH] = nom - i;
502 frame_buffer[FBUS_MAX_CONTENT_LENGTH + 1] = seqnum;
504 FBUS_TX_SendFrame(FBUS_MAX_CONTENT_LENGTH + 2,
505 messagetype, frame_buffer);
507 seqnum = flink.RequestSequenceNumber;
508 flink.RequestSequenceNumber = (flink.RequestSequenceNumber + 1) & 0x07;
511 memcpy(frame_buffer, message + ((nom - 1) * FBUS_MAX_CONTENT_LENGTH), lml);
512 frame_buffer[lml] = 0x01;
513 frame_buffer[lml + 1] = seqnum;
514 FBUS_TX_SendFrame(lml + 2, messagetype, frame_buffer);
518 memcpy(frame_buffer, message, messagesize);
519 frame_buffer[messagesize] = 0x01;
520 frame_buffer[messagesize + 1] = seqnum;
521 FBUS_TX_SendFrame(messagesize + 2, messagetype,
528 int FBUS_TX_SendAck(u8 message_type, u8 message_seq)
531 unsigned char request[2];
533 request[0] = message_type;
534 request[1] = message_seq;
536 dprintf("[Sending Ack of type %02x, seq: %x]\n",message_type, message_seq);
538 return FBUS_TX_SendFrame(2, 0x7f, request);
542 /* Initialise variables and start the link */
543 /* newlink is actually part of state - but the link code should not anything about state */
544 /* state is only passed around to allow for muliple state machines (one day...) */
546 GSM_Error FBUS_Initialise(GSM_Link *newlink, GSM_Statemachine *state, int type)
548 unsigned char init_char = 0x55;
551 if (type > 2) return GE_DEVICEOPENFAILED;
552 /* 'Copy in' the global structures */
554 statemachine = state;
556 /* Fill in the link functions */
557 glink->Loop = &FBUS_Loop;
558 glink->SendMessage = &FBUS_SendMessage;
560 /* Check for a valid init length */
561 if (glink->InitLength == 0)
562 glink->InitLength = 250;
564 /* Start up the link */
565 flink.RequestSequenceNumber = 0;
567 if (glink->ConnectionType == GCT_Infrared) {
569 return GE_DEVICEOPENFAILED;
570 } else { /* ConnectionType == GCT_Serial */
571 /* FBUS_OpenSerial(0) - try dau-9p
572 * FBUS_OpenSerial(n != 0) - try dlr-3p */
573 if (!FBUS_OpenSerial(type))
574 return GE_DEVICEOPENFAILED;
577 /* Send init string to phone, this is a bunch of 0x55 characters. Timing is
579 /* I believe that we need/can do this for any phone to get the UART synced */
581 for (count = 0; count < glink->InitLength; count++) {
583 device_write(&init_char, 1);
587 flink.i.state = FBUS_RX_Sync;
588 flink.i.BufferCount = 0;
589 for (count = 0; count < FBUS_MAX_MESSAGE_TYPES; count++) {
590 flink.messages[count].Malloced = 0;
591 flink.messages[count].FramesToGo = 0;
592 flink.messages[count].MessageLength = 0;