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.2.1 2001/11/27 22:48:37 short
21 Update: orig2001_11_27_05_17 -> orig2001_11_27_22_58
23 Revision 1.1.1.2 2001/11/27 22:01:16 short
24 :pserver:cvs@pserver.samba.org:/cvsroot - gnokii - Tue Nov 27 22:58 CET 2001
26 Revision 1.14 2001/11/27 12:19:01 pkot
27 Cleanup, indentation, ANSI complaint preprocesor symbols (Jan Kratochvil, me)
29 Revision 1.13 2001/11/17 20:14:15 pkot
30 Nasty bug with counting message length. Workaround applied. Needs fixing.
32 Revision 1.12 2001/11/15 12:04:05 pkot
33 Faster initialization for 6100 series (don't check for dlr3 cable)
35 Revision 1.11 2001/09/09 21:45:49 machek
36 Cleanups from Ladislav Michl <ladis@psi.cz>:
38 *) do *not* internationalize debug messages
40 *) some whitespace fixes, do not use //
42 *) break is unneccessary after return
44 Revision 1.10 2001/08/20 23:27:37 pkot
45 Add hardware shakehand to the link layer (Manfred Jonsson)
47 Revision 1.9 2001/05/28 09:25:16 pkot
48 Fixed autodetecting of the cable type in 6110 and 7110 series. DLR-3 is
49 tried first now. Seems to work ok with either 6130 or 6210.
51 Revision 1.8 2001/05/07 16:24:03 pkot
52 DLR-3P temporary fix. How should I do it better?
54 Revision 1.7 2001/03/22 16:17:05 chris
55 Tidy-ups and fixed gnokii/Makefile and gnokii/ChangeLog which I somehow corrupted.
57 Revision 1.6 2001/03/21 23:36:05 chris
58 Added the statemachine
59 This will break gnokii --identify and --monitor except for 6210/7110
61 Revision 1.5 2001/03/19 23:44:56 pkot
64 Revision 1.4 2001/03/13 01:24:02 pkot
65 Code cleanup - no warnings during compilation
67 Revision 1.3 2001/03/13 01:23:18 pkot
68 Windows updates (Manfred Jonsson)
70 Revision 1.2 2001/03/11 11:18:39 machek
71 Made fbus link_dispatch (and fixed minor memory leak)
73 Revision 1.1 2001/02/21 19:57:06 chris
74 More fiddling with the directory layout
76 Revision 1.1 2001/02/16 14:29:52 chris
77 Restructure of common/. Fixed a problem in fbus-phonet.c
78 Lots of dprintfs for Marcin
79 Any size xpm can now be loaded (eg for 7110 startup logos)
80 nk7110 code detects 7110/6210 and alters startup logo size to suit
81 Moved Marcin's extended phonebook code into gnokii.c
83 Revision 1.3 2001/02/06 21:15:34 chris
84 Preliminary irda support for 7110 etc. Not well tested!
86 Revision 1.2 2001/02/03 23:56:14 chris
87 Start of work on irda support (now we just need fbus-irda.c!)
88 Proper unicode support in 7110 code (from pkot)
90 Revision 1.1 2001/01/14 22:46:59 chris
91 Preliminary 7110 support (dlr9 only) and the beginnings of a new structure
96 /* System header files */
102 /* Various header file */
106 #include "gsm-common.h"
107 #include "gsm-ringtones.h"
108 #include "gsm-networks.h"
109 #include "gsm-statemachine.h"
110 #include "links/utils.h"
115 # include "win32/winserial.h"
116 # define device_write(a, b) WriteCommBlock(a, b)
117 # define device_read(a, b) ReadCommBlock(a, b)
118 # define sleep(x) Sleep((x) * 1000)
119 # define usleep(x) Sleep(((x) < 1000) ? 1 : ((x) / 1000))
122 #define __links_fbus_c
123 #include "links/fbus.h"
125 /* FIXME - pass device_* the link stuff?? */
126 /* FIXME - win32 stuff! */
131 static GSM_Link *glink;
132 static GSM_Statemachine *statemachine;
133 static FBUS_Link flink; /* FBUS specific stuff, internal to this file */
136 /*--------------------------------------------*/
138 bool FBUS_OpenSerial(bool dlr3)
143 if (OpenConnection(glink->PortDevice, FBUS_RX_StateMachine, NULL)) {
145 if (!device_open(glink->PortDevice, false, false, false, GCT_Serial)) {
147 perror(_("Couldn't open FBUS device"));
150 device_changespeed(115200);
152 /* clearing the RTS bit and setting the DTR bit */
153 device_setdtrrts((1-dlr3), 0);
159 /* RX_State machine for receive handling. Called once for each character
160 received from the phone. */
162 void FBUS_RX_StateMachine(unsigned char rx_byte)
165 struct timeval time_diff;
166 FBUS_IncomingFrame *i = &flink.i;
167 int frm_num, seq_num;
168 FBUS_IncomingMessage *m;
171 if (isprint(rx_byte))
172 dprintf("[%02x%c]", (unsigned char) rx_byte, rx_byte);
174 dprintf("[%02x ]", (unsigned char) rx_byte);
177 /* XOR the byte with the current checksum */
178 i->checksum[i->BufferCount & 1] ^= rx_byte;
182 /* Messages from the phone start with an 0x1e (cable) or 0x1c (IR).
183 We use this to "synchronise" with the incoming data stream. However,
184 if we see something else, we assume we have lost sync and we require
185 a gap of at least 5ms before we start looking again. This is because
186 the data part of the frame could contain a byte which looks like the
189 case FBUS_RX_Discarding:
190 gettimeofday(&i->time_now, NULL);
191 timersub(&i->time_now, &i->time_last, &time_diff);
192 if (time_diff.tv_sec == 0 && time_diff.tv_usec < 5000) {
193 i->time_last = i->time_now; /* no gap seen, continue discarding */
197 /* else fall through to... */
200 if (glink->ConnectionType == GCT_Infrared) {
201 if (rx_byte == FBUS_IR_FRAME_ID) {
202 /* Initialize checksums. */
203 i->checksum[0] = FBUS_IR_FRAME_ID;
205 i->state = FBUS_RX_GetDestination;
207 /* Lost frame sync */
208 i->state = FBUS_RX_Discarding;
209 gettimeofday(&i->time_last, NULL);
212 } else { /* glink->ConnectionType == GCT_Serial */
213 if (rx_byte == FBUS_FRAME_ID) {
214 /* Initialize checksums. */
215 i->checksum[0] = FBUS_FRAME_ID;
217 i->state = FBUS_RX_GetDestination;
219 /* Lost frame sync */
220 i->state = FBUS_RX_Discarding;
221 gettimeofday(&i->time_last, NULL);
227 case FBUS_RX_GetDestination:
229 i->MessageDestination = rx_byte;
230 i->state = FBUS_RX_GetSource;
232 /* When there is a checksum error and things get out of sync we have to manage to resync */
233 /* If doing a data call at the time, finding a 0x1e etc is really quite likely in the data stream */
234 /* Then all sorts of horrible things happen because the packet length etc is wrong... */
235 /* Therefore we test here for a destination of 0x0c and return to the top if it is not */
237 if (rx_byte != 0x0c) {
238 i->state = FBUS_RX_Sync;
239 dprintf("The fbus stream is out of sync - expected 0x0c, got %2x\n", rx_byte);
244 case FBUS_RX_GetSource:
246 i->MessageSource = rx_byte;
247 i->state = FBUS_RX_GetType;
249 /* Source should be 0x00 */
251 if (rx_byte != 0x00) {
252 i->state = FBUS_RX_Sync;
253 dprintf("The fbus stream is out of sync - expected 0x00, got %2x\n",rx_byte);
258 case FBUS_RX_GetType:
260 i->MessageType = rx_byte;
261 i->state = FBUS_RX_GetLength1;
265 case FBUS_RX_GetLength1:
267 i->FrameLength = rx_byte << 8;
268 i->state = FBUS_RX_GetLength2;
272 case FBUS_RX_GetLength2:
274 i->FrameLength = i->FrameLength + rx_byte;
275 i->state = FBUS_RX_GetMessage;
280 case FBUS_RX_GetMessage:
282 i->MessageBuffer[i->BufferCount] = rx_byte;
285 if (i->BufferCount > FBUS_MAX_FRAME_LENGTH) {
286 dprintf("FBUS: Message buffer overun - resetting\n");
287 i->state = FBUS_RX_Sync;
291 /* If this is the last byte, it's the checksum. */
293 if (i->BufferCount == i->FrameLength + (i->FrameLength % 2) + 2) {
294 /* Is the checksum correct? */
295 if (i->checksum[0] == i->checksum[1]) {
297 /* Deal with exceptions to the rules - acks and rlp.. */
299 if (i->MessageType == 0x7f) {
300 dprintf("[Received Ack of type %02x, seq: %2x]\n",
301 i->MessageBuffer[0],(unsigned char) i->MessageBuffer[1]);
303 } else { /* Normal message type */
305 /* Add data to the relevant Message buffer */
306 /* having checked the sequence number */
308 m = &flink.messages[i->MessageType];
310 frm_num = i->MessageBuffer[i->FrameLength - 2];
311 seq_num = i->MessageBuffer[i->FrameLength - 1];
314 /* 0x40 in the sequence number indicates first frame of a message */
316 if ((seq_num & 0x40) == 0x40) {
317 /* Fiddle around and malloc some memory */
318 m->MessageLength = 0;
319 m->FramesToGo = frm_num;
320 if (m->Malloced != 0) {
321 free(m->MessageBuffer);
323 m->MessageBuffer = NULL;
325 m->Malloced = frm_num * m->MessageLength;
326 m->MessageBuffer = (char *) malloc(m->Malloced);
328 } else if (m->FramesToGo != frm_num) {
329 dprintf("Missed a frame in a multiframe message.\n");
330 /* FIXME - we should make sure we don't ack the rest etc */
333 if (m->Malloced < m->MessageLength + i->FrameLength) {
334 m->Malloced = m->MessageLength + i->FrameLength;
335 m->MessageBuffer = (char *) realloc(m->MessageBuffer, m->Malloced);
338 memcpy(m->MessageBuffer + m->MessageLength, i->MessageBuffer,
339 i->FrameLength - 2);/* - (i->FrameLength % 2)); */
341 m->MessageLength += i->FrameLength - 2;/* - (i->FrameLength % 2); */
345 /* Finally dispatch if ready */
347 if (m->FramesToGo == 0) {
348 SM_IncomingFunction(statemachine, i->MessageType, m->MessageBuffer, m->MessageLength);
349 free(m->MessageBuffer);
350 m->MessageBuffer = NULL;
354 /* Send an ack (for all for now) */
356 FBUS_TX_SendAck(i->MessageType, seq_num & 0x0f);
360 dprintf("Bad checksum!\n");
362 i->state = FBUS_RX_Sync;
369 /* This is the main loop function which must be called regularly */
370 /* timeout can be used to make it 'busy' or not */
372 GSM_Error FBUS_Loop(struct timeval *timeout)
375 unsigned char buffer[255];
378 res = device_select(timeout);
380 res = device_read(buffer, 255);
381 for (count = 0; count < res; count++)
382 FBUS_RX_StateMachine(buffer[count]);
386 /* This traps errors from device_read */
390 return GE_INTERNALERROR;
398 /* Prepares the message header and sends it, prepends the message start byte
399 (0x1e) and other values according the value specified when called.
400 Calculates checksum and then sends the lot down the pipe... */
402 int FBUS_TX_SendFrame(u8 message_length, u8 message_type, u8 * buffer)
405 u8 out_buffer[FBUS_MAX_TRANSMIT_LENGTH + 5];
406 int count, current = 0;
407 unsigned char checksum;
409 /* FIXME - we should check for the message length ... */
411 /* Now construct the message header. */
413 if (glink->ConnectionType == GCT_Infrared)
414 out_buffer[current++] = FBUS_IR_FRAME_ID; /* Start of the IR frame indicator */
415 else /* ConnectionType == GCT_Serial */
416 out_buffer[current++] = FBUS_FRAME_ID; /* Start of the frame indicator */
418 out_buffer[current++] = FBUS_DEVICE_PHONE; /* Destination */
419 out_buffer[current++] = FBUS_DEVICE_PC; /* Source */
421 out_buffer[current++] = message_type; /* Type */
423 out_buffer[current++] = 0; /* Length */
425 out_buffer[current++] = message_length; /* Length */
427 /* Copy in data if any. */
429 if (message_length != 0) {
430 memcpy(out_buffer + current, buffer, message_length);
431 current += message_length;
434 /* If the message length is odd we should add pad byte 0x00 */
435 if (message_length % 2)
436 out_buffer[current++] = 0x00;
438 /* Now calculate checksums over entire message and append to message. */
443 for (count = 0; count < current; count += 2)
444 checksum ^= out_buffer[count];
446 out_buffer[current++] = checksum;
451 for (count = 1; count < current; count += 2)
452 checksum ^= out_buffer[count];
454 out_buffer[current++] = checksum;
457 fprintf(stderr, _("PC: "));
459 for (count = 0; count < current; count++)
460 fprintf(stderr, "%02x:", out_buffer[count]);
462 fprintf(stderr, "\n");
467 if (device_write(out_buffer, current) != current)
474 /* Main function to send an fbus message */
475 /* Splits up the message into frames if necessary */
477 GSM_Error FBUS_SendMessage(u16 messagesize, u8 messagetype, void *message)
480 u8 seqnum, frame_buffer[FBUS_MAX_CONTENT_LENGTH + 2];
481 u8 nom, lml; /* number of messages, last message len */
484 seqnum = 0x40 + flink.RequestSequenceNumber;
485 flink.RequestSequenceNumber =
486 (flink.RequestSequenceNumber + 1) & 0x07;
488 if (messagesize > FBUS_MAX_CONTENT_LENGTH) {
490 nom = (messagesize + FBUS_MAX_CONTENT_LENGTH - 1)
491 / FBUS_MAX_CONTENT_LENGTH;
492 lml = messagesize - ((nom - 1) * FBUS_MAX_CONTENT_LENGTH);
494 for (i = 0; i < nom - 1; i++) {
496 memcpy(frame_buffer, message + (i * FBUS_MAX_CONTENT_LENGTH),
497 FBUS_MAX_CONTENT_LENGTH);
498 frame_buffer[FBUS_MAX_CONTENT_LENGTH] = nom - i;
499 frame_buffer[FBUS_MAX_CONTENT_LENGTH + 1] = seqnum;
501 FBUS_TX_SendFrame(FBUS_MAX_CONTENT_LENGTH + 2,
502 messagetype, frame_buffer);
504 seqnum = flink.RequestSequenceNumber;
505 flink.RequestSequenceNumber = (flink.RequestSequenceNumber + 1) & 0x07;
508 memcpy(frame_buffer, message + ((nom - 1) * FBUS_MAX_CONTENT_LENGTH), lml);
509 frame_buffer[lml] = 0x01;
510 frame_buffer[lml + 1] = seqnum;
511 FBUS_TX_SendFrame(lml + 2, messagetype, frame_buffer);
515 memcpy(frame_buffer, message, messagesize);
516 frame_buffer[messagesize] = 0x01;
517 frame_buffer[messagesize + 1] = seqnum;
518 FBUS_TX_SendFrame(messagesize + 2, messagetype,
525 int FBUS_TX_SendAck(u8 message_type, u8 message_seq)
528 unsigned char request[2];
530 request[0] = message_type;
531 request[1] = message_seq;
533 dprintf("[Sending Ack of type %02x, seq: %x]\n",message_type, message_seq);
535 return FBUS_TX_SendFrame(2, 0x7f, request);
539 /* Initialise variables and start the link */
540 /* newlink is actually part of state - but the link code should not anything about state */
541 /* state is only passed around to allow for muliple state machines (one day...) */
543 GSM_Error FBUS_Initialise(GSM_Link *newlink, GSM_Statemachine *state, int type)
545 unsigned char init_char = 0x55;
548 if (type > 2) return GE_DEVICEOPENFAILED;
549 /* 'Copy in' the global structures */
551 statemachine = state;
553 /* Fill in the link functions */
554 glink->Loop = &FBUS_Loop;
555 glink->SendMessage = &FBUS_SendMessage;
557 /* Check for a valid init length */
558 if (glink->InitLength == 0)
559 glink->InitLength = 250;
561 /* Start up the link */
562 flink.RequestSequenceNumber = 0;
564 if (glink->ConnectionType == GCT_Infrared) {
566 return GE_DEVICEOPENFAILED;
567 } else { /* ConnectionType == GCT_Serial */
568 /* FBUS_OpenSerial(0) - try dau-9p
569 * FBUS_OpenSerial(n != 0) - try dlr-3p */
570 if (!FBUS_OpenSerial(type))
571 return GE_DEVICEOPENFAILED;
574 /* Send init string to phone, this is a bunch of 0x55 characters. Timing is
576 /* I believe that we need/can do this for any phone to get the UART synced */
578 for (count = 0; count < glink->InitLength; count++) {
580 device_write(&init_char, 1);
584 flink.i.state = FBUS_RX_Sync;
585 flink.i.BufferCount = 0;
586 for (count = 0; count < FBUS_MAX_MESSAGE_TYPES; count++) {
587 flink.messages[count].Malloced = 0;
588 flink.messages[count].FramesToGo = 0;
589 flink.messages[count].MessageLength = 0;