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);
165 if (!NULL_WritePhone(current,out_buffer))
171 int FBUS_SendMessage(u16 message_length, u8 message_type, u8 *buffer) {
175 u8 frame_buffer[FBUS_MAX_CONTENT_LENGTH + 2];
177 u8 nom, lml; /* number of messages, last message len */
180 seqnum = 0x40 + RequestSequenceNumber;
181 RequestSequenceNumber = (RequestSequenceNumber + 1) & 0x07;
183 if (message_length > FBUS_MAX_CONTENT_LENGTH) {
185 nom = (message_length + FBUS_MAX_CONTENT_LENGTH - 1)
186 / FBUS_MAX_CONTENT_LENGTH;
187 lml = message_length - ((nom - 1) * FBUS_MAX_CONTENT_LENGTH);
189 for (i = 0; i < nom - 1; i++) {
191 memcpy(frame_buffer, buffer + (i * FBUS_MAX_CONTENT_LENGTH),
192 FBUS_MAX_CONTENT_LENGTH);
193 frame_buffer[FBUS_MAX_CONTENT_LENGTH] = nom - i;
194 frame_buffer[FBUS_MAX_CONTENT_LENGTH + 1] = seqnum;
196 FBUS_SendFrame(FBUS_MAX_CONTENT_LENGTH + 2, message_type,
199 seqnum = RequestSequenceNumber;
200 RequestSequenceNumber = (RequestSequenceNumber + 1) & 0x07;
203 memcpy(frame_buffer, buffer + ((nom - 1) * FBUS_MAX_CONTENT_LENGTH), lml);
204 frame_buffer[lml] = 0x01;
205 frame_buffer[lml + 1] = seqnum;
206 FBUS_SendFrame(lml + 2, message_type, frame_buffer);
210 memcpy(frame_buffer, buffer, message_length);
211 frame_buffer[message_length] = 0x01;
212 frame_buffer[message_length + 1] = seqnum;
213 FBUS_SendFrame(message_length + 2, message_type, frame_buffer);
219 static int FBUS_SendAck(u8 message_type, u8 message_seq) {
221 unsigned char request[6];
223 request[0] = message_type;
224 request[1] = message_seq;
227 fprintf(stdout, _("[Sending Ack of type %02x, seq: %x]\n"), message_type, message_seq);
230 return FBUS_SendFrame(2, FBUS_FRTYPE_ACK, request);
233 /* Applications should call FBUS_Terminate to shut down the FBUS thread and
234 close the serial port. */
235 void FBUS_Terminate(void)
237 /* Request termination of thread */
238 CurrentRequestTerminate = true;
240 /* Close serial port. */
244 /* RX_State machine for receive handling. Called once for each character
245 received from the phone/phone. */
247 void FBUS_RX_StateMachine(unsigned char rx_byte) {
249 static struct timeval time_now, time_last, time_diff;
251 static int checksum[2];
255 // if (CurrentConnectionType==GCT_DLR3) {
256 // AT_RX_StateMachine(rx_byte);
260 /* For model sniff only display received bytes */
261 if (strcmp(GSM_Info->FBUSModels, "sniff"))
265 /* XOR the byte with the current checksum */
266 checksum[BufferCount&1] ^= rx_byte;
270 /* Messages from the phone start with an 0x1e (FBUS) or 0x1c (IR) or 0x1f (MBUS).
271 We use this to "synchronise" with the incoming data stream. However,
272 if we see something else, we assume we have lost sync and we require
273 a gap of at least 5ms before we start looking again. This is because
274 the data part of the frame could contain a byte which looks like the
277 case FBUS_RX_Discarding:
280 gettimeofday(&time_now, NULL);
281 timersub(&time_now, &time_last, &time_diff);
282 if (time_diff.tv_sec == 0 && time_diff.tv_usec < 5000) {
283 time_last = time_now; /* no gap seen, continue discarding */
286 /* else fall through to... */
291 if ((CurrentConnectionType==GCT_FBUS && rx_byte == FBUS_FRAME_ID) ||
292 0/*((CurrentConnectionType==GCT_Infrared ||
293 CurrentConnectionType==GCT_Tekram) && rx_byte == FBUS_IR_FRAME_ID)*/) {
297 RX_State = FBUS_RX_GetDestination;
299 /* Initialize checksums. */
300 checksum[0] = rx_byte;
303 /* Lost frame sync */
304 RX_State = FBUS_RX_Discarding;
306 gettimeofday(&time_last, NULL);
311 case FBUS_RX_GetDestination:
313 MessageDestination=rx_byte;
314 RX_State = FBUS_RX_GetSource;
316 /* When there is a checksum error and things get out of sync we have to manage to resync */
317 /* If doing a data call at the time, finding a 0x1e etc is really quite likely in the data stream */
318 /* Then all sorts of horrible things happen because the packet length etc is wrong... */
319 /* Therefore we test here for a destination of 0x0c and return to the top if it is not */
320 if (rx_byte!=FBUS_DEVICE_PC && strstr(GSM_Info->FBUSModels, "sniff")==NULL) {
321 RX_State=FBUS_RX_Sync;
323 fprintf(stdout,"The fbus stream is out of sync - expected 0x0c, got %2x\n",rx_byte);
325 AppendLogText("SYNC\n",false);
330 case FBUS_RX_GetSource:
332 MessageSource=rx_byte;
333 RX_State = FBUS_RX_GetType;
335 /* Source should be 0x00 */
336 if (rx_byte!=FBUS_DEVICE_PHONE && strstr(GSM_Info->FBUSModels, "sniff")==NULL) {
337 RX_State=FBUS_RX_Sync;
339 fprintf(stdout,"The fbus stream is out of sync - expected 0x00, got %2x\n",rx_byte);
341 AppendLogText("SYNC\n",false);
346 case FBUS_RX_GetType:
350 RX_State = FBUS_RX_GetLength1;
354 case FBUS_RX_GetLength1:
358 RX_State = FBUS_RX_GetLength2;
362 case FBUS_RX_GetLength2:
364 /* MW:Here are problems with conversion. For chars 0-127 it's OK, for
365 higher not (probably because rx_byte is char type) - improtant
366 for MBUS. So, I make it double and strange - generally it should be
367 more simple and make simple convert rx_byte into MessageLength */
368 #if defined(__svr4__) || defined(__FreeBSD__)
370 for (i=0;i<rx_byte;i++)
371 MessageLength=MessageLength++;
374 MessageLength = rx_byte;
377 RX_State = FBUS_RX_GetMessage;
381 case FBUS_RX_GetMessage:
383 MessageBuffer[BufferCount] = rx_byte;
386 if (BufferCount>FBUS_MAX_RECEIVE_LENGTH*6) {
388 fprintf(stdout, "FB61: Message buffer overun - resetting\n");
390 AppendLogText("OVERUN\n",false);
392 RX_State = FBUS_RX_Sync;
396 /* If this is the last byte, it's the checksum. */
397 if (BufferCount == MessageLength+(MessageLength%2)+2) {
399 /* Is the checksum correct? */
400 if (checksum[0] == checksum[1]) {
404 if (MessageType==MultiMessageType) {
406 if (MessageLength+MultiMessageLength>FBUS_MAX_RECEIVE_LENGTH*6) {
408 fprintf(stdout, "FB61: Message buffer overun - resetting\n");
410 AppendLogText("OVERUN\n",false);
412 RX_State = FBUS_RX_Sync;
416 /* We copy next part of multiframe message into special buffer */
417 for (i=0;i<MessageLength;i++) {
418 MultiMessageBuffer[i+MultiMessageLength]=MessageBuffer[i];
420 MultiMessageLength=MultiMessageLength+MessageLength-2;
422 FBUS_SendAck(MessageType, MessageBuffer[MessageLength-1] & 0x0f);
424 if ((MessageLength > 1) && (MessageBuffer[MessageLength-2] != 0x01))
427 for (i=0;i<MultiMessageLength+2;i++) {
428 MessageBuffer[i]=MultiMessageBuffer[i];
430 MessageLength=MultiMessageLength+2;
433 /* Do not debug Ack and RLP frames to detail. */
434 if (MessageType != FBUS_FRTYPE_ACK && MessageType != 0xf1)
435 N61_RX_DisplayMessage();
437 GSM->DispatchMessage(MessageLength, MessageBuffer, MessageType);
442 /* We do not want to send ACK of ACKs and ACK of RLP frames. */
443 if (MessageType != FBUS_FRTYPE_ACK && MessageType != 0xf1) {
444 FBUS_SendAck(MessageType, MessageBuffer[MessageLength-1] & 0x0f);
446 if ((MessageLength > 1) && (MessageBuffer[MessageLength-2] != 0x01))
449 fprintf(stdout,_("Multiframe message in multiframe message !\n"));
450 fprintf(stdout,_("Please report it !\n"));
452 RX_State = FBUS_RX_Sync;
458 /* We do not want to send ACK of ACKs and ACK of RLP frames. */
459 if (MessageType != FBUS_FRTYPE_ACK && MessageType != 0xf1) {
460 FBUS_SendAck(MessageType, MessageBuffer[MessageLength-1] & 0x0f);
462 if ((MessageLength > 1) && (MessageBuffer[MessageLength-2] != 0x01))
464 /* We copy previous part of multiframe message into special buffer */
466 for (i=0;i<MessageLength-2;i++) {
467 MultiMessageBuffer[i]=MessageBuffer[i];
469 MultiMessageLength=MessageLength-2;
470 MultiMessageType=MessageType;
474 if (!RX_Multiple && MessageDestination!=FBUS_DEVICE_PHONE ) {
475 /* Do not debug Ack and RLP frames to detail. */
476 if (MessageType != FBUS_FRTYPE_ACK && MessageType != 0xf1)
477 N61_RX_DisplayMessage();
479 GSM->DispatchMessage(MessageLength, MessageBuffer, MessageType);
483 /* When make debug and message is to phone display it */
484 if (MessageDestination==FBUS_DEVICE_PHONE) {
485 for (i=MessageLength;i>=0;i--)
486 MessageBuffer[i+6]=MessageBuffer[i];
487 MessageBuffer[0]=FBUS_FRAME_ID;
488 MessageBuffer[1]=FBUS_DEVICE_PHONE;
489 MessageBuffer[2]=FBUS_DEVICE_PC;
490 MessageBuffer[3]=MessageType;
492 MessageBuffer[5]=MessageLength;
493 MessageLength=MessageLength+8;
494 if (MessageLength % 2) MessageLength++;
495 NULL_TX_DisplayMessage(MessageLength, MessageBuffer);
501 fprintf(stdout, _("Bad checksum %02x (should be %02x), msg len=%i !\n"),checksum[0],checksum[1],MessageLength);
503 AppendLogText("CHECKSUM\n",false);
505 /* Just to be sure! */
508 RX_State = FBUS_RX_Sync;
515 if (isprint(rx_byte))
516 fprintf(stdout, "[%02x%c]", rx_byte, rx_byte);
518 fprintf(stdout, "[%02x ]", rx_byte);
526 /* Called by initialisation code to open comm port in asynchronous mode. */
527 static bool FBUS_OpenSerial(void)
529 /* Uncomment, if want to test first method for DLR3 */
530 // unsigned char req[3] = {"AT\r"};
531 // unsigned char req2[5] = {"AT&F\r"};
532 // unsigned char req3[13] = {"AT*NOKIAFBUS\r"};
536 // GSM_Information *GSMINFOCOPY;
537 // GSM_Functions *GSMCOPY;
539 switch (CurrentConnectionType) {
543 fprintf(stdout, _("Setting cable for FBUS communication...\n"));
546 device_changespeed(115200);
549 The data suite cable has some electronics built into the connector. This of
550 course needs a power supply of some sorts to operate properly.
552 In this case power is drawn off the handshaking lines of the PC. DTR has to
553 be set and RTS have to be cleared, thus if you use a terminal program (that
554 does not set the handshaking lines to these conditions) you will get weird
555 results. It will not set them like this since if Request To Send (RTS) is
556 not set the other party will not send any data (in hardware handshaking)
557 and if DTS is not set (handshaking = none) the cable will not receive
559 /* clearing the RTS bit and setting the DTR bit*/
560 device_setdtrrts(1, 0);
567 fprintf(stdout, _("Setting DLR3 cable for FBUS communication...\n"));
570 /* There are 2 ways to init DLR in FBUS: Here is first described by
571 Reuben Harris [reuben.harris@snowvalley.com] and used in Logo Manager,
572 1. Firstly set the connection baud to 19200, DTR off, RTS off,
573 Parity on, one stop bit,
574 2. Send "AT\r\n". The response should be "AT\r\n\r\nOK\r\n".
575 3. Send "AT&F\r\n". The response should be "AT&F\r\n\r\nOK\r\n".
576 4. Send "AT*NOKIAFBUS\r\n". The response should be
577 "AT*NOKIAFBUS\r\n\r\nOK\r\n".
578 5. Set speed to 115200
580 This is one should be used by us, because seems to be compatible with more
581 phones. But we make something wrong and often phones don't want to start transmision */
583 /* Uncomment and test if want */
584 // device_changespeed(19200);
586 /*leave RTS low, DTR low for duration of session.*/
587 // device_setdtrrts(0, 0);
589 /* Making copy of pointers */
591 // GSMINFOCOPY =GSM_Info;
593 /* Set pointers to relevant addresses - new "AT" module here is required */
594 // GSM = &Nat_Functions;
595 // GSM_Info = &Nat_Information;
597 /* Note: We change Protocol inside function pointed by it.
598 That's why in FBUS_RX_StateMachine we must check it (changing
599 Protocol is not enough), This is for correct work and be sure... */
600 // Protocol = &AT_Functions;
602 // error=N6110_SendMessageSequence (50, &CurrentGetHWError, 3, 0x00, req);
603 // if (error!=GE_NONE) return false;
605 // error=N6110_SendMessageSequence (50, &CurrentGetHWError, 5, 0x00, req2);
606 // if (error!=GE_NONE) return false;
608 // error=N6110_SendMessageSequence (50, &CurrentGetHWError, 13, 0x00, req3);
609 // if (error!=GE_NONE) return false;
611 /* Returning to old protocol */
612 // Protocol = &FBUS_Functions;
614 /* Returning to old module */
616 // GSM_Info = GSMINFOCOPY;
618 // device_changespeed(115200);
620 /* Second method for DLR3:
621 Used by some 7110 soft, but not compatible with some other
622 phones supporting DLR3 - 7160, NCP2.0
623 Used in this moment in mygnokii
626 device_changespeed(115200);
628 /*leave RTS low, DTR low for duration of session.*/
629 device_setdtrrts(0, 0);
633 CurrentConnectionType=GCT_FBUS;
637 /* It's more complicated and not done here */
641 /* It's more complicated and not done here */
647 fprintf(stdout,_("Wrong connection type for fbus module. Inform marcin-wiacek@topnet.pl about it\n"));
655 /* Initialise variables and state machine. */
656 static GSM_Error FBUS_Initialise(char *port_device, char *initlength,
657 GSM_ConnectionType connection,
658 void (*rlp_callback)(RLP_F96Frame *frame))
661 if (!StartConnection (port_device,false,connection))
662 return GE_INTERNALERROR;
664 CurrentConnectionType = connection;
666 if (FBUS_OpenSerial() != true) return GE_INTERNALERROR;