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);
169 if (!NULL_WritePhone(current,out_buffer))
175 int FBUS_SendMessage(u16 message_length, u8 message_type, u8 *buffer) {
179 u8 frame_buffer[FBUS_MAX_CONTENT_LENGTH + 2];
181 u8 nom, lml; /* number of messages, last message len */
184 seqnum = 0x40 + RequestSequenceNumber;
185 RequestSequenceNumber = (RequestSequenceNumber + 1) & 0x07;
187 if (message_length > FBUS_MAX_CONTENT_LENGTH) {
189 nom = (message_length + FBUS_MAX_CONTENT_LENGTH - 1)
190 / FBUS_MAX_CONTENT_LENGTH;
191 lml = message_length - ((nom - 1) * FBUS_MAX_CONTENT_LENGTH);
193 for (i = 0; i < nom - 1; i++) {
195 memcpy(frame_buffer, buffer + (i * FBUS_MAX_CONTENT_LENGTH),
196 FBUS_MAX_CONTENT_LENGTH);
197 frame_buffer[FBUS_MAX_CONTENT_LENGTH] = nom - i;
198 frame_buffer[FBUS_MAX_CONTENT_LENGTH + 1] = seqnum;
200 FBUS_SendFrame(FBUS_MAX_CONTENT_LENGTH + 2, message_type,
203 seqnum = RequestSequenceNumber;
204 RequestSequenceNumber = (RequestSequenceNumber + 1) & 0x07;
207 memcpy(frame_buffer, buffer + ((nom - 1) * FBUS_MAX_CONTENT_LENGTH), lml);
208 frame_buffer[lml] = 0x01;
209 frame_buffer[lml + 1] = seqnum;
210 FBUS_SendFrame(lml + 2, message_type, frame_buffer);
214 memcpy(frame_buffer, buffer, message_length);
215 frame_buffer[message_length] = 0x01;
216 frame_buffer[message_length + 1] = seqnum;
217 FBUS_SendFrame(message_length + 2, message_type, frame_buffer);
223 static int FBUS_SendAck(u8 message_type, u8 message_seq) {
225 unsigned char request[6];
227 request[0] = message_type;
228 request[1] = message_seq;
231 fprintf(stdout, _("[Sending Ack of type %02x, seq: %x]\n"), message_type, message_seq);
234 return FBUS_SendFrame(2, FBUS_FRTYPE_ACK, request);
237 /* Applications should call FBUS_Terminate to shut down the FBUS thread and
238 close the serial port. */
239 void FBUS_Terminate(void)
241 /* Request termination of thread */
242 CurrentRequestTerminate = true;
244 /* Close serial port. */
248 /* RX_State machine for receive handling. Called once for each character
249 received from the phone/phone. */
251 void FBUS_RX_StateMachine(unsigned char rx_byte) {
253 static struct timeval time_now, time_last, time_diff;
255 static int checksum[2];
259 // if (CurrentConnectionType==GCT_DLR3) {
260 // AT_RX_StateMachine(rx_byte);
263 #ifdef XDEBUG_LaceDisabled
264 if (isprint(rx_byte))
265 fprintf(stdout, "[%02x%c]", rx_byte, rx_byte);
267 fprintf(stdout, "[%02x ]", rx_byte);
272 /* For model sniff only display received bytes */
273 if (strcmp(GSM_Info->FBUSModels, "sniff"))
277 /* XOR the byte with the current checksum */
278 checksum[BufferCount&1] ^= rx_byte;
282 /* Messages from the phone start with an 0x1e (FBUS) or 0x1c (IR) or 0x1f (MBUS).
283 We use this to "synchronise" with the incoming data stream. However,
284 if we see something else, we assume we have lost sync and we require
285 a gap of at least 5ms before we start looking again. This is because
286 the data part of the frame could contain a byte which looks like the
289 case FBUS_RX_Discarding:
292 gettimeofday(&time_now, NULL);
293 timersub(&time_now, &time_last, &time_diff);
294 if (time_diff.tv_sec == 0 && time_diff.tv_usec < 5000) {
295 time_last = time_now; /* no gap seen, continue discarding */
298 /* else fall through to... */
303 if ((CurrentConnectionType==GCT_FBUS && rx_byte == FBUS_FRAME_ID) ||
304 0/*((CurrentConnectionType==GCT_Infrared ||
305 CurrentConnectionType==GCT_Tekram) && rx_byte == FBUS_IR_FRAME_ID)*/) {
309 RX_State = FBUS_RX_GetDestination;
311 /* Initialize checksums. */
312 checksum[0] = rx_byte;
315 /* Lost frame sync */
316 RX_State = FBUS_RX_Discarding;
318 gettimeofday(&time_last, NULL);
323 case FBUS_RX_GetDestination:
325 MessageDestination=rx_byte;
326 RX_State = FBUS_RX_GetSource;
328 /* When there is a checksum error and things get out of sync we have to manage to resync */
329 /* If doing a data call at the time, finding a 0x1e etc is really quite likely in the data stream */
330 /* Then all sorts of horrible things happen because the packet length etc is wrong... */
331 /* Therefore we test here for a destination of 0x0c and return to the top if it is not */
332 if (rx_byte!=FBUS_DEVICE_PC && strstr(GSM_Info->FBUSModels, "sniff")==NULL) {
333 RX_State=FBUS_RX_Sync;
335 fprintf(stdout,"The fbus stream is out of sync - expected 0x0c, got %2x\n",rx_byte);
337 AppendLogText("SYNC\n",false);
342 case FBUS_RX_GetSource:
344 MessageSource=rx_byte;
345 RX_State = FBUS_RX_GetType;
347 /* Source should be 0x00 */
348 if (rx_byte!=FBUS_DEVICE_PHONE && strstr(GSM_Info->FBUSModels, "sniff")==NULL) {
349 RX_State=FBUS_RX_Sync;
351 fprintf(stdout,"The fbus stream is out of sync - expected 0x00, got %2x\n",rx_byte);
353 AppendLogText("SYNC\n",false);
358 case FBUS_RX_GetType:
362 RX_State = FBUS_RX_GetLength1;
366 case FBUS_RX_GetLength1:
370 RX_State = FBUS_RX_GetLength2;
374 case FBUS_RX_GetLength2:
376 /* MW:Here are problems with conversion. For chars 0-127 it's OK, for
377 higher not (probably because rx_byte is char type) - improtant
378 for MBUS. So, I make it double and strange - generally it should be
379 more simple and make simple convert rx_byte into MessageLength */
380 #if defined(__svr4__) || defined(__FreeBSD__)
382 for (i=0;i<rx_byte;i++)
383 MessageLength=MessageLength++;
386 MessageLength = rx_byte;
389 RX_State = FBUS_RX_GetMessage;
393 case FBUS_RX_GetMessage:
395 MessageBuffer[BufferCount] = rx_byte;
398 if (BufferCount>FBUS_MAX_RECEIVE_LENGTH*6) {
400 fprintf(stdout, "FB61: Message buffer overun - resetting\n");
402 AppendLogText("OVERUN\n",false);
404 RX_State = FBUS_RX_Sync;
408 /* If this is the last byte, it's the checksum. */
409 if (BufferCount == MessageLength+(MessageLength%2)+2) {
411 /* Is the checksum correct? */
412 if (checksum[0] == checksum[1]) {
416 if (MessageType==MultiMessageType) {
418 if (MessageLength+MultiMessageLength>FBUS_MAX_RECEIVE_LENGTH*6) {
420 fprintf(stdout, "FB61: Message buffer overun - resetting\n");
422 AppendLogText("OVERUN\n",false);
424 RX_State = FBUS_RX_Sync;
428 /* We copy next part of multiframe message into special buffer */
429 for (i=0;i<MessageLength;i++) {
430 MultiMessageBuffer[i+MultiMessageLength]=MessageBuffer[i];
432 MultiMessageLength=MultiMessageLength+MessageLength-2;
434 FBUS_SendAck(MessageType, MessageBuffer[MessageLength-1] & 0x0f);
436 if ((MessageLength > 1) && (MessageBuffer[MessageLength-2] != 0x01))
439 for (i=0;i<MultiMessageLength+2;i++) {
440 MessageBuffer[i]=MultiMessageBuffer[i];
442 MessageLength=MultiMessageLength+2;
445 /* Do not debug Ack and RLP frames to detail. */
446 if (MessageType != FBUS_FRTYPE_ACK && MessageType != 0xf1)
447 N61_RX_DisplayMessage();
449 GSM->DispatchMessage(MessageLength-2, MessageBuffer, MessageType);
454 /* We do not want to send ACK of ACKs and ACK of RLP frames. */
455 if (MessageType != FBUS_FRTYPE_ACK && MessageType != 0xf1) {
456 FBUS_SendAck(MessageType, MessageBuffer[MessageLength-1] & 0x0f);
458 if ((MessageLength > 1) && (MessageBuffer[MessageLength-2] != 0x01))
461 fprintf(stdout,_("Multiframe message in multiframe message !\n"));
462 fprintf(stdout,_("Please report it !\n"));
464 RX_State = FBUS_RX_Sync;
470 /* We do not want to send ACK of ACKs and ACK of RLP frames. */
471 if (MessageType != FBUS_FRTYPE_ACK && MessageType != 0xf1) {
472 FBUS_SendAck(MessageType, MessageBuffer[MessageLength-1] & 0x0f);
474 if ((MessageLength > 1) && (MessageBuffer[MessageLength-2] != 0x01))
476 /* We copy previous part of multiframe message into special buffer */
478 for (i=0;i<MessageLength-2;i++) {
479 MultiMessageBuffer[i]=MessageBuffer[i];
481 MultiMessageLength=MessageLength-2;
482 MultiMessageType=MessageType;
486 if (!RX_Multiple && MessageDestination!=FBUS_DEVICE_PHONE ) {
487 /* Do not debug Ack and RLP frames to detail. */
488 if (MessageType != FBUS_FRTYPE_ACK && MessageType != 0xf1)
489 N61_RX_DisplayMessage();
491 GSM->DispatchMessage(MessageLength-2, MessageBuffer, MessageType);
495 /* When make debug and message is to phone display it */
496 if (MessageDestination==FBUS_DEVICE_PHONE) {
497 for (i=MessageLength;i>=0;i--)
498 MessageBuffer[i+6]=MessageBuffer[i];
499 MessageBuffer[0]=FBUS_FRAME_ID;
500 MessageBuffer[1]=FBUS_DEVICE_PHONE;
501 MessageBuffer[2]=FBUS_DEVICE_PC;
502 MessageBuffer[3]=MessageType;
504 MessageBuffer[5]=MessageLength;
505 MessageLength=MessageLength+8;
506 if (MessageLength % 2) MessageLength++;
507 NULL_TX_DisplayMessage(MessageLength, MessageBuffer);
513 fprintf(stdout, _("Bad checksum %02x (should be %02x), msg len=%i !\n"),checksum[0],checksum[1],MessageLength);
515 AppendLogText("CHECKSUM\n",false);
517 /* Just to be sure! */
520 RX_State = FBUS_RX_Sync;
527 if (isprint(rx_byte))
528 fprintf(stdout, "[%02x%c]", rx_byte, rx_byte);
530 fprintf(stdout, "[%02x ]", rx_byte);
538 /* Called by initialisation code to open comm port in asynchronous mode. */
539 static bool FBUS_OpenSerial(void)
541 /* Uncomment, if want to test first method for DLR3 */
542 // unsigned char req[3] = {"AT\r"};
543 // unsigned char req2[5] = {"AT&F\r"};
544 // unsigned char req3[13] = {"AT*NOKIAFBUS\r"};
548 // GSM_Information *GSMINFOCOPY;
549 // GSM_Functions *GSMCOPY;
551 switch (CurrentConnectionType) {
555 fprintf(stdout, _("Setting cable for FBUS communication...\n"));
558 device_changespeed(115200);
561 The data suite cable has some electronics built into the connector. This of
562 course needs a power supply of some sorts to operate properly.
564 In this case power is drawn off the handshaking lines of the PC. DTR has to
565 be set and RTS have to be cleared, thus if you use a terminal program (that
566 does not set the handshaking lines to these conditions) you will get weird
567 results. It will not set them like this since if Request To Send (RTS) is
568 not set the other party will not send any data (in hardware handshaking)
569 and if DTS is not set (handshaking = none) the cable will not receive
571 /* clearing the RTS bit and setting the DTR bit*/
572 device_setdtrrts(1, 0);
579 fprintf(stdout, _("Setting DLR3 cable for FBUS communication...\n"));
582 /* There are 2 ways to init DLR in FBUS: Here is first described by
583 Reuben Harris [reuben.harris@snowvalley.com] and used in Logo Manager,
584 1. Firstly set the connection baud to 19200, DTR off, RTS off,
585 Parity on, one stop bit,
586 2. Send "AT\r\n". The response should be "AT\r\n\r\nOK\r\n".
587 3. Send "AT&F\r\n". The response should be "AT&F\r\n\r\nOK\r\n".
588 4. Send "AT*NOKIAFBUS\r\n". The response should be
589 "AT*NOKIAFBUS\r\n\r\nOK\r\n".
590 5. Set speed to 115200
592 This is one should be used by us, because seems to be compatible with more
593 phones. But we make something wrong and often phones don't want to start transmision */
595 /* Uncomment and test if want */
596 // device_changespeed(19200);
598 /*leave RTS low, DTR low for duration of session.*/
599 // device_setdtrrts(0, 0);
601 /* Making copy of pointers */
603 // GSMINFOCOPY =GSM_Info;
605 /* Set pointers to relevant addresses - new "AT" module here is required */
606 // GSM = &Nat_Functions;
607 // GSM_Info = &Nat_Information;
609 /* Note: We change Protocol inside function pointed by it.
610 That's why in FBUS_RX_StateMachine we must check it (changing
611 Protocol is not enough), This is for correct work and be sure... */
612 // Protocol = &AT_Functions;
614 // error=N6110_SendMessageSequence (50, &CurrentGetHWError, 3, 0x00, req);
615 // if (error!=GE_NONE) return false;
617 // error=N6110_SendMessageSequence (50, &CurrentGetHWError, 5, 0x00, req2);
618 // if (error!=GE_NONE) return false;
620 // error=N6110_SendMessageSequence (50, &CurrentGetHWError, 13, 0x00, req3);
621 // if (error!=GE_NONE) return false;
623 /* Returning to old protocol */
624 // Protocol = &FBUS_Functions;
626 /* Returning to old module */
628 // GSM_Info = GSMINFOCOPY;
630 // device_changespeed(115200);
632 /* Second method for DLR3:
633 Used by some 7110 soft, but not compatible with some other
634 phones supporting DLR3 - 7160, NCP2.0
635 Used in this moment in mygnokii
638 device_changespeed(115200);
640 /*leave RTS low, DTR low for duration of session.*/
641 device_setdtrrts(0, 0);
645 CurrentConnectionType=GCT_FBUS;
649 /* It's more complicated and not done here */
653 /* It's more complicated and not done here */
659 fprintf(stdout,_("Wrong connection type for fbus module. Inform marcin-wiacek@topnet.pl about it\n"));
667 /* Initialise variables and state machine. */
668 static GSM_Error FBUS_Initialise(char *port_device, char *initlength,
669 GSM_ConnectionType connection,
670 void (*rlp_callback)(RLP_F96Frame *frame))
673 if (!StartConnection (port_device,false,connection))
674 return GE_INTERNALERROR;
676 CurrentConnectionType = connection;
678 if (FBUS_OpenSerial() != true) return GE_INTERNALERROR;