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.3 2002/04/03 00:08:07 short
21 Found in "gnokii-working" directory, some November-patches version
23 Revision 1.11 2001/09/09 21:45:49 machek
24 Cleanups from Ladislav Michl <ladis@psi.cz>:
26 *) do *not* internationalize debug messages
28 *) some whitespace fixes, do not use //
30 *) break is unneccessary after return
32 Revision 1.10 2001/08/20 23:27:37 pkot
33 Add hardware shakehand to the link layer (Manfred Jonsson)
35 Revision 1.9 2001/05/28 09:25:16 pkot
36 Fixed autodetecting of the cable type in 6110 and 7110 series. DLR-3 is
37 tried first now. Seems to work ok with either 6130 or 6210.
39 Revision 1.8 2001/05/07 16:24:03 pkot
40 DLR-3P temporary fix. How should I do it better?
42 Revision 1.7 2001/03/22 16:17:05 chris
43 Tidy-ups and fixed gnokii/Makefile and gnokii/ChangeLog which I somehow corrupted.
45 Revision 1.6 2001/03/21 23:36:05 chris
46 Added the statemachine
47 This will break gnokii --identify and --monitor except for 6210/7110
49 Revision 1.5 2001/03/19 23:44:56 pkot
52 Revision 1.4 2001/03/13 01:24:02 pkot
53 Code cleanup - no warnings during compilation
55 Revision 1.3 2001/03/13 01:23:18 pkot
56 Windows updates (Manfred Jonsson)
58 Revision 1.2 2001/03/11 11:18:39 machek
59 Made fbus link_dispatch (and fixed minor memory leak)
61 Revision 1.1 2001/02/21 19:57:06 chris
62 More fiddling with the directory layout
64 Revision 1.1 2001/02/16 14:29:52 chris
65 Restructure of common/. Fixed a problem in fbus-phonet.c
66 Lots of dprintfs for Marcin
67 Any size xpm can now be loaded (eg for 7110 startup logos)
68 nk7110 code detects 7110/6210 and alters startup logo size to suit
69 Moved Marcin's extended phonebook code into gnokii.c
71 Revision 1.3 2001/02/06 21:15:34 chris
72 Preliminary irda support for 7110 etc. Not well tested!
74 Revision 1.2 2001/02/03 23:56:14 chris
75 Start of work on irda support (now we just need fbus-irda.c!)
76 Proper unicode support in 7110 code (from pkot)
78 Revision 1.1 2001/01/14 22:46:59 chris
79 Preliminary 7110 support (dlr9 only) and the beginnings of a new structure
84 /* System header files */
90 /* Various header file */
94 #include "gsm-common.h"
95 #include "gsm-ringtones.h"
96 #include "gsm-networks.h"
97 #include "gsm-statemachine.h"
98 #include "links/utils.h"
103 #include "win32/winserial.h"
104 #define device_write(a, b) WriteCommBlock(a, b)
105 #define device_read(a, b) ReadCommBlock(a, b)
106 #define sleep(x) Sleep((x) * 1000)
107 #define usleep(x) Sleep(((x) < 1000) ? 1 : ((x) / 1000))
110 #define __links_fbus_c
111 #include "links/fbus.h"
113 /* FIXME - pass device_* the link stuff?? */
114 /* FIXME - win32 stuff! */
119 static GSM_Link *glink;
120 static GSM_Statemachine *FBUS_statemachine;
121 static FBUS_Link flink; /* FBUS specific stuff, internal to this file */
124 /*--------------------------------------------*/
126 bool FBUS_OpenSerial(bool dlr3)
131 if (OpenConnection(glink->PortDevice, FBUS_RX_StateMachine, NULL)) {
133 if (!device_open(glink->PortDevice, false, false, false, GCT_Serial)) {
135 perror(_("Couldn't open FBUS device"));
138 device_changespeed(115200);
140 /* clearing the RTS bit and setting the DTR bit */
141 device_setdtrrts((1-dlr3), 0);
147 /* RX_State machine for receive handling. Called once for each character
148 received from the phone. */
150 void FBUS_RX_StateMachine(unsigned char rx_byte)
153 struct timeval time_diff;
154 FBUS_IncomingFrame *i = &flink.i;
155 int frm_num, seq_num;
156 FBUS_IncomingMessage *m;
159 if (isprint(rx_byte))
160 fprintf(stderr, "[%02x%c]", (unsigned char) rx_byte, rx_byte);
162 fprintf(stderr, "[%02x ]", (unsigned char) rx_byte);
165 /* XOR the byte with the current checksum */
166 i->checksum[i->BufferCount & 1] ^= rx_byte;
170 /* Messages from the phone start with an 0x1e (cable) or 0x1c (IR).
171 We use this to "synchronise" with the incoming data stream. However,
172 if we see something else, we assume we have lost sync and we require
173 a gap of at least 5ms before we start looking again. This is because
174 the data part of the frame could contain a byte which looks like the
177 case FBUS_RX_Discarding:
178 gettimeofday(&i->time_now, NULL);
179 timersub(&i->time_now, &i->time_last, &time_diff);
180 if (time_diff.tv_sec == 0 && time_diff.tv_usec < 5000) {
181 i->time_last = i->time_now; /* no gap seen, continue discarding */
185 /* else fall through to... */
188 if (glink->ConnectionType == GCT_Infrared) {
189 if (rx_byte == FBUS_IR_FRAME_ID) {
190 /* Initialize checksums. */
191 i->checksum[0] = FBUS_IR_FRAME_ID;
193 i->state = FBUS_RX_GetDestination;
195 /* Lost frame sync */
196 i->state = FBUS_RX_Discarding;
197 gettimeofday(&i->time_last, NULL);
200 } else { /* glink->ConnectionType == GCT_Serial */
201 if (rx_byte == FBUS_FRAME_ID) {
202 /* Initialize checksums. */
203 i->checksum[0] = FBUS_FRAME_ID;
205 i->state = FBUS_RX_GetDestination;
207 /* Lost frame sync */
208 i->state = FBUS_RX_Discarding;
209 gettimeofday(&i->time_last, NULL);
215 case FBUS_RX_GetDestination:
217 i->MessageDestination = rx_byte;
218 i->state = FBUS_RX_GetSource;
220 /* When there is a checksum error and things get out of sync we have to manage to resync */
221 /* If doing a data call at the time, finding a 0x1e etc is really quite likely in the data stream */
222 /* Then all sorts of horrible things happen because the packet length etc is wrong... */
223 /* Therefore we test here for a destination of 0x0c and return to the top if it is not */
225 if (rx_byte != 0x0c) {
226 i->state = FBUS_RX_Sync;
227 dprintf("The fbus stream is out of sync - expected 0x0c, got %2x\n", rx_byte);
232 case FBUS_RX_GetSource:
234 i->MessageSource = rx_byte;
235 i->state = FBUS_RX_GetType;
237 /* Source should be 0x00 */
239 if (rx_byte != 0x00) {
240 i->state = FBUS_RX_Sync;
241 dprintf("The fbus stream is out of sync - expected 0x00, got %2x\n",rx_byte);
246 case FBUS_RX_GetType:
248 i->MessageType = rx_byte;
249 i->state = FBUS_RX_GetLength1;
253 case FBUS_RX_GetLength1:
255 i->FrameLength = rx_byte << 8;
256 i->state = FBUS_RX_GetLength2;
260 case FBUS_RX_GetLength2:
262 i->FrameLength = i->FrameLength + rx_byte;
263 i->state = FBUS_RX_GetMessage;
268 case FBUS_RX_GetMessage:
270 i->MessageBuffer[i->BufferCount] = rx_byte;
273 if (i->BufferCount > FBUS_MAX_FRAME_LENGTH) {
274 dprintf("FBUS: Message buffer overun - resetting\n");
275 i->state = FBUS_RX_Sync;
279 /* If this is the last byte, it's the checksum. */
281 if (i->BufferCount == i->FrameLength + (i->FrameLength % 2) + 2) {
282 /* Is the checksum correct? */
283 if (i->checksum[0] == i->checksum[1]) {
285 /* Deal with exceptions to the rules - acks and rlp.. */
287 if (i->MessageType == 0x7f) {
288 dprintf("[Received Ack of type %02x, seq: %2x]\n",
289 i->MessageBuffer[0],(unsigned char) i->MessageBuffer[1]);
291 } else { /* Normal message type */
293 /* Add data to the relevant Message buffer */
294 /* having checked the sequence number */
296 m = &flink.messages[i->MessageType];
298 frm_num = i->MessageBuffer[i->FrameLength - 2];
299 seq_num = i->MessageBuffer[i->FrameLength - 1];
302 /* 0x40 in the sequence number indicates first frame of a message */
304 if ((seq_num & 0x40) == 0x40) {
305 /* Fiddle around and malloc some memory */
306 m->MessageLength = 0;
307 m->FramesToGo = frm_num;
308 if (m->Malloced != 0) {
309 free(m->MessageBuffer);
311 m->MessageBuffer = NULL;
313 m->Malloced = frm_num *m->MessageLength;
314 m->MessageBuffer = (char *) malloc(m->Malloced);
316 } else if (m->FramesToGo != frm_num) {
317 fprintf(stdout, "Missed a frame in a multiframe message.\n");
318 /* FIXME - we should make sure we don't ack the rest etc */
321 if (m->Malloced < m->MessageLength + i->FrameLength) {
322 m->Malloced = m->MessageLength + i->FrameLength;
323 m->MessageBuffer = (char *) realloc(m->MessageBuffer, m->Malloced);
326 memcpy(m->MessageBuffer + m->MessageLength, i->MessageBuffer,
327 i->FrameLength - 2 - (i->FrameLength % 2));
329 m->MessageLength += i->FrameLength - 2 - (i->FrameLength % 2);
333 /* Finally dispatch if ready */
335 if (m->FramesToGo == 0) {
336 SM_IncomingFunction(FBUS_statemachine, i->MessageType, m->MessageBuffer, m->MessageLength);
337 free(m->MessageBuffer);
338 m->MessageBuffer = NULL;
342 /* Send an ack (for all for now) */
344 FBUS_TX_SendAck(i->MessageType, seq_num & 0x0f);
348 dprintf("Bad checksum!\n");
350 i->state = FBUS_RX_Sync;
357 /* This is the main loop function which must be called regularly */
358 /* timeout can be used to make it 'busy' or not */
360 GSM_Error FBUS_Loop(struct timeval *timeout)
363 unsigned char buffer[255];
366 res = device_select(timeout);
368 res = device_read(buffer, 255);
369 for (count = 0; count < res; count++)
370 FBUS_RX_StateMachine(buffer[count]);
374 /* This traps errors from device_read */
378 return GE_INTERNALERROR;
386 /* Prepares the message header and sends it, prepends the message start byte
387 (0x1e) and other values according the value specified when called.
388 Calculates checksum and then sends the lot down the pipe... */
390 int FBUS_TX_SendFrame(u8 message_length, u8 message_type, u8 * buffer)
393 u8 out_buffer[FBUS_MAX_TRANSMIT_LENGTH + 5];
394 int count, current = 0;
395 unsigned char checksum;
397 /* FIXME - we should check for the message length ... */
399 /* Now construct the message header. */
401 if (glink->ConnectionType == GCT_Infrared)
402 out_buffer[current++] = FBUS_IR_FRAME_ID; /* Start of the IR frame indicator */
403 else /* ConnectionType == GCT_Serial */
404 out_buffer[current++] = FBUS_FRAME_ID; /* Start of the frame indicator */
406 out_buffer[current++] = FBUS_DEVICE_PHONE; /* Destination */
407 out_buffer[current++] = FBUS_DEVICE_PC; /* Source */
409 out_buffer[current++] = message_type; /* Type */
411 out_buffer[current++] = 0; /* Length */
413 out_buffer[current++] = message_length; /* Length */
415 /* Copy in data if any. */
417 if (message_length != 0) {
418 memcpy(out_buffer + current, buffer, message_length);
419 current += message_length;
422 /* If the message length is odd we should add pad byte 0x00 */
423 if (message_length % 2)
424 out_buffer[current++] = 0x00;
426 /* Now calculate checksums over entire message and append to message. */
431 for (count = 0; count < current; count += 2)
432 checksum ^= out_buffer[count];
434 out_buffer[current++] = checksum;
439 for (count = 1; count < current; count += 2)
440 checksum ^= out_buffer[count];
442 out_buffer[current++] = checksum;
445 fprintf(stderr, _("PC: "));
447 for (count = 0; count < current; count++)
448 fprintf(stderr, "%02x:", out_buffer[count]);
450 fprintf(stderr, "\n");
455 if (device_write(out_buffer, current) != current)
462 /* Main function to send an fbus message */
463 /* Splits up the message into frames if necessary */
465 GSM_Error FBUS_SendMessage(u16 messagesize, u8 messagetype, void *message)
468 u8 seqnum, frame_buffer[FBUS_MAX_CONTENT_LENGTH + 2];
469 u8 nom, lml; /* number of messages, last message len */
472 seqnum = 0x40 + flink.RequestSequenceNumber;
473 flink.RequestSequenceNumber =
474 (flink.RequestSequenceNumber + 1) & 0x07;
476 if (messagesize > FBUS_MAX_CONTENT_LENGTH) {
478 nom = (messagesize + FBUS_MAX_CONTENT_LENGTH - 1)
479 / FBUS_MAX_CONTENT_LENGTH;
480 lml = messagesize - ((nom - 1) * FBUS_MAX_CONTENT_LENGTH);
482 for (i = 0; i < nom - 1; i++) {
484 memcpy(frame_buffer, message + (i * FBUS_MAX_CONTENT_LENGTH),
485 FBUS_MAX_CONTENT_LENGTH);
486 frame_buffer[FBUS_MAX_CONTENT_LENGTH] = nom - i;
487 frame_buffer[FBUS_MAX_CONTENT_LENGTH + 1] = seqnum;
489 FBUS_TX_SendFrame(FBUS_MAX_CONTENT_LENGTH + 2,
490 messagetype, frame_buffer);
492 seqnum = flink.RequestSequenceNumber;
493 flink.RequestSequenceNumber = (flink.RequestSequenceNumber + 1) & 0x07;
496 memcpy(frame_buffer, message + ((nom - 1) * FBUS_MAX_CONTENT_LENGTH), lml);
497 frame_buffer[lml] = 0x01;
498 frame_buffer[lml + 1] = seqnum;
499 FBUS_TX_SendFrame(lml + 2, messagetype, frame_buffer);
503 memcpy(frame_buffer, message, messagesize);
504 frame_buffer[messagesize] = 0x01;
505 frame_buffer[messagesize + 1] = seqnum;
506 FBUS_TX_SendFrame(messagesize + 2, messagetype,
513 int FBUS_TX_SendAck(u8 message_type, u8 message_seq)
516 unsigned char request[2];
518 request[0] = message_type;
519 request[1] = message_seq;
521 dprintf("[Sending Ack of type %02x, seq: %x]\n",message_type, message_seq);
523 return FBUS_TX_SendFrame(2, 0x7f, request);
527 /* Initialise variables and start the link */
528 /* newlink is actually part of state - but the link code should not anything about state */
529 /* state is only passed around to allow for muliple state machines (one day...) */
531 GSM_Error FBUS_Initialise(GSM_Link *newlink, GSM_Statemachine *state)
533 unsigned char init_char = 0x55;
538 if (try > 2) return GE_DEVICEOPENFAILED;
539 /* 'Copy in' the global structures */
541 FBUS_statemachine = state;
543 /* Fill in the link functions */
544 glink->Loop = &FBUS_Loop;
545 glink->SendMessage = &FBUS_SendMessage;
547 /* Check for a valid init length */
548 if (glink->InitLength == 0)
549 glink->InitLength = 250;
551 /* Start up the link */
552 flink.RequestSequenceNumber = 0;
554 if (glink->ConnectionType == GCT_Infrared) {
556 return GE_DEVICEOPENFAILED;
557 } else { /* ConnectionType == GCT_Serial */
558 /* FBUS_OpenSerial(0) - try dau-9p
559 * FBUS_OpenSerial(n != 0) - try dlr-3p */
560 if (!FBUS_OpenSerial(2 - try))
561 return GE_DEVICEOPENFAILED;
564 /* Send init string to phone, this is a bunch of 0x55 characters. Timing is
566 /* I believe that we need/can do this for any phone to get the UART synced */
568 for (count = 0; count < glink->InitLength; count++) {
570 device_write(&init_char, 1);
574 flink.i.state = FBUS_RX_Sync;
575 flink.i.BufferCount = 0;
576 for (count = 0; count < FBUS_MAX_MESSAGE_TYPES; count++) {
577 flink.messages[count].Malloced = 0;
578 flink.messages[count].FramesToGo = 0;
579 flink.messages[count].MessageLength = 0;