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
13 /* "Turn on" prototypes in fbus.h */
16 /* System header files */
23 #include "misc_win32.h"
28 /* Various header file */
29 #include "devices/device.h"
31 #include "protocol/fbus.h"
32 #include "protocol/at.h"
33 #include "newmodules/newat.h"
34 #include "newmodules/n6110.h"
37 GSM_Protocol FBUS_Functions = {
47 enum FBUS_RX_States RX_State;
49 u8 MessageDestination, MessageSource;
51 u16 BufferCount, MultiBufferCount;
53 u16 MessageLength, MultiMessageLength;
55 bool RX_Multiple = false;
57 u8 MessageType,MultiMessageType;
59 u8 MessageBuffer[FBUS_MAX_RECEIVE_LENGTH * 6],MultiMessageBuffer[FBUS_MAX_RECEIVE_LENGTH * 6];
61 u8 RequestSequenceNumber = 0x00;
66 char *N61_PrintDevice(int Device)
70 case FBUS_DEVICE_PHONE:return _("Phone");
71 case FBUS_DEVICE_PC :return _("PC");
72 default :return _("Unknown");
77 /* N61_RX_DisplayMessage is called when a message we don't know about is
78 received so that the user can see what is going back and forth, and perhaps
79 shed some more light/explain another message type! */
80 void N61_RX_DisplayMessage()
83 hexdump(MessageLength-2,MessageBuffer);
85 fprintf(stdout, _("Msg Dest: %s\n"), N61_PrintDevice(MessageDestination));
86 fprintf(stdout, _("Msg Source: %s\n"), N61_PrintDevice(MessageSource));
87 fprintf(stdout, _("Msg Type: %02x\n"), MessageType);
88 fprintf(stdout, _("Msg Seq: %d\n"), MessageBuffer[MessageLength-1] & 0x0f);
91 AppendLog(MessageBuffer,MessageLength-2,true);
94 /* Prepares the message header and sends it, prepends the message start byte
95 (0x1e) and other values according the value specified when called.
96 Calculates checksum and then sends the lot down the pipe... */
97 int FBUS_SendFrame(u16 message_length, u8 message_type, u8 *buffer) {
99 /* Originally out_buffer[FBUS_MAX_CONTENT_LENGTH + 2],
100 but it made problems with MBUS */
103 int count, current=0;
104 unsigned char checksum;
106 /* FIXME - we should check for the message length ... */
108 /* Now construct the message header. */
110 if (CurrentConnectionType==GCT_FBUS)
111 out_buffer[current++] = FBUS_FRAME_ID; /* Start of the frame indicator */
113 out_buffer[current++] = FBUS_IR_FRAME_ID; /* Start of the frame indicator */
115 out_buffer[current++] = FBUS_DEVICE_PHONE; /* Destination */
117 out_buffer[current++] = FBUS_DEVICE_PC; /* Source */
119 out_buffer[current++] = message_type; /* Type */
121 out_buffer[current++] = 0; /* Length1 */
122 out_buffer[current++] = message_length; /* Length2 */
124 /* Copy in data if any. */
125 if (message_length != 0) {
126 memcpy(out_buffer + current, buffer, message_length);
127 current+=message_length;
130 /* If the message length is odd we should add pad byte 0x00 */
131 if (message_length % 2)
132 out_buffer[current++]=0x00;
134 /* Now calculate checksums over entire message and append to message. */
138 for (count = 0; count < current; count+=2)
139 checksum ^= out_buffer[count];
141 out_buffer[current++] = checksum;
145 for (count = 1; count < current; count+=2)
146 checksum ^= out_buffer[count];
148 out_buffer[current++] = checksum;
151 NULL_TX_DisplayMessage(current, out_buffer);
155 if (!NULL_WritePhone(current,out_buffer))
161 int FBUS_SendMessage(u16 message_length, u8 message_type, u8 *buffer) {
165 u8 frame_buffer[FBUS_MAX_CONTENT_LENGTH + 2];
167 u8 nom, lml; /* number of messages, last message len */
170 seqnum = 0x40 + RequestSequenceNumber;
171 RequestSequenceNumber = (RequestSequenceNumber + 1) & 0x07;
173 if (message_length > FBUS_MAX_CONTENT_LENGTH) {
175 nom = (message_length + FBUS_MAX_CONTENT_LENGTH - 1)
176 / FBUS_MAX_CONTENT_LENGTH;
177 lml = message_length - ((nom - 1) * FBUS_MAX_CONTENT_LENGTH);
179 for (i = 0; i < nom - 1; i++) {
181 memcpy(frame_buffer, buffer + (i * FBUS_MAX_CONTENT_LENGTH),
182 FBUS_MAX_CONTENT_LENGTH);
183 frame_buffer[FBUS_MAX_CONTENT_LENGTH] = nom - i;
184 frame_buffer[FBUS_MAX_CONTENT_LENGTH + 1] = seqnum;
186 FBUS_SendFrame(FBUS_MAX_CONTENT_LENGTH + 2, message_type,
189 seqnum = RequestSequenceNumber;
190 RequestSequenceNumber = (RequestSequenceNumber + 1) & 0x07;
193 memcpy(frame_buffer, buffer + ((nom - 1) * FBUS_MAX_CONTENT_LENGTH), lml);
194 frame_buffer[lml] = 0x01;
195 frame_buffer[lml + 1] = seqnum;
196 FBUS_SendFrame(lml + 2, message_type, frame_buffer);
200 memcpy(frame_buffer, buffer, message_length);
201 frame_buffer[message_length] = 0x01;
202 frame_buffer[message_length + 1] = seqnum;
203 FBUS_SendFrame(message_length + 2, message_type, frame_buffer);
209 int FBUS_SendAck(u8 message_type, u8 message_seq) {
211 unsigned char request[6];
216 request[0] = message_type;
217 request[1] = message_seq;
220 fprintf(stdout, _("[Sending Ack of type %02x, seq: %x]\n"), message_type, message_seq);
223 return FBUS_SendFrame(2, FBUS_FRTYPE_ACK, request);
226 /* Applications should call FBUS_Terminate to shut down the FBUS thread and
227 close the serial port. */
228 void FBUS_Terminate(void)
230 /* Request termination of thread */
231 CurrentRequestTerminate = true;
233 /* Close serial port. */
237 /* RX_State machine for receive handling. Called once for each character
238 received from the phone/phone. */
240 void FBUS_RX_StateMachine(unsigned char rx_byte) {
243 static struct timeval time_now, time_last, time_diff;
246 static int checksum[2];
250 // if (CurrentConnectionType==GCT_DLR3) {
251 // AT_RX_StateMachine(rx_byte);
255 /* For model sniff only display received bytes */
256 if (strcmp(GSM_Info->FBUSModels, "sniff"))
260 /* XOR the byte with the current checksum */
261 checksum[BufferCount&1] ^= rx_byte;
265 /* Messages from the phone start with an 0x1e (FBUS) or 0x1c (IR) or 0x1f (MBUS).
266 We use this to "synchronise" with the incoming data stream. However,
267 if we see something else, we assume we have lost sync and we require
268 a gap of at least 5ms before we start looking again. This is because
269 the data part of the frame could contain a byte which looks like the
272 case FBUS_RX_Discarding:
276 gettimeofday(&time_now, NULL);
277 timersub(&time_now, &time_last, &time_diff);
278 if (time_diff.tv_sec == 0 && time_diff.tv_usec < 5000) {
279 time_last = time_now; /* no gap seen, continue discarding */
282 /* else fall through to... */
287 static int discarded=0,discarded55=0;
289 if ((CurrentConnectionType==GCT_FBUS && rx_byte == FBUS_FRAME_ID) ||
290 ((CurrentConnectionType==GCT_Infrared ||
291 CurrentConnectionType==GCT_Tekram) && rx_byte == FBUS_IR_FRAME_ID)) {
294 printf("[discarded %d bytes, %d were NOT 0x55]\n",discarded,discarded-discarded55);
301 RX_State = FBUS_RX_GetDestination;
303 /* Initialize checksums. */
304 checksum[0] = rx_byte;
307 /* Lost frame sync */
308 RX_State = FBUS_RX_Discarding;
311 gettimeofday(&time_last, NULL);
320 case FBUS_RX_GetDestination:
322 MessageDestination=rx_byte;
323 RX_State = FBUS_RX_GetSource;
325 /* When there is a checksum error and things get out of sync we have to manage to resync */
326 /* If doing a data call at the time, finding a 0x1e etc is really quite likely in the data stream */
327 /* Then all sorts of horrible things happen because the packet length etc is wrong... */
328 /* Therefore we test here for a destination of 0x0c and return to the top if it is not */
329 if (rx_byte!=FBUS_DEVICE_PC && strstr(GSM_Info->FBUSModels, "sniff")==NULL) {
330 RX_State=FBUS_RX_Sync;
332 fprintf(stdout,"The fbus stream is out of sync - expected 0x0c, got %2x\n",rx_byte);
334 AppendLogText("SYNC\n",false);
339 case FBUS_RX_GetSource:
341 MessageSource=rx_byte;
342 RX_State = FBUS_RX_GetType;
344 /* Source should be 0x00 */
345 if (rx_byte!=FBUS_DEVICE_PHONE && strstr(GSM_Info->FBUSModels, "sniff")==NULL) {
346 RX_State=FBUS_RX_Sync;
348 fprintf(stdout,"The fbus stream is out of sync - expected 0x00, got %2x\n",rx_byte);
350 AppendLogText("SYNC\n",false);
355 case FBUS_RX_GetType:
359 RX_State = FBUS_RX_GetLength1;
363 case FBUS_RX_GetLength1:
367 RX_State = FBUS_RX_GetLength2;
371 case FBUS_RX_GetLength2:
373 /* MW:Here are problems with conversion. For chars 0-127 it's OK, for
374 higher not (probably because rx_byte is char type) - improtant
375 for MBUS. So, I make it double and strange - generally it should be
376 more simple and make simple convert rx_byte into MessageLength */
377 #if defined(__svr4__) || defined(__FreeBSD__)
379 for (i=0;i<rx_byte;i++)
380 MessageLength=MessageLength++;
383 MessageLength = rx_byte;
386 RX_State = FBUS_RX_GetMessage;
390 case FBUS_RX_GetMessage:
392 MessageBuffer[BufferCount] = rx_byte;
395 if (BufferCount>FBUS_MAX_RECEIVE_LENGTH*6) {
397 fprintf(stdout, "FB61: Message buffer overun - resetting\n");
399 AppendLogText("OVERUN\n",false);
401 RX_State = FBUS_RX_Sync;
405 /* If this is the last byte, it's the checksum. */
406 if (BufferCount == MessageLength+(MessageLength%2)+2) {
408 /* Is the checksum correct? */
409 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 msgseq=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 if (MessageType == FBUS_FRTYPE_ACK)
448 puts("[ignoring print of ACK]");
450 puts("[ignoring print of RLP]");
453 GSM->DispatchMessage(MessageLength-2, MessageBuffer, MessageType);
456 FBUS_SendAck(MessageType, msgseq);
460 /* We do not want to send ACK of ACKs and ACK of RLP frames. */
461 if (MessageType != FBUS_FRTYPE_ACK && MessageType != 0xf1) {
463 if ((MessageLength > 1) && (MessageBuffer[MessageLength-2] != 0x01))
466 fprintf(stdout,_("Multiframe message in multiframe message !\n"));
467 fprintf(stdout,_("Please report it !\n"));
469 RX_State = FBUS_RX_Sync;
472 msgseq=MessageBuffer[MessageLength-1] & 0x0f;
473 FBUS_SendAck(MessageType, msgseq);
477 msgseq=MessageBuffer[MessageLength-1] & 0x0f;
479 /* We do not want to send ACK of ACKs and ACK of RLP frames. */
480 if (MessageType != FBUS_FRTYPE_ACK && MessageType != 0xf1) {
482 if ((MessageLength > 1) && (MessageBuffer[MessageLength-2] != 0x01))
484 /* We copy previous part of multiframe message into special buffer */
486 for (i=0;i<MessageLength-2;i++) {
487 MultiMessageBuffer[i]=MessageBuffer[i];
489 MultiMessageLength=MessageLength-2;
490 MultiMessageType=MessageType;
494 if (!RX_Multiple /* && MessageDestination!=FBUS_DEVICE_PHONE */ ) {
495 /* Do not debug Ack and RLP frames to detail. */
496 if (MessageType != FBUS_FRTYPE_ACK && MessageType != 0xf1)
497 N61_RX_DisplayMessage();
499 if (MessageType == FBUS_FRTYPE_ACK)
500 puts("[ignoring print of ACK]");
502 puts("[ignoring print of RLP]");
505 GSM->DispatchMessage(MessageLength-2, MessageBuffer, MessageType);
509 /* When make debug and message is to phone display it */
510 if (MessageDestination==FBUS_DEVICE_PHONE && !fbus_decoding) {
511 for (i=MessageLength;i>=0;i--)
512 MessageBuffer[i+6]=MessageBuffer[i];
513 MessageBuffer[0]=FBUS_FRAME_ID;
514 MessageBuffer[1]=FBUS_DEVICE_PHONE;
515 MessageBuffer[2]=FBUS_DEVICE_PC;
516 MessageBuffer[3]=MessageType;
518 MessageBuffer[5]=MessageLength;
519 MessageLength=MessageLength+8;
520 if (MessageLength % 2) MessageLength++;
521 NULL_TX_DisplayMessage(MessageLength, MessageBuffer);
524 if (MessageType != FBUS_FRTYPE_ACK && MessageType != 0xf1)
525 FBUS_SendAck(MessageType, msgseq);
532 fprintf(stdout, _("Bad checksum %02x (should be %02x), msg len=%i !\n"),checksum[0],checksum[1],MessageLength);
534 AppendLogText("CHECKSUM\n",false);
536 /* Just to be sure! */
539 RX_State = FBUS_RX_Sync;
546 if (isprint(rx_byte))
547 fprintf(stdout, "[%02x%c]", rx_byte, rx_byte);
549 fprintf(stdout, "[%02x ]", rx_byte);
557 /* Called by initialisation code to open comm port in asynchronous mode. */
558 bool FBUS_OpenSerial(void)
560 /* Uncomment, if want to test first method for DLR3 */
561 // unsigned char req[3] = {"AT\r"};
562 // unsigned char req2[5] = {"AT&F\r"};
563 // unsigned char req3[13] = {"AT*NOKIAFBUS\r"};
567 // GSM_Information *GSMINFOCOPY;
568 // GSM_Functions *GSMCOPY;
570 switch (CurrentConnectionType) {
574 fprintf(stdout, _("Setting cable for FBUS communication...\n"));
577 device_changespeed(115200);
580 The data suite cable has some electronics built into the connector. This of
581 course needs a power supply of some sorts to operate properly.
583 In this case power is drawn off the handshaking lines of the PC. DTR has to
584 be set and RTS have to be cleared, thus if you use a terminal program (that
585 does not set the handshaking lines to these conditions) you will get weird
586 results. It will not set them like this since if Request To Send (RTS) is
587 not set the other party will not send any data (in hardware handshaking)
588 and if DTS is not set (handshaking = none) the cable will not receive
590 /* clearing the RTS bit and setting the DTR bit*/
591 device_setdtrrts(1, 0);
597 fprintf(stdout, _("Setting DLR3 cable for FBUS communication...\n"));
600 /* There are 2 ways to init DLR in FBUS: Here is first described by
601 Reuben Harris [reuben.harris@snowvalley.com] and used in Logo Manager,
602 1. Firstly set the connection baud to 19200, DTR off, RTS off,
603 Parity on, one stop bit,
604 2. Send "AT\r\n". The response should be "AT\r\n\r\nOK\r\n".
605 3. Send "AT&F\r\n". The response should be "AT&F\r\n\r\nOK\r\n".
606 4. Send "AT*NOKIAFBUS\r\n". The response should be
607 "AT*NOKIAFBUS\r\n\r\nOK\r\n".
608 5. Set speed to 115200
610 This is one should be used by us, because seems to be compatible with more
611 phones. But we make something wrong and often phones don't want to start transmision */
613 /* Uncomment and test if want */
614 // device_changespeed(19200);
616 /*leave RTS low, DTR low for duration of session.*/
617 // device_setdtrrts(0, 0);
619 /* Making copy of pointers */
621 // GSMINFOCOPY =GSM_Info;
623 /* Set pointers to relevant addresses - new "AT" module here is required */
624 // GSM = &Nat_Functions;
625 // GSM_Info = &Nat_Information;
627 /* Note: We change Protocol inside function pointed by it.
628 That's why in FBUS_RX_StateMachine we must check it (changing
629 Protocol is not enough), This is for correct work and be sure... */
630 // Protocol = &AT_Functions;
632 // error=N6110_SendMessageSequence (50, &CurrentGetHWError, 3, 0x00, req);
633 // if (error!=GE_NONE) return false;
635 // error=N6110_SendMessageSequence (50, &CurrentGetHWError, 5, 0x00, req2);
636 // if (error!=GE_NONE) return false;
638 // error=N6110_SendMessageSequence (50, &CurrentGetHWError, 13, 0x00, req3);
639 // if (error!=GE_NONE) return false;
641 /* Returning to old protocol */
642 // Protocol = &FBUS_Functions;
644 /* Returning to old module */
646 // GSM_Info = GSMINFOCOPY;
648 // device_changespeed(115200);
650 /* Second method for DLR3:
651 Used by some 7110 soft, but not compatible with some other
652 phones supporting DLR3 - 7160, NCP2.0
653 Used in this moment in mygnokii
656 device_changespeed(115200);
658 /*leave RTS low, DTR low for duration of session.*/
659 device_setdtrrts(0, 0);
663 CurrentConnectionType=GCT_FBUS;
667 /* It's more complicated and not done here */
671 /* It's more complicated and not done here */
676 fprintf(stdout,_("Wrong connection type for fbus module. Inform marcin-wiacek@topnet.pl about it\n"));
684 /* Initialise variables and state machine. */
685 GSM_Error FBUS_Initialise(char *port_device, char *initlength,
686 GSM_ConnectionType connection,
687 void (*rlp_callback)(RLP_F96Frame *frame))
690 if (!StartConnection (port_device,false,connection))
691 return GE_INTERNALERROR;
693 CurrentConnectionType = connection;
695 if (FBUS_OpenSerial() != true) return GE_INTERNALERROR;