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 MBUS protocol
15 /* "Turn on" prototypes in MBUS.h */
18 /* System header files */
26 #include "misc_win32.h"
31 /* Various header file */
32 #include "devices/device.h"
34 #include "protocol/mbus.h"
35 #include "protocol/fbus.h"
37 GSM_Protocol MBUS_Functions = {
47 enum FBUS_RX_States RX_State;
49 u8 MessageDestination, MessageSource;
57 u8 MessageBuffer[MBUS_MAX_RECEIVE_LENGTH * 6];
59 static u8 RequestSequenceNumber = 0x00;
62 char *MBUS_PrintDevice(int Device)
66 case FBUS_DEVICE_PHONE:
81 /* N61_RX_DisplayMessage is called when a message we don't know about is
82 received so that the user can see what is going back and forth, and perhaps
83 shed some more light/explain another message type! */
84 void MBUS_RX_DisplayMessage()
86 fprintf(stdout, _("Msg Dest: %s\n"), MBUS_PrintDevice(MessageDestination));
87 fprintf(stdout, _("Msg Source: %s\n"), MBUS_PrintDevice(MessageSource));
88 fprintf(stdout, _("Msg Type: %02x\n"), MessageType);
90 hexdump(MessageLength,MessageBuffer);
95 /* Prepares the message header and sends it, prepends the message start byte
96 (0x1e) and other values according the value specified when called.
97 Calculates checksum and then sends the lot down the pipe... */
98 int MBUS_SendFrame(u16 message_length, u8 message_type, u8 *buffer) {
99 u8 out_buffer[MBUS_MAX_CONTENT_LENGTH + 2];
101 int count, current=0;
102 unsigned char checksum;
104 /* FIXME - we should check for the message length ... */
106 /* Now construct the message header. */
108 out_buffer[current++] = MBUS_FRAME_ID; /* Start of the frame indicator */
110 out_buffer[current++] = FBUS_DEVICE_PHONE; /* Destination */
112 out_buffer[current++] = MBUS_DEVICE_PC1; /* Source */
114 out_buffer[current++] = message_type; /* Type */
116 out_buffer[current++] = (message_length-1)/256; /* Length1 */
117 out_buffer[current++] = (message_length-1)%256; /* Length2 */
119 /* Copy in data if any. */
121 if (message_length != 0) {
122 memcpy(out_buffer + current, buffer, message_length);
123 current+=message_length;
126 /* Now calculate checksum over entire message and append to message. */
130 for (count = 0; count < current; count++)
131 checksum ^= out_buffer[count];
133 out_buffer[current++] = checksum;
136 NULL_TX_DisplayMessage(current, out_buffer);
140 if (!MBUS_WritePhone(current,out_buffer))
146 int MBUS_SendMessage(u16 message_length, u8 message_type, u8 *buffer) {
148 u8 frame_buffer[MBUS_MAX_CONTENT_LENGTH + 2];
150 RequestSequenceNumber++;
152 memcpy(frame_buffer, buffer, message_length);
153 frame_buffer[message_length] = RequestSequenceNumber;
154 MBUS_SendFrame(message_length + 1, message_type, frame_buffer);
159 int MBUS_SendAck(u8 message_type, u8 message_seq) {
161 unsigned char request[6];
165 request[0]=MBUS_FRAME_ID;
166 request[1]=FBUS_DEVICE_PHONE;
167 request[2]=MBUS_DEVICE_PC1;
168 request[3]=FBUS_FRTYPE_ACK;
169 request[4] = message_seq;
173 for (count = 0; count < 5; count++)
174 request[5] ^= request[count];
177 fprintf(stdout, _("[Sending Ack of type %02x, seq: %x]\n"), message_type, message_seq);
179 NULL_TX_DisplayMessage(5, request);
182 if (!MBUS_WritePhone(6, request)) {
184 fprintf(stdout,_("Sending ACK failed %i !\n"),count);
192 /* Applications should call MBUS_Terminate to shut down the MBUS thread and
193 close the serial port. */
194 void MBUS_Terminate(void)
196 /* Request termination of thread */
197 CurrentRequestTerminate = true;
200 device_setdtrrts(0, 0);
202 /* Close serial port. */
206 /* RX_State machine for receive handling. Called once for each character
207 received from the phone/phone. */
208 void MBUS_RX_StateMachine(unsigned char rx_byte) {
210 static struct timeval time_now, time_last, time_diff;
214 static int checksum[2];
216 #if defined(__svr4__) || defined(__FreeBSD__) || defined(DEBUG)
221 if (strcmp(GSM_Info->MBUSModels, "sniff"))
225 checksum[0]=checksum[1];
226 checksum[1] ^= rx_byte;
230 /* Messages from the phone start with an 0x1f (MBUS).
231 We use this to "synchronise" with the incoming data stream. However,
232 if we see something else, we assume we have lost sync and we require
233 a gap of at least 5ms before we start looking again. This is because
234 the data part of the frame could contain a byte which looks like the
236 case FBUS_RX_Discarding:
238 gettimeofday(&time_now, NULL);
239 timersub(&time_now, &time_last, &time_diff);
240 if (time_diff.tv_sec == 0 && time_diff.tv_usec < 5000) {
241 time_last = time_now; /* no gap seen, continue discarding */
244 /* else fall through to... */
249 if (rx_byte == MBUS_FRAME_ID) {
253 RX_State = FBUS_RX_GetDestination;
255 /* Initialize checksum. */
256 checksum[1] = MBUS_FRAME_ID;
258 /* Lost frame sync */
259 RX_State = FBUS_RX_Discarding;
261 gettimeofday(&time_last, NULL);
267 case FBUS_RX_GetDestination:
269 MessageDestination=rx_byte;
270 RX_State = FBUS_RX_GetSource;
272 /* When there is a checksum error and things get out of sync we have to manage to resync */
273 /* If doing a data call at the time, finding a 0x1e etc is really quite likely in the data stream */
274 /* Then all sorts of horrible things happen because the packet length etc is wrong... */
275 /* Therefore we test here for a destination of 0x0c and return to the top if it is not */
276 /* The same testing for MBUS. Only one change: MBUS returns, what we send.
277 So, the byte can be 0x10 (destination MBUS) or 0x00 (phone) */
278 if (rx_byte!=MBUS_DEVICE_PC1 && rx_byte!=MBUS_DEVICE_PC2 && rx_byte!=FBUS_DEVICE_PHONE) {
279 RX_State=FBUS_RX_Sync;
281 fprintf(stdout,"The mbus stream is out of sync - expected 0x10 or 0x00, got %2x\n",rx_byte);
287 case FBUS_RX_GetSource:
289 MessageSource=rx_byte;
290 RX_State = FBUS_RX_GetType;
292 /* Source should be 0x00 or 0x10 */
293 if (rx_byte!=FBUS_DEVICE_PHONE && rx_byte!=MBUS_DEVICE_PC1 && rx_byte!=MBUS_DEVICE_PC2) {
294 RX_State=FBUS_RX_Sync;
296 fprintf(stdout,"The mbus stream is out of sync - expected 0x00 or 0x10, got %2x\n",rx_byte);
302 case FBUS_RX_GetType:
306 RX_State = FBUS_RX_GetLength1;
310 case FBUS_RX_GetLength1:
314 /* MW:Here are problems with conversion. For chars 0-127 it's OK, for
315 higher not (probably because rx_byte is char type) - improtant
316 for MBUS. So, I make it double and strange - generally it should be
317 more simple and make simple convert rx_byte into MessageLength */
320 MessageLength=max*256;
323 RX_State = FBUS_RX_GetLength2;
327 case FBUS_RX_GetLength2:
329 /* MW:Here are problems with conversion. For chars 0-127 it's OK, for
330 higher not (probably because rx_byte is char type) - improtant
331 for MBUS. So, I make it double and strange - generally it should be
332 more simple and make simple convert rx_byte into MessageLength */
333 #if defined(__svr4__) || defined(__FreeBSD__)
335 for (i=0;i<rx_byte;i++)
336 MessageLength=MessageLength++;
341 MessageLength=MessageLength+max;
345 RX_State = FBUS_RX_GetMessage;
347 /* In MBUS ACK ends here */
348 if (MessageType==FBUS_FRTYPE_ACK)
351 fprintf(stdout, _("[Received Ack from phone]\n"));
353 RX_State = FBUS_RX_Sync;
358 case FBUS_RX_GetMessage:
360 MessageBuffer[BufferCount] = rx_byte;
363 /* If this is the last byte, it's the checksum. */
364 if (BufferCount == MessageLength+2) {
366 /* Is the checksum correct? */
367 if (checksum[0] == rx_byte) {
369 /* We do not want to send ACK of ACKs and ACK of RLP frames. */
370 if (MessageType != FBUS_FRTYPE_ACK && MessageType != 0xf1
371 && (MessageDestination==MBUS_DEVICE_PC1 || MessageDestination==MBUS_DEVICE_PC2)) {
372 MBUS_SendAck(MessageType, MessageBuffer[BufferCount-2]);
375 /* We don't write info about messages sent to phone */
376 if (MessageDestination!=FBUS_DEVICE_PHONE) {
378 /* Do not debug Ack and RLP frames to detail. */
379 if (MessageType != FBUS_FRTYPE_ACK && MessageType != 0xf1)
380 MBUS_RX_DisplayMessage();
383 GSM->DispatchMessage(MessageLength, MessageBuffer, MessageType);
387 if (strstr(GSM_Info->MBUSModels, "6110sniff") != NULL) {
388 fprintf(stdout, _("PC: "));
390 fprintf(stdout, "%02x:", MBUS_FRAME_ID);
391 fprintf(stdout, "%02x:", MBUS_DEVICE_PC1);
392 fprintf(stdout, "%02x:", FBUS_DEVICE_PHONE);
393 fprintf(stdout, "%02x:", MessageType);
394 fprintf(stdout, "%02x:", MessageLength/256);
395 fprintf(stdout, "%02x:", MessageLength%256);
397 // NULL_TX_DisplayMessage(current, out_buffer);
399 for (i = 0; i < BufferCount; i++)
400 fprintf(stdout, "%02x:", MessageBuffer[i]);
402 fprintf(stdout, "\n");
408 fprintf(stdout, _("Bad checksum %02x (should be %02x), msg len=%i !\n"),rx_byte,checksum[0],MessageLength);
411 RX_State = FBUS_RX_Sync;
419 if (isprint(rx_byte))
420 fprintf(stdout, "[%02x%c]", rx_byte, rx_byte);
422 fprintf(stdout, "[%02x ]", rx_byte);
429 /* Called by initialisation code to open comm port in asynchronous mode. */
430 bool MBUS_OpenSerial(void)
433 fprintf(stdout, _("Setting MBUS communication...\n"));
436 device_changespeed(9600);
440 if (strstr(GSM_Info->MBUSModels, "sniff") == NULL) {
442 /* leave RTS high, DTR low for duration of session. */
443 device_setdtrrts(0, 1);
452 /* Initialise variables and state machine. */
453 GSM_Error MBUS_Initialise(char *port_device, char *initlength,
454 GSM_ConnectionType connection,
455 void (*rlp_callback)(RLP_F96Frame *frame))
457 if (!StartConnection (port_device,true,connection))
458 return GE_INTERNALERROR;
460 CurrentConnectionType = connection;
462 if (MBUS_OpenSerial() != true) {
463 /* Fail so sit here till calling code works out there is a problem. */
464 // while (!CurrentRequestTerminate)
467 return GE_INTERNALERROR;
473 bool MBUS_WritePhone (u16 length, u8 *buffer) {
475 if (!CurrentDisableKeepAlive)
478 if (device_write(buffer,length)!=length)