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;
64 char *N61_PrintDevice(int Device)
68 case FBUS_DEVICE_PHONE:return _("Phone");
69 case FBUS_DEVICE_PC :return _("PC");
70 default :return _("Unknown");
75 /* N61_RX_DisplayMessage is called when a message we don't know about is
76 received so that the user can see what is going back and forth, and perhaps
77 shed some more light/explain another message type! */
78 void N61_RX_DisplayMessage()
81 fprintf(stdout, _("Msg Dest: %s\n"), N61_PrintDevice(MessageDestination));
82 fprintf(stdout, _("Msg Source: %s\n"), N61_PrintDevice(MessageSource));
83 fprintf(stdout, _("Msg Type: %02x\n"), MessageType);
85 hexdump(MessageLength-2,MessageBuffer);
88 AppendLog(MessageBuffer,MessageLength-2,true);
91 /* Prepares the message header and sends it, prepends the message start byte
92 (0x1e) and other values according the value specified when called.
93 Calculates checksum and then sends the lot down the pipe... */
94 int FBUS_SendFrame(u16 message_length, u8 message_type, u8 *buffer) {
96 /* Originally out_buffer[FBUS_MAX_CONTENT_LENGTH + 2],
97 but it made problems with MBUS */
100 int count, current=0;
101 unsigned char checksum;
103 /* FIXME - we should check for the message length ... */
105 /* Now construct the message header. */
107 if (CurrentConnectionType==GCT_FBUS)
108 out_buffer[current++] = FBUS_FRAME_ID; /* Start of the frame indicator */
110 out_buffer[current++] = FBUS_IR_FRAME_ID; /* Start of the frame indicator */
112 out_buffer[current++] = FBUS_DEVICE_PHONE; /* Destination */
114 out_buffer[current++] = FBUS_DEVICE_PC; /* Source */
116 out_buffer[current++] = message_type; /* Type */
118 out_buffer[current++] = 0; /* Length1 */
119 out_buffer[current++] = message_length; /* Length2 */
121 /* Copy in data if any. */
122 if (message_length != 0) {
123 memcpy(out_buffer + current, buffer, message_length);
124 current+=message_length;
127 /* If the message length is odd we should add pad byte 0x00 */
128 if (message_length % 2)
129 out_buffer[current++]=0x00;
131 /* Now calculate checksums over entire message and append to message. */
135 for (count = 0; count < current; count+=2)
136 checksum ^= out_buffer[count];
138 out_buffer[current++] = checksum;
142 for (count = 1; count < current; count+=2)
143 checksum ^= out_buffer[count];
145 out_buffer[current++] = checksum;
148 NULL_TX_DisplayMessage(current, out_buffer);
152 if (!NULL_WritePhone(current,out_buffer))
158 int FBUS_SendMessage(u16 message_length, u8 message_type, u8 *buffer) {
162 u8 frame_buffer[FBUS_MAX_CONTENT_LENGTH + 2];
164 u8 nom, lml; /* number of messages, last message len */
167 seqnum = 0x40 + RequestSequenceNumber;
168 RequestSequenceNumber = (RequestSequenceNumber + 1) & 0x07;
170 if (message_length > FBUS_MAX_CONTENT_LENGTH) {
172 nom = (message_length + FBUS_MAX_CONTENT_LENGTH - 1)
173 / FBUS_MAX_CONTENT_LENGTH;
174 lml = message_length - ((nom - 1) * FBUS_MAX_CONTENT_LENGTH);
176 for (i = 0; i < nom - 1; i++) {
178 memcpy(frame_buffer, buffer + (i * FBUS_MAX_CONTENT_LENGTH),
179 FBUS_MAX_CONTENT_LENGTH);
180 frame_buffer[FBUS_MAX_CONTENT_LENGTH] = nom - i;
181 frame_buffer[FBUS_MAX_CONTENT_LENGTH + 1] = seqnum;
183 FBUS_SendFrame(FBUS_MAX_CONTENT_LENGTH + 2, message_type,
186 seqnum = RequestSequenceNumber;
187 RequestSequenceNumber = (RequestSequenceNumber + 1) & 0x07;
190 memcpy(frame_buffer, buffer + ((nom - 1) * FBUS_MAX_CONTENT_LENGTH), lml);
191 frame_buffer[lml] = 0x01;
192 frame_buffer[lml + 1] = seqnum;
193 FBUS_SendFrame(lml + 2, message_type, frame_buffer);
197 memcpy(frame_buffer, buffer, message_length);
198 frame_buffer[message_length] = 0x01;
199 frame_buffer[message_length + 1] = seqnum;
200 FBUS_SendFrame(message_length + 2, message_type, frame_buffer);
206 int FBUS_SendAck(u8 message_type, u8 message_seq) {
208 unsigned char request[6];
210 request[0] = message_type;
211 request[1] = message_seq;
214 fprintf(stdout, _("[Sending Ack of type %02x, seq: %x]\n"), message_type, message_seq);
217 return FBUS_SendFrame(2, FBUS_FRTYPE_ACK, request);
220 /* Applications should call FBUS_Terminate to shut down the FBUS thread and
221 close the serial port. */
222 void FBUS_Terminate(void)
224 /* Request termination of thread */
225 CurrentRequestTerminate = true;
227 /* Close serial port. */
231 /* RX_State machine for receive handling. Called once for each character
232 received from the phone/phone. */
234 void FBUS_RX_StateMachine(unsigned char rx_byte) {
236 static struct timeval time_now, time_last, time_diff;
238 static int checksum[2];
242 // if (CurrentConnectionType==GCT_DLR3) {
243 // AT_RX_StateMachine(rx_byte);
247 /* For model sniff only display received bytes */
248 if (strcmp(GSM_Info->FBUSModels, "sniff"))
252 /* XOR the byte with the current checksum */
253 checksum[BufferCount&1] ^= rx_byte;
257 /* Messages from the phone start with an 0x1e (FBUS) or 0x1c (IR) or 0x1f (MBUS).
258 We use this to "synchronise" with the incoming data stream. However,
259 if we see something else, we assume we have lost sync and we require
260 a gap of at least 5ms before we start looking again. This is because
261 the data part of the frame could contain a byte which looks like the
264 case FBUS_RX_Discarding:
267 gettimeofday(&time_now, NULL);
268 timersub(&time_now, &time_last, &time_diff);
269 if (time_diff.tv_sec == 0 && time_diff.tv_usec < 5000) {
270 time_last = time_now; /* no gap seen, continue discarding */
273 /* else fall through to... */
278 if ((CurrentConnectionType==GCT_FBUS && rx_byte == FBUS_FRAME_ID) ||
279 ((CurrentConnectionType==GCT_Infrared ||
280 CurrentConnectionType==GCT_Tekram) && rx_byte == FBUS_IR_FRAME_ID)) {
284 RX_State = FBUS_RX_GetDestination;
286 /* Initialize checksums. */
287 checksum[0] = rx_byte;
290 /* Lost frame sync */
291 RX_State = FBUS_RX_Discarding;
293 gettimeofday(&time_last, NULL);
298 case FBUS_RX_GetDestination:
300 MessageDestination=rx_byte;
301 RX_State = FBUS_RX_GetSource;
303 /* When there is a checksum error and things get out of sync we have to manage to resync */
304 /* If doing a data call at the time, finding a 0x1e etc is really quite likely in the data stream */
305 /* Then all sorts of horrible things happen because the packet length etc is wrong... */
306 /* Therefore we test here for a destination of 0x0c and return to the top if it is not */
307 if (rx_byte!=FBUS_DEVICE_PC && strstr(GSM_Info->FBUSModels, "sniff")==NULL) {
308 RX_State=FBUS_RX_Sync;
310 fprintf(stdout,"The fbus stream is out of sync - expected 0x0c, got %2x\n",rx_byte);
312 AppendLogText("SYNC\n",false);
317 case FBUS_RX_GetSource:
319 MessageSource=rx_byte;
320 RX_State = FBUS_RX_GetType;
322 /* Source should be 0x00 */
323 if (rx_byte!=FBUS_DEVICE_PHONE && strstr(GSM_Info->FBUSModels, "sniff")==NULL) {
324 RX_State=FBUS_RX_Sync;
326 fprintf(stdout,"The fbus stream is out of sync - expected 0x00, got %2x\n",rx_byte);
328 AppendLogText("SYNC\n",false);
333 case FBUS_RX_GetType:
337 RX_State = FBUS_RX_GetLength1;
341 case FBUS_RX_GetLength1:
345 RX_State = FBUS_RX_GetLength2;
349 case FBUS_RX_GetLength2:
351 /* MW:Here are problems with conversion. For chars 0-127 it's OK, for
352 higher not (probably because rx_byte is char type) - improtant
353 for MBUS. So, I make it double and strange - generally it should be
354 more simple and make simple convert rx_byte into MessageLength */
355 #if defined(__svr4__) || defined(__FreeBSD__)
357 for (i=0;i<rx_byte;i++)
358 MessageLength=MessageLength++;
361 MessageLength = rx_byte;
364 RX_State = FBUS_RX_GetMessage;
368 case FBUS_RX_GetMessage:
370 MessageBuffer[BufferCount] = rx_byte;
373 if (BufferCount>FBUS_MAX_RECEIVE_LENGTH*6) {
375 fprintf(stdout, "FB61: Message buffer overun - resetting\n");
377 AppendLogText("OVERUN\n",false);
379 RX_State = FBUS_RX_Sync;
383 /* If this is the last byte, it's the checksum. */
384 if (BufferCount == MessageLength+(MessageLength%2)+2) {
386 /* Is the checksum correct? */
387 if (checksum[0] == checksum[1]) {
391 if (MessageType==MultiMessageType) {
393 if (MessageLength+MultiMessageLength>FBUS_MAX_RECEIVE_LENGTH*6) {
395 fprintf(stdout, "FB61: Message buffer overun - resetting\n");
397 AppendLogText("OVERUN\n",false);
399 RX_State = FBUS_RX_Sync;
403 /* We copy next part of multiframe message into special buffer */
404 for (i=0;i<MessageLength;i++) {
405 MultiMessageBuffer[i+MultiMessageLength]=MessageBuffer[i];
407 MultiMessageLength=MultiMessageLength+MessageLength-2;
409 FBUS_SendAck(MessageType, MessageBuffer[MessageLength-1] & 0x0f);
411 if ((MessageLength > 1) && (MessageBuffer[MessageLength-2] != 0x01))
414 for (i=0;i<MultiMessageLength+2;i++) {
415 MessageBuffer[i]=MultiMessageBuffer[i];
417 MessageLength=MultiMessageLength+2;
420 /* Do not debug Ack and RLP frames to detail. */
421 if (MessageType != FBUS_FRTYPE_ACK && MessageType != 0xf1)
422 N61_RX_DisplayMessage();
424 GSM->DispatchMessage(MessageLength-2, MessageBuffer, MessageType);
429 /* We do not want to send ACK of ACKs and ACK of RLP frames. */
430 if (MessageType != FBUS_FRTYPE_ACK && MessageType != 0xf1) {
431 FBUS_SendAck(MessageType, MessageBuffer[MessageLength-1] & 0x0f);
433 if ((MessageLength > 1) && (MessageBuffer[MessageLength-2] != 0x01))
436 fprintf(stdout,_("Multiframe message in multiframe message !\n"));
437 fprintf(stdout,_("Please report it !\n"));
439 RX_State = FBUS_RX_Sync;
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))
451 /* We copy previous part of multiframe message into special buffer */
453 for (i=0;i<MessageLength-2;i++) {
454 MultiMessageBuffer[i]=MessageBuffer[i];
456 MultiMessageLength=MessageLength-2;
457 MultiMessageType=MessageType;
461 if (!RX_Multiple && MessageDestination!=FBUS_DEVICE_PHONE ) {
462 /* Do not debug Ack and RLP frames to detail. */
463 if (MessageType != FBUS_FRTYPE_ACK && MessageType != 0xf1)
464 N61_RX_DisplayMessage();
466 GSM->DispatchMessage(MessageLength-2, MessageBuffer, MessageType);
470 /* When make debug and message is to phone display it */
471 if (MessageDestination==FBUS_DEVICE_PHONE) {
472 for (i=MessageLength;i>=0;i--)
473 MessageBuffer[i+6]=MessageBuffer[i];
474 MessageBuffer[0]=FBUS_FRAME_ID;
475 MessageBuffer[1]=FBUS_DEVICE_PHONE;
476 MessageBuffer[2]=FBUS_DEVICE_PC;
477 MessageBuffer[3]=MessageType;
479 MessageBuffer[5]=MessageLength;
480 MessageLength=MessageLength+8;
481 if (MessageLength % 2) MessageLength++;
482 NULL_TX_DisplayMessage(MessageLength, MessageBuffer);
488 fprintf(stdout, _("Bad checksum %02x (should be %02x), msg len=%i !\n"),checksum[0],checksum[1],MessageLength);
490 AppendLogText("CHECKSUM\n",false);
492 /* Just to be sure! */
495 RX_State = FBUS_RX_Sync;
502 if (isprint(rx_byte))
503 fprintf(stdout, "[%02x%c]", rx_byte, rx_byte);
505 fprintf(stdout, "[%02x ]", rx_byte);
513 /* Called by initialisation code to open comm port in asynchronous mode. */
514 bool FBUS_OpenSerial(void)
516 /* Uncomment, if want to test first method for DLR3 */
517 // unsigned char req[3] = {"AT\r"};
518 // unsigned char req2[5] = {"AT&F\r"};
519 // unsigned char req3[13] = {"AT*NOKIAFBUS\r"};
523 // GSM_Information *GSMINFOCOPY;
524 // GSM_Functions *GSMCOPY;
526 switch (CurrentConnectionType) {
530 fprintf(stdout, _("Setting cable for FBUS communication...\n"));
533 device_changespeed(115200);
536 The data suite cable has some electronics built into the connector. This of
537 course needs a power supply of some sorts to operate properly.
539 In this case power is drawn off the handshaking lines of the PC. DTR has to
540 be set and RTS have to be cleared, thus if you use a terminal program (that
541 does not set the handshaking lines to these conditions) you will get weird
542 results. It will not set them like this since if Request To Send (RTS) is
543 not set the other party will not send any data (in hardware handshaking)
544 and if DTS is not set (handshaking = none) the cable will not receive
546 /* clearing the RTS bit and setting the DTR bit*/
547 device_setdtrrts(1, 0);
553 fprintf(stdout, _("Setting DLR3 cable for FBUS communication...\n"));
556 /* There are 2 ways to init DLR in FBUS: Here is first described by
557 Reuben Harris [reuben.harris@snowvalley.com] and used in Logo Manager,
558 1. Firstly set the connection baud to 19200, DTR off, RTS off,
559 Parity on, one stop bit,
560 2. Send "AT\r\n". The response should be "AT\r\n\r\nOK\r\n".
561 3. Send "AT&F\r\n". The response should be "AT&F\r\n\r\nOK\r\n".
562 4. Send "AT*NOKIAFBUS\r\n". The response should be
563 "AT*NOKIAFBUS\r\n\r\nOK\r\n".
564 5. Set speed to 115200
566 This is one should be used by us, because seems to be compatible with more
567 phones. But we make something wrong and often phones don't want to start transmision */
569 /* Uncomment and test if want */
570 // device_changespeed(19200);
572 /*leave RTS low, DTR low for duration of session.*/
573 // device_setdtrrts(0, 0);
575 /* Making copy of pointers */
577 // GSMINFOCOPY =GSM_Info;
579 /* Set pointers to relevant addresses - new "AT" module here is required */
580 // GSM = &Nat_Functions;
581 // GSM_Info = &Nat_Information;
583 /* Note: We change Protocol inside function pointed by it.
584 That's why in FBUS_RX_StateMachine we must check it (changing
585 Protocol is not enough), This is for correct work and be sure... */
586 // Protocol = &AT_Functions;
588 // error=N6110_SendMessageSequence (50, &CurrentGetHWError, 3, 0x00, req);
589 // if (error!=GE_NONE) return false;
591 // error=N6110_SendMessageSequence (50, &CurrentGetHWError, 5, 0x00, req2);
592 // if (error!=GE_NONE) return false;
594 // error=N6110_SendMessageSequence (50, &CurrentGetHWError, 13, 0x00, req3);
595 // if (error!=GE_NONE) return false;
597 /* Returning to old protocol */
598 // Protocol = &FBUS_Functions;
600 /* Returning to old module */
602 // GSM_Info = GSMINFOCOPY;
604 // device_changespeed(115200);
606 /* Second method for DLR3:
607 Used by some 7110 soft, but not compatible with some other
608 phones supporting DLR3 - 7160, NCP2.0
609 Used in this moment in mygnokii
612 device_changespeed(115200);
614 /*leave RTS low, DTR low for duration of session.*/
615 device_setdtrrts(0, 0);
619 CurrentConnectionType=GCT_FBUS;
623 /* It's more complicated and not done here */
627 /* It's more complicated and not done here */
632 fprintf(stdout,_("Wrong connection type for fbus module. Inform marcin-wiacek@topnet.pl about it\n"));
640 /* Initialise variables and state machine. */
641 GSM_Error FBUS_Initialise(char *port_device, char *initlength,
642 GSM_ConnectionType connection,
643 void (*rlp_callback)(RLP_F96Frame *frame))
646 if (!StartConnection (port_device,false,connection))
647 return GE_INTERNALERROR;
649 CurrentConnectionType = connection;
651 if (FBUS_OpenSerial() != true) return GE_INTERNALERROR;