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];
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 ((CurrentConnectionType==GCT_Infrared
294 || CurrentConnectionType==GCT_Tekram
296 ) && rx_byte == FBUS_IR_FRAME_ID)) {
300 RX_State = FBUS_RX_GetDestination;
302 /* Initialize checksums. */
303 checksum[0] = rx_byte;
306 /* Lost frame sync */
307 RX_State = FBUS_RX_Discarding;
309 gettimeofday(&time_last, NULL);
314 case FBUS_RX_GetDestination:
316 MessageDestination=rx_byte;
317 RX_State = FBUS_RX_GetSource;
319 /* When there is a checksum error and things get out of sync we have to manage to resync */
320 /* If doing a data call at the time, finding a 0x1e etc is really quite likely in the data stream */
321 /* Then all sorts of horrible things happen because the packet length etc is wrong... */
322 /* Therefore we test here for a destination of 0x0c and return to the top if it is not */
323 if (rx_byte!=FBUS_DEVICE_PC && strstr(GSM_Info->FBUSModels, "sniff")==NULL) {
324 RX_State=FBUS_RX_Sync;
326 fprintf(stdout,"The fbus stream is out of sync - expected 0x0c, got %2x\n",rx_byte);
328 AppendLogText("SYNC\n",false);
333 case FBUS_RX_GetSource:
335 MessageSource=rx_byte;
336 RX_State = FBUS_RX_GetType;
338 /* Source should be 0x00 */
339 if (rx_byte!=FBUS_DEVICE_PHONE && strstr(GSM_Info->FBUSModels, "sniff")==NULL) {
340 RX_State=FBUS_RX_Sync;
342 fprintf(stdout,"The fbus stream is out of sync - expected 0x00, got %2x\n",rx_byte);
344 AppendLogText("SYNC\n",false);
349 case FBUS_RX_GetType:
353 RX_State = FBUS_RX_GetLength1;
357 case FBUS_RX_GetLength1:
361 RX_State = FBUS_RX_GetLength2;
365 case FBUS_RX_GetLength2:
367 /* MW:Here are problems with conversion. For chars 0-127 it's OK, for
368 higher not (probably because rx_byte is char type) - improtant
369 for MBUS. So, I make it double and strange - generally it should be
370 more simple and make simple convert rx_byte into MessageLength */
371 #if defined(__svr4__) || defined(__FreeBSD__)
373 for (i=0;i<rx_byte;i++)
374 MessageLength=MessageLength++;
377 MessageLength = rx_byte;
380 RX_State = FBUS_RX_GetMessage;
384 case FBUS_RX_GetMessage:
386 MessageBuffer[BufferCount] = rx_byte;
389 if (BufferCount>FBUS_MAX_RECEIVE_LENGTH*6) {
391 fprintf(stdout, "FB61: Message buffer overun - resetting\n");
393 AppendLogText("OVERUN\n",false);
395 RX_State = FBUS_RX_Sync;
399 /* If this is the last byte, it's the checksum. */
400 if (BufferCount == MessageLength+(MessageLength%2)+2) {
402 /* Is the checksum correct? */
403 if (checksum[0] == checksum[1]) {
407 if (MessageType==MultiMessageType) {
409 if (MessageLength+MultiMessageLength>FBUS_MAX_RECEIVE_LENGTH*6) {
411 fprintf(stdout, "FB61: Message buffer overun - resetting\n");
413 AppendLogText("OVERUN\n",false);
415 RX_State = FBUS_RX_Sync;
419 /* We copy next part of multiframe message into special buffer */
420 for (i=0;i<MessageLength;i++) {
421 MultiMessageBuffer[i+MultiMessageLength]=MessageBuffer[i];
423 MultiMessageLength=MultiMessageLength+MessageLength-2;
425 FBUS_SendAck(MessageType, MessageBuffer[MessageLength-1] & 0x0f);
427 if ((MessageLength > 1) && (MessageBuffer[MessageLength-2] != 0x01))
430 for (i=0;i<MultiMessageLength+2;i++) {
431 MessageBuffer[i]=MultiMessageBuffer[i];
433 MessageLength=MultiMessageLength+2;
436 /* Do not debug Ack and RLP frames to detail. */
437 if (MessageType != FBUS_FRTYPE_ACK && MessageType != 0xf1)
438 N61_RX_DisplayMessage();
440 GSM->DispatchMessage(MessageLength-2, MessageBuffer, MessageType);
445 /* We do not want to send ACK of ACKs and ACK of RLP frames. */
446 if (MessageType != FBUS_FRTYPE_ACK && MessageType != 0xf1) {
447 FBUS_SendAck(MessageType, MessageBuffer[MessageLength-1] & 0x0f);
449 if ((MessageLength > 1) && (MessageBuffer[MessageLength-2] != 0x01))
452 fprintf(stdout,_("Multiframe message in multiframe message !\n"));
453 fprintf(stdout,_("Please report it !\n"));
455 RX_State = FBUS_RX_Sync;
461 /* We do not want to send ACK of ACKs and ACK of RLP frames. */
462 if (MessageType != FBUS_FRTYPE_ACK && MessageType != 0xf1) {
463 FBUS_SendAck(MessageType, MessageBuffer[MessageLength-1] & 0x0f);
465 if ((MessageLength > 1) && (MessageBuffer[MessageLength-2] != 0x01))
467 /* We copy previous part of multiframe message into special buffer */
469 for (i=0;i<MessageLength-2;i++) {
470 MultiMessageBuffer[i]=MessageBuffer[i];
472 MultiMessageLength=MessageLength-2;
473 MultiMessageType=MessageType;
477 if (!RX_Multiple && MessageDestination!=FBUS_DEVICE_PHONE ) {
478 /* Do not debug Ack and RLP frames to detail. */
479 if (MessageType != FBUS_FRTYPE_ACK && MessageType != 0xf1)
480 N61_RX_DisplayMessage();
482 GSM->DispatchMessage(MessageLength-2, MessageBuffer, MessageType);
486 /* When make debug and message is to phone display it */
487 if (MessageDestination==FBUS_DEVICE_PHONE) {
488 for (i=MessageLength;i>=0;i--)
489 MessageBuffer[i+6]=MessageBuffer[i];
490 MessageBuffer[0]=FBUS_FRAME_ID;
491 MessageBuffer[1]=FBUS_DEVICE_PHONE;
492 MessageBuffer[2]=FBUS_DEVICE_PC;
493 MessageBuffer[3]=MessageType;
495 MessageBuffer[5]=MessageLength;
496 MessageLength=MessageLength+8;
497 if (MessageLength % 2) MessageLength++;
498 NULL_TX_DisplayMessage(MessageLength, MessageBuffer);
504 fprintf(stdout, _("Bad checksum %02x (should be %02x), msg len=%i !\n"),checksum[0],checksum[1],MessageLength);
506 AppendLogText("CHECKSUM\n",false);
508 /* Just to be sure! */
511 RX_State = FBUS_RX_Sync;
518 if (isprint(rx_byte))
519 fprintf(stdout, "[%02x%c]", rx_byte, rx_byte);
521 fprintf(stdout, "[%02x ]", rx_byte);
527 /* Called by initialisation code to open comm port in asynchronous mode. */
528 static bool FBUS_OpenSerial(void)
531 /* Uncomment, if want to test first method for DLR3 */
532 unsigned char req[3] = {"AT\r"};
533 unsigned char req2[5] = {"AT&F\r"};
534 unsigned char req3[13] = {"AT*NOKIAFBUS\r"};
537 switch (CurrentConnectionType) {
541 fprintf(stdout, _("Setting cable for FBUS communication...\n"));
544 device_changespeed(115200);
547 The data suite cable has some electronics built into the connector. This of
548 course needs a power supply of some sorts to operate properly.
550 In this case power is drawn off the handshaking lines of the PC. DTR has to
551 be set and RTS have to be cleared, thus if you use a terminal program (that
552 does not set the handshaking lines to these conditions) you will get weird
553 results. It will not set them like this since if Request To Send (RTS) is
554 not set the other party will not send any data (in hardware handshaking)
555 and if DTS is not set (handshaking = none) the cable will not receive
557 /* clearing the RTS bit and setting the DTR bit*/
558 device_setdtrrts(1, 0);
565 fprintf(stdout, _("Setting DLR3 cable for FBUS communication...\n"));
568 /* There are 2 ways to init DLR in FBUS: Here is first described by
569 Reuben Harris [reuben.harris@snowvalley.com] and used in Logo Manager,
570 1. Firstly set the connection baud to 19200, DTR off, RTS off,
571 Parity on, one stop bit,
572 2. Send "AT\r\n". The response should be "AT\r\n\r\nOK\r\n".
573 3. Send "AT&F\r\n". The response should be "AT&F\r\n\r\nOK\r\n".
574 4. Send "AT*NOKIAFBUS\r\n". The response should be
575 "AT*NOKIAFBUS\r\n\r\nOK\r\n".
576 5. Set speed to 115200
577 This seems to be compatible with more phones*/
579 device_changespeed(19200);
581 /*leave RTS low, DTR low for duration of session.*/
582 device_setdtrrts(0, 0);
584 Protocol->WritePhone (3,req );usleep(300);
585 Protocol->WritePhone (5,req2);usleep(300);
586 Protocol->WritePhone(13,req3);usleep(300);
588 device_changespeed(115200);
590 // /* Second method for DLR3:
591 // Used by some 7110 soft, but not compatible with some other
592 // phones supporting DLR3 - 7160, NCP2.0*/
593 // device_changespeed(115200);
594 // /*leave RTS low, DTR low for duration of session.*/
595 // device_setdtrrts(0, 0);
598 CurrentConnectionType=GCT_FBUS;
603 /* It's more complicated and not done here */
608 /* It's more complicated and not done here */
614 fprintf(stdout,_("Wrong connection type for fbus module. Inform marcin-wiacek@topnet.pl about it\n"));
622 /* Initialise variables and state machine. */
623 static GSM_Error FBUS_Initialise(char *port_device, char *initlength,
624 GSM_ConnectionType connection,
625 void (*rlp_callback)(RLP_F96Frame *frame))
628 if (!StartConnection (port_device,false,connection))
629 return GE_INTERNALERROR;
631 CurrentConnectionType = connection;
633 if (FBUS_OpenSerial() != true) return GE_INTERNALERROR;