5 A Linux/Unix toolset and driver for Nokia mobile phones.
7 Released under the terms of the GNU GPL, see file COPYING for more details.
9 This file provides an API for support for FBUS protocol
15 /* "Turn on" prototypes in fbus.h */
18 /* System header files */
25 #include "misc_win32.h"
30 /* Various header file */
31 #include "devices/device.h"
33 #include "protocol/fbus.h"
34 #include "protocol/at.h"
35 #include "newmodules/newat.h"
37 #include "newmodules/n6110.h"
41 static GSM_Error FBUS_Initialise(char *port_device, char *initlength,
42 GSM_ConnectionType connection,
43 void (*rlp_callback)(RLP_F96Frame *frame));
45 static int FBUS_SendMessage(u16 message_length, u8 message_type, u8 *buffer);
46 static int FBUS_SendFrame(u16 message_length, u8 message_type, u8 *buffer);
47 static void FBUS_Terminate(void);
48 static void FBUS_RX_StateMachine(unsigned char rx_byte);
50 GSM_Protocol FBUS_Functions = {
60 static enum FBUS_RX_States RX_State;
62 static u8 MessageDestination, MessageSource;
64 static u16 BufferCount;
66 static u16 MessageLength, MultiMessageLength;
68 static bool RX_Multiple = false;
70 static u8 MessageType,MultiMessageType;
72 static u8 MessageBuffer[FBUS_MAX_RECEIVE_LENGTH * 6],MultiMessageBuffer[FBUS_MAX_RECEIVE_LENGTH * 6];
74 static u8 RequestSequenceNumber = 0x00;
77 static char *N61_PrintDevice(int Device)
81 case FBUS_DEVICE_PHONE:return _("Phone");
82 case FBUS_DEVICE_PC :return _("PC");
83 default :return _("Unknown");
88 /* N61_RX_DisplayMessage is called when a message we don't know about is
89 received so that the user can see what is going back and forth, and perhaps
90 shed some more light/explain another message type! */
91 static void N61_RX_DisplayMessage()
94 fprintf(stdout, _("Msg Dest: %s\n"), N61_PrintDevice(MessageDestination));
95 fprintf(stdout, _("Msg Source: %s\n"), N61_PrintDevice(MessageSource));
96 fprintf(stdout, _("Msg Type: %02x\n"), MessageType);
98 hexdump(MessageLength-2,MessageBuffer);
101 AppendLog(MessageBuffer,MessageLength-2,true);
104 /* Prepares the message header and sends it, prepends the message start byte
105 (0x1e) and other values according the value specified when called.
106 Calculates checksum and then sends the lot down the pipe... */
107 int FBUS_SendFrame(u16 message_length, u8 message_type, u8 *buffer) {
109 /* Originally out_buffer[FBUS_MAX_CONTENT_LENGTH + 2],
110 but it made problems with MBUS */
113 int count, current=0;
114 unsigned char checksum;
116 /* FIXME - we should check for the message length ... */
118 /* Now construct the message header. */
120 if (CurrentConnectionType==GCT_FBUS)
121 out_buffer[current++] = FBUS_FRAME_ID; /* Start of the frame indicator */
123 out_buffer[current++] = FBUS_IR_FRAME_ID; /* Start of the frame indicator */
125 out_buffer[current++] = FBUS_DEVICE_PHONE; /* Destination */
127 out_buffer[current++] = FBUS_DEVICE_PC; /* Source */
129 out_buffer[current++] = message_type; /* Type */
131 out_buffer[current++] = 0; /* Length1 */
132 out_buffer[current++] = message_length; /* Length2 */
134 /* Copy in data if any. */
135 if (message_length != 0) {
136 memcpy(out_buffer + current, buffer, message_length);
137 current+=message_length;
140 /* If the message length is odd we should add pad byte 0x00 */
141 if (message_length % 2)
142 out_buffer[current++]=0x00;
144 /* Now calculate checksums over entire message and append to message. */
148 for (count = 0; count < current; count+=2)
149 checksum ^= out_buffer[count];
151 out_buffer[current++] = checksum;
155 for (count = 1; count < current; count+=2)
156 checksum ^= out_buffer[count];
158 out_buffer[current++] = checksum;
161 NULL_TX_DisplayMessage(current, out_buffer);
167 if (!NULL_WritePhone(current,out_buffer))
173 int FBUS_SendMessage(u16 message_length, u8 message_type, u8 *buffer) {
177 u8 frame_buffer[FBUS_MAX_CONTENT_LENGTH + 2];
179 u8 nom, lml; /* number of messages, last message len */
182 seqnum = 0x40 + RequestSequenceNumber;
183 RequestSequenceNumber = (RequestSequenceNumber + 1) & 0x07;
185 if (message_length > FBUS_MAX_CONTENT_LENGTH) {
187 nom = (message_length + FBUS_MAX_CONTENT_LENGTH - 1)
188 / FBUS_MAX_CONTENT_LENGTH;
189 lml = message_length - ((nom - 1) * FBUS_MAX_CONTENT_LENGTH);
191 for (i = 0; i < nom - 1; i++) {
193 memcpy(frame_buffer, buffer + (i * FBUS_MAX_CONTENT_LENGTH),
194 FBUS_MAX_CONTENT_LENGTH);
195 frame_buffer[FBUS_MAX_CONTENT_LENGTH] = nom - i;
196 frame_buffer[FBUS_MAX_CONTENT_LENGTH + 1] = seqnum;
198 FBUS_SendFrame(FBUS_MAX_CONTENT_LENGTH + 2, message_type,
201 seqnum = RequestSequenceNumber;
202 RequestSequenceNumber = (RequestSequenceNumber + 1) & 0x07;
205 memcpy(frame_buffer, buffer + ((nom - 1) * FBUS_MAX_CONTENT_LENGTH), lml);
206 frame_buffer[lml] = 0x01;
207 frame_buffer[lml + 1] = seqnum;
208 FBUS_SendFrame(lml + 2, message_type, frame_buffer);
212 memcpy(frame_buffer, buffer, message_length);
213 frame_buffer[message_length] = 0x01;
214 frame_buffer[message_length + 1] = seqnum;
215 FBUS_SendFrame(message_length + 2, message_type, frame_buffer);
221 static int FBUS_SendAck(u8 message_type, u8 message_seq) {
223 unsigned char request[6];
225 request[0] = message_type;
226 request[1] = message_seq;
229 fprintf(stdout, _("[Sending Ack of type %02x, seq: %x]\n"), message_type, message_seq);
232 return FBUS_SendFrame(2, FBUS_FRTYPE_ACK, request);
235 /* Applications should call FBUS_Terminate to shut down the FBUS thread and
236 close the serial port. */
237 void FBUS_Terminate(void)
239 /* Request termination of thread */
240 CurrentRequestTerminate = true;
242 /* Close serial port. */
246 /* RX_State machine for receive handling. Called once for each character
247 received from the phone/phone. */
249 void FBUS_RX_StateMachine(unsigned char rx_byte) {
251 static struct timeval time_now, time_last, time_diff;
253 static int checksum[2];
257 // if (CurrentConnectionType==GCT_DLR3) {
258 // AT_RX_StateMachine(rx_byte);
261 #ifdef XDEBUG_LaceDisabled
262 if (isprint(rx_byte))
263 fprintf(stdout, "[%02x%c]", rx_byte, rx_byte);
265 fprintf(stdout, "[%02x ]", rx_byte);
270 /* For model sniff only display received bytes */
271 if (strcmp(GSM_Info->FBUSModels, "sniff"))
275 /* XOR the byte with the current checksum */
276 checksum[BufferCount&1] ^= rx_byte;
280 /* Messages from the phone start with an 0x1e (FBUS) or 0x1c (IR) or 0x1f (MBUS).
281 We use this to "synchronise" with the incoming data stream. However,
282 if we see something else, we assume we have lost sync and we require
283 a gap of at least 5ms before we start looking again. This is because
284 the data part of the frame could contain a byte which looks like the
287 case FBUS_RX_Discarding:
290 gettimeofday(&time_now, NULL);
291 timersub(&time_now, &time_last, &time_diff);
292 if (time_diff.tv_sec == 0 && time_diff.tv_usec < 5000) {
293 time_last = time_now; /* no gap seen, continue discarding */
296 /* else fall through to... */
301 if ((CurrentConnectionType==GCT_FBUS && rx_byte == FBUS_FRAME_ID) ||
302 0/*((CurrentConnectionType==GCT_Infrared ||
303 CurrentConnectionType==GCT_Tekram) && rx_byte == FBUS_IR_FRAME_ID)*/) {
307 RX_State = FBUS_RX_GetDestination;
309 /* Initialize checksums. */
310 checksum[0] = rx_byte;
313 /* Lost frame sync */
314 RX_State = FBUS_RX_Discarding;
316 gettimeofday(&time_last, NULL);
321 case FBUS_RX_GetDestination:
323 MessageDestination=rx_byte;
324 RX_State = FBUS_RX_GetSource;
326 /* When there is a checksum error and things get out of sync we have to manage to resync */
327 /* If doing a data call at the time, finding a 0x1e etc is really quite likely in the data stream */
328 /* Then all sorts of horrible things happen because the packet length etc is wrong... */
329 /* Therefore we test here for a destination of 0x0c and return to the top if it is not */
330 if (rx_byte!=FBUS_DEVICE_PC && strstr(GSM_Info->FBUSModels, "sniff")==NULL) {
331 RX_State=FBUS_RX_Sync;
333 fprintf(stdout,"The fbus stream is out of sync - expected 0x0c, got %2x\n",rx_byte);
335 AppendLogText("SYNC\n",false);
340 case FBUS_RX_GetSource:
342 MessageSource=rx_byte;
343 RX_State = FBUS_RX_GetType;
345 /* Source should be 0x00 */
346 if (rx_byte!=FBUS_DEVICE_PHONE && strstr(GSM_Info->FBUSModels, "sniff")==NULL) {
347 RX_State=FBUS_RX_Sync;
349 fprintf(stdout,"The fbus stream is out of sync - expected 0x00, got %2x\n",rx_byte);
351 AppendLogText("SYNC\n",false);
356 case FBUS_RX_GetType:
360 RX_State = FBUS_RX_GetLength1;
364 case FBUS_RX_GetLength1:
368 RX_State = FBUS_RX_GetLength2;
372 case FBUS_RX_GetLength2:
374 /* MW:Here are problems with conversion. For chars 0-127 it's OK, for
375 higher not (probably because rx_byte is char type) - improtant
376 for MBUS. So, I make it double and strange - generally it should be
377 more simple and make simple convert rx_byte into MessageLength */
378 #if defined(__svr4__) || defined(__FreeBSD__)
380 for (i=0;i<rx_byte;i++)
381 MessageLength=MessageLength++;
384 MessageLength = rx_byte;
387 RX_State = FBUS_RX_GetMessage;
391 case FBUS_RX_GetMessage:
393 MessageBuffer[BufferCount] = rx_byte;
396 if (BufferCount>FBUS_MAX_RECEIVE_LENGTH*6) {
398 fprintf(stdout, "FB61: Message buffer overun - resetting\n");
400 AppendLogText("OVERUN\n",false);
402 RX_State = FBUS_RX_Sync;
406 /* If this is the last byte, it's the checksum. */
407 if (BufferCount == MessageLength+(MessageLength%2)+2) {
409 /* Is the checksum correct? */
410 if (checksum[0] == checksum[1]) {
414 if (MessageType==MultiMessageType) {
416 if (MessageLength+MultiMessageLength>FBUS_MAX_RECEIVE_LENGTH*6) {
418 fprintf(stdout, "FB61: Message buffer overun - resetting\n");
420 AppendLogText("OVERUN\n",false);
422 RX_State = FBUS_RX_Sync;
426 /* We copy next part of multiframe message into special buffer */
427 for (i=0;i<MessageLength;i++) {
428 MultiMessageBuffer[i+MultiMessageLength]=MessageBuffer[i];
430 MultiMessageLength=MultiMessageLength+MessageLength-2;
432 FBUS_SendAck(MessageType, MessageBuffer[MessageLength-1] & 0x0f);
434 if ((MessageLength > 1) && (MessageBuffer[MessageLength-2] != 0x01))
437 for (i=0;i<MultiMessageLength+2;i++) {
438 MessageBuffer[i]=MultiMessageBuffer[i];
440 MessageLength=MultiMessageLength+2;
443 /* Do not debug Ack and RLP frames to detail. */
444 if (MessageType != FBUS_FRTYPE_ACK && MessageType != 0xf1)
445 N61_RX_DisplayMessage();
447 GSM->DispatchMessage(MessageLength, MessageBuffer, MessageType);
452 /* We do not want to send ACK of ACKs and ACK of RLP frames. */
453 if (MessageType != FBUS_FRTYPE_ACK && MessageType != 0xf1) {
454 FBUS_SendAck(MessageType, MessageBuffer[MessageLength-1] & 0x0f);
456 if ((MessageLength > 1) && (MessageBuffer[MessageLength-2] != 0x01))
459 fprintf(stdout,_("Multiframe message in multiframe message !\n"));
460 fprintf(stdout,_("Please report it !\n"));
462 RX_State = FBUS_RX_Sync;
468 /* We do not want to send ACK of ACKs and ACK of RLP frames. */
469 if (MessageType != FBUS_FRTYPE_ACK && MessageType != 0xf1) {
470 FBUS_SendAck(MessageType, MessageBuffer[MessageLength-1] & 0x0f);
472 if ((MessageLength > 1) && (MessageBuffer[MessageLength-2] != 0x01))
474 /* We copy previous part of multiframe message into special buffer */
476 for (i=0;i<MessageLength-2;i++) {
477 MultiMessageBuffer[i]=MessageBuffer[i];
479 MultiMessageLength=MessageLength-2;
480 MultiMessageType=MessageType;
484 if (!RX_Multiple && MessageDestination!=FBUS_DEVICE_PHONE ) {
485 /* Do not debug Ack and RLP frames to detail. */
486 if (MessageType != FBUS_FRTYPE_ACK && MessageType != 0xf1)
487 N61_RX_DisplayMessage();
489 GSM->DispatchMessage(MessageLength, MessageBuffer, MessageType);
493 /* When make debug and message is to phone display it */
494 if (MessageDestination==FBUS_DEVICE_PHONE) {
495 for (i=MessageLength;i>=0;i--)
496 MessageBuffer[i+6]=MessageBuffer[i];
497 MessageBuffer[0]=FBUS_FRAME_ID;
498 MessageBuffer[1]=FBUS_DEVICE_PHONE;
499 MessageBuffer[2]=FBUS_DEVICE_PC;
500 MessageBuffer[3]=MessageType;
502 MessageBuffer[5]=MessageLength;
503 MessageLength=MessageLength+8;
504 if (MessageLength % 2) MessageLength++;
505 NULL_TX_DisplayMessage(MessageLength, MessageBuffer);
511 fprintf(stdout, _("Bad checksum %02x (should be %02x), msg len=%i !\n"),checksum[0],checksum[1],MessageLength);
513 AppendLogText("CHECKSUM\n",false);
515 /* Just to be sure! */
518 RX_State = FBUS_RX_Sync;
525 if (isprint(rx_byte))
526 fprintf(stdout, "[%02x%c]", rx_byte, rx_byte);
528 fprintf(stdout, "[%02x ]", rx_byte);
536 /* Called by initialisation code to open comm port in asynchronous mode. */
537 static bool FBUS_OpenSerial(void)
539 /* Uncomment, if want to test first method for DLR3 */
540 // unsigned char req[3] = {"AT\r"};
541 // unsigned char req2[5] = {"AT&F\r"};
542 // unsigned char req3[13] = {"AT*NOKIAFBUS\r"};
546 // GSM_Information *GSMINFOCOPY;
547 // GSM_Functions *GSMCOPY;
549 switch (CurrentConnectionType) {
553 fprintf(stdout, _("Setting cable for FBUS communication...\n"));
556 device_changespeed(115200);
559 The data suite cable has some electronics built into the connector. This of
560 course needs a power supply of some sorts to operate properly.
562 In this case power is drawn off the handshaking lines of the PC. DTR has to
563 be set and RTS have to be cleared, thus if you use a terminal program (that
564 does not set the handshaking lines to these conditions) you will get weird
565 results. It will not set them like this since if Request To Send (RTS) is
566 not set the other party will not send any data (in hardware handshaking)
567 and if DTS is not set (handshaking = none) the cable will not receive
569 /* clearing the RTS bit and setting the DTR bit*/
570 device_setdtrrts(1, 0);
577 fprintf(stdout, _("Setting DLR3 cable for FBUS communication...\n"));
580 /* There are 2 ways to init DLR in FBUS: Here is first described by
581 Reuben Harris [reuben.harris@snowvalley.com] and used in Logo Manager,
582 1. Firstly set the connection baud to 19200, DTR off, RTS off,
583 Parity on, one stop bit,
584 2. Send "AT\r\n". The response should be "AT\r\n\r\nOK\r\n".
585 3. Send "AT&F\r\n". The response should be "AT&F\r\n\r\nOK\r\n".
586 4. Send "AT*NOKIAFBUS\r\n". The response should be
587 "AT*NOKIAFBUS\r\n\r\nOK\r\n".
588 5. Set speed to 115200
590 This is one should be used by us, because seems to be compatible with more
591 phones. But we make something wrong and often phones don't want to start transmision */
593 /* Uncomment and test if want */
594 // device_changespeed(19200);
596 /*leave RTS low, DTR low for duration of session.*/
597 // device_setdtrrts(0, 0);
599 /* Making copy of pointers */
601 // GSMINFOCOPY =GSM_Info;
603 /* Set pointers to relevant addresses - new "AT" module here is required */
604 // GSM = &Nat_Functions;
605 // GSM_Info = &Nat_Information;
607 /* Note: We change Protocol inside function pointed by it.
608 That's why in FBUS_RX_StateMachine we must check it (changing
609 Protocol is not enough), This is for correct work and be sure... */
610 // Protocol = &AT_Functions;
612 // error=N6110_SendMessageSequence (50, &CurrentGetHWError, 3, 0x00, req);
613 // if (error!=GE_NONE) return false;
615 // error=N6110_SendMessageSequence (50, &CurrentGetHWError, 5, 0x00, req2);
616 // if (error!=GE_NONE) return false;
618 // error=N6110_SendMessageSequence (50, &CurrentGetHWError, 13, 0x00, req3);
619 // if (error!=GE_NONE) return false;
621 /* Returning to old protocol */
622 // Protocol = &FBUS_Functions;
624 /* Returning to old module */
626 // GSM_Info = GSMINFOCOPY;
628 // device_changespeed(115200);
630 /* Second method for DLR3:
631 Used by some 7110 soft, but not compatible with some other
632 phones supporting DLR3 - 7160, NCP2.0
633 Used in this moment in mygnokii
636 device_changespeed(115200);
638 /*leave RTS low, DTR low for duration of session.*/
639 device_setdtrrts(0, 0);
643 CurrentConnectionType=GCT_FBUS;
647 /* It's more complicated and not done here */
651 /* It's more complicated and not done here */
657 fprintf(stdout,_("Wrong connection type for fbus module. Inform marcin-wiacek@topnet.pl about it\n"));
665 /* Initialise variables and state machine. */
666 static GSM_Error FBUS_Initialise(char *port_device, char *initlength,
667 GSM_ConnectionType connection,
668 void (*rlp_callback)(RLP_F96Frame *frame))
671 if (!StartConnection (port_device,false,connection))
672 return GE_INTERNALERROR;
674 CurrentConnectionType = connection;
676 if (FBUS_OpenSerial() != true) return GE_INTERNALERROR;