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];
243 /* For model sniff only display received bytes */
244 if (strcmp(GSM_Info->FBUSModels, "sniff"))
248 /* XOR the byte with the current checksum */
249 checksum[BufferCount&1] ^= rx_byte;
253 /* Messages from the phone start with an 0x1e (FBUS) or 0x1c (IR) or 0x1f (MBUS).
254 We use this to "synchronise" with the incoming data stream. However,
255 if we see something else, we assume we have lost sync and we require
256 a gap of at least 5ms before we start looking again. This is because
257 the data part of the frame could contain a byte which looks like the
260 case FBUS_RX_Discarding:
263 gettimeofday(&time_now, NULL);
264 timersub(&time_now, &time_last, &time_diff);
265 if (time_diff.tv_sec == 0 && time_diff.tv_usec < 5000) {
266 time_last = time_now; /* no gap seen, continue discarding */
269 /* else fall through to... */
274 if ((CurrentConnectionType==GCT_FBUS && rx_byte == FBUS_FRAME_ID) ||
275 ((CurrentConnectionType==GCT_Infrared ||
276 CurrentConnectionType==GCT_Tekram) && rx_byte == FBUS_IR_FRAME_ID)) {
280 RX_State = FBUS_RX_GetDestination;
282 /* Initialize checksums. */
283 checksum[0] = rx_byte;
286 /* Lost frame sync */
287 RX_State = FBUS_RX_Discarding;
289 gettimeofday(&time_last, NULL);
294 case FBUS_RX_GetDestination:
296 MessageDestination=rx_byte;
297 RX_State = FBUS_RX_GetSource;
299 /* When there is a checksum error and things get out of sync we have to manage to resync */
300 /* If doing a data call at the time, finding a 0x1e etc is really quite likely in the data stream */
301 /* Then all sorts of horrible things happen because the packet length etc is wrong... */
302 /* Therefore we test here for a destination of 0x0c and return to the top if it is not */
303 if (rx_byte!=FBUS_DEVICE_PC && strstr(GSM_Info->FBUSModels, "sniff")==NULL) {
304 RX_State=FBUS_RX_Sync;
306 fprintf(stdout,"The fbus stream is out of sync - expected 0x0c, got %2x\n",rx_byte);
308 AppendLogText("SYNC\n",false);
313 case FBUS_RX_GetSource:
315 MessageSource=rx_byte;
316 RX_State = FBUS_RX_GetType;
318 /* Source should be 0x00 */
319 if (rx_byte!=FBUS_DEVICE_PHONE && strstr(GSM_Info->FBUSModels, "sniff")==NULL) {
320 RX_State=FBUS_RX_Sync;
322 fprintf(stdout,"The fbus stream is out of sync - expected 0x00, got %2x\n",rx_byte);
324 AppendLogText("SYNC\n",false);
329 case FBUS_RX_GetType:
333 RX_State = FBUS_RX_GetLength1;
337 case FBUS_RX_GetLength1:
341 RX_State = FBUS_RX_GetLength2;
345 case FBUS_RX_GetLength2:
347 /* MW:Here are problems with conversion. For chars 0-127 it's OK, for
348 higher not (probably because rx_byte is char type) - improtant
349 for MBUS. So, I make it double and strange - generally it should be
350 more simple and make simple convert rx_byte into MessageLength */
351 #if defined(__svr4__) || defined(__FreeBSD__)
353 for (i=0;i<rx_byte;i++)
354 MessageLength=MessageLength++;
357 MessageLength = rx_byte;
360 RX_State = FBUS_RX_GetMessage;
364 case FBUS_RX_GetMessage:
366 MessageBuffer[BufferCount] = rx_byte;
369 if (BufferCount>FBUS_MAX_RECEIVE_LENGTH*6) {
371 fprintf(stdout, "FB61: Message buffer overun - resetting\n");
373 AppendLogText("OVERUN\n",false);
375 RX_State = FBUS_RX_Sync;
379 /* If this is the last byte, it's the checksum. */
380 if (BufferCount == MessageLength+(MessageLength%2)+2) {
382 /* Is the checksum correct? */
383 if (checksum[0] == checksum[1]) {
387 if (MessageType==MultiMessageType) {
389 if (MessageLength+MultiMessageLength>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 /* We copy next part of multiframe message into special buffer */
400 for (i=0;i<MessageLength;i++) {
401 MultiMessageBuffer[i+MultiMessageLength]=MessageBuffer[i];
403 MultiMessageLength=MultiMessageLength+MessageLength-2;
405 FBUS_SendAck(MessageType, MessageBuffer[MessageLength-1] & 0x0f);
407 if ((MessageLength > 1) && (MessageBuffer[MessageLength-2] != 0x01))
410 for (i=0;i<MultiMessageLength+2;i++) {
411 MessageBuffer[i]=MultiMessageBuffer[i];
413 MessageLength=MultiMessageLength+2;
416 /* Do not debug Ack and RLP frames to detail. */
417 if (MessageType != FBUS_FRTYPE_ACK && MessageType != 0xf1)
418 N61_RX_DisplayMessage();
420 GSM->DispatchMessage(MessageLength-2, MessageBuffer, MessageType);
425 /* We do not want to send ACK of ACKs and ACK of RLP frames. */
426 if (MessageType != FBUS_FRTYPE_ACK && MessageType != 0xf1) {
427 FBUS_SendAck(MessageType, MessageBuffer[MessageLength-1] & 0x0f);
429 if ((MessageLength > 1) && (MessageBuffer[MessageLength-2] != 0x01))
432 fprintf(stdout,_("Multiframe message in multiframe message !\n"));
433 fprintf(stdout,_("Please report it !\n"));
435 RX_State = FBUS_RX_Sync;
441 /* We do not want to send ACK of ACKs and ACK of RLP frames. */
442 if (MessageType != FBUS_FRTYPE_ACK && MessageType != 0xf1) {
443 FBUS_SendAck(MessageType, MessageBuffer[MessageLength-1] & 0x0f);
445 if ((MessageLength > 1) && (MessageBuffer[MessageLength-2] != 0x01))
447 /* We copy previous part of multiframe message into special buffer */
449 for (i=0;i<MessageLength-2;i++) {
450 MultiMessageBuffer[i]=MessageBuffer[i];
452 MultiMessageLength=MessageLength-2;
453 MultiMessageType=MessageType;
457 if (!RX_Multiple && MessageDestination!=FBUS_DEVICE_PHONE ) {
458 /* Do not debug Ack and RLP frames to detail. */
459 if (MessageType != FBUS_FRTYPE_ACK && MessageType != 0xf1)
460 N61_RX_DisplayMessage();
462 GSM->DispatchMessage(MessageLength-2, MessageBuffer, MessageType);
466 /* When make debug and message is to phone display it */
467 if (MessageDestination==FBUS_DEVICE_PHONE) {
468 for (i=MessageLength;i>=0;i--)
469 MessageBuffer[i+6]=MessageBuffer[i];
470 MessageBuffer[0]=FBUS_FRAME_ID;
471 MessageBuffer[1]=FBUS_DEVICE_PHONE;
472 MessageBuffer[2]=FBUS_DEVICE_PC;
473 MessageBuffer[3]=MessageType;
475 MessageBuffer[5]=MessageLength;
476 MessageLength=MessageLength+8;
477 if (MessageLength % 2) MessageLength++;
478 NULL_TX_DisplayMessage(MessageLength, MessageBuffer);
484 fprintf(stdout, _("Bad checksum %02x (should be %02x), msg len=%i !\n"),checksum[0],checksum[1],MessageLength);
486 AppendLogText("CHECKSUM\n",false);
488 /* Just to be sure! */
491 RX_State = FBUS_RX_Sync;
498 if (isprint(rx_byte))
499 fprintf(stdout, "[%02x%c]", rx_byte, rx_byte);
501 fprintf(stdout, "[%02x ]", rx_byte);
507 /* Called by initialisation code to open comm port in asynchronous mode. */
508 bool FBUS_OpenSerial(void)
510 /* Uncomment, if want to test first method for DLR3 */
511 unsigned char req[3] = {"AT\r"};
512 unsigned char req2[5] = {"AT&F\r"};
513 unsigned char req3[13] = {"AT*NOKIAFBUS\r"};
515 switch (CurrentConnectionType) {
519 fprintf(stdout, _("Setting cable for FBUS communication...\n"));
522 device_changespeed(115200);
525 The data suite cable has some electronics built into the connector. This of
526 course needs a power supply of some sorts to operate properly.
528 In this case power is drawn off the handshaking lines of the PC. DTR has to
529 be set and RTS have to be cleared, thus if you use a terminal program (that
530 does not set the handshaking lines to these conditions) you will get weird
531 results. It will not set them like this since if Request To Send (RTS) is
532 not set the other party will not send any data (in hardware handshaking)
533 and if DTS is not set (handshaking = none) the cable will not receive
535 /* clearing the RTS bit and setting the DTR bit*/
536 device_setdtrrts(1, 0);
542 fprintf(stdout, _("Setting DLR3 cable for FBUS communication...\n"));
545 /* There are 2 ways to init DLR in FBUS: Here is first described by
546 Reuben Harris [reuben.harris@snowvalley.com] and used in Logo Manager,
547 1. Firstly set the connection baud to 19200, DTR off, RTS off,
548 Parity on, one stop bit,
549 2. Send "AT\r\n". The response should be "AT\r\n\r\nOK\r\n".
550 3. Send "AT&F\r\n". The response should be "AT&F\r\n\r\nOK\r\n".
551 4. Send "AT*NOKIAFBUS\r\n". The response should be
552 "AT*NOKIAFBUS\r\n\r\nOK\r\n".
553 5. Set speed to 115200
554 This seems to be compatible with more phones*/
556 device_changespeed(19200);
558 /*leave RTS low, DTR low for duration of session.*/
559 device_setdtrrts(0, 0);
561 Protocol->WritePhone (3,req );usleep(300);
562 Protocol->WritePhone (5,req2);usleep(300);
563 Protocol->WritePhone(13,req3);usleep(300);
565 device_changespeed(115200);
567 // /* Second method for DLR3:
568 // Used by some 7110 soft, but not compatible with some other
569 // phones supporting DLR3 - 7160, NCP2.0*/
570 // device_changespeed(115200);
571 // /*leave RTS low, DTR low for duration of session.*/
572 // device_setdtrrts(0, 0);
575 CurrentConnectionType=GCT_FBUS;
579 /* It's more complicated and not done here */
583 /* It's more complicated and not done here */
588 fprintf(stdout,_("Wrong connection type for fbus module. Inform marcin-wiacek@topnet.pl about it\n"));
596 /* Initialise variables and state machine. */
597 GSM_Error FBUS_Initialise(char *port_device, char *initlength,
598 GSM_ConnectionType connection,
599 void (*rlp_callback)(RLP_F96Frame *frame))
602 if (!StartConnection (port_device,false,connection))
603 return GE_INTERNALERROR;
605 CurrentConnectionType = connection;
607 if (FBUS_OpenSerial() != true) return GE_INTERNALERROR;