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
13 /* "Turn on" prototypes in MBUS.h */
16 /* System header files */
24 #include "misc_win32.h"
29 /* Various header file */
30 #include "devices/device.h"
32 #include "protocol/mbus.h"
33 #include "protocol/fbus.h"
35 GSM_Protocol MBUS_Functions = {
45 enum FBUS_RX_States RX_State;
47 u8 MessageDestination, MessageSource;
55 u8 MessageBuffer[MBUS_MAX_RECEIVE_LENGTH * 6];
57 static u8 RequestSequenceNumber = 0x00;
60 char *MBUS_PrintDevice(int Device)
64 case FBUS_DEVICE_PHONE:
79 /* N61_RX_DisplayMessage is called when a message we don't know about is
80 received so that the user can see what is going back and forth, and perhaps
81 shed some more light/explain another message type! */
82 void MBUS_RX_DisplayMessage()
84 fprintf(stdout, _("Msg Dest: %s\n"), MBUS_PrintDevice(MessageDestination));
85 fprintf(stdout, _("Msg Source: %s\n"), MBUS_PrintDevice(MessageSource));
86 fprintf(stdout, _("Msg Type: %02x\n"), MessageType);
88 hexdump(MessageLength,MessageBuffer);
93 /* Prepares the message header and sends it, prepends the message start byte
94 (0x1e) and other values according the value specified when called.
95 Calculates checksum and then sends the lot down the pipe... */
96 int MBUS_SendFrame(u16 message_length, u8 message_type, u8 *buffer) {
97 u8 out_buffer[MBUS_MAX_CONTENT_LENGTH + 2];
100 unsigned char checksum;
102 /* FIXME - we should check for the message length ... */
104 /* Now construct the message header. */
106 out_buffer[current++] = MBUS_FRAME_ID; /* Start of the frame indicator */
108 out_buffer[current++] = FBUS_DEVICE_PHONE; /* Destination */
110 out_buffer[current++] = MBUS_DEVICE_PC1; /* Source */
112 out_buffer[current++] = message_type; /* Type */
114 out_buffer[current++] = (message_length-1)/256; /* Length1 */
115 out_buffer[current++] = (message_length-1)%256; /* Length2 */
117 /* Copy in data if any. */
119 if (message_length != 0) {
120 memcpy(out_buffer + current, buffer, message_length);
121 current+=message_length;
124 /* Now calculate checksum over entire message and append to message. */
128 for (count = 0; count < current; count++)
129 checksum ^= out_buffer[count];
131 out_buffer[current++] = checksum;
134 NULL_TX_DisplayMessage(current, out_buffer);
138 if (!MBUS_WritePhone(current,out_buffer))
144 int MBUS_SendMessage(u16 message_length, u8 message_type, u8 *buffer) {
146 u8 frame_buffer[MBUS_MAX_CONTENT_LENGTH + 2];
148 RequestSequenceNumber++;
150 memcpy(frame_buffer, buffer, message_length);
151 frame_buffer[message_length] = RequestSequenceNumber;
152 MBUS_SendFrame(message_length + 1, message_type, frame_buffer);
157 int MBUS_SendAck(u8 message_type, u8 message_seq) {
159 unsigned char request[6];
163 request[0]=MBUS_FRAME_ID;
164 request[1]=FBUS_DEVICE_PHONE;
165 request[2]=MBUS_DEVICE_PC1;
166 request[3]=FBUS_FRTYPE_ACK;
167 request[4] = message_seq;
171 for (count = 0; count < 5; count++)
172 request[5] ^= request[count];
175 fprintf(stdout, _("[Sending Ack of type %02x, seq: %x]\n"), message_type, message_seq);
177 NULL_TX_DisplayMessage(5, request);
180 if (!MBUS_WritePhone(6, request)) {
182 fprintf(stdout,_("Sending ACK failed %i !\n"),count);
190 /* Applications should call MBUS_Terminate to shut down the MBUS thread and
191 close the serial port. */
192 void MBUS_Terminate(void)
194 /* Request termination of thread */
195 CurrentRequestTerminate = true;
198 device_setdtrrts(0, 0);
200 /* Close serial port. */
204 /* RX_State machine for receive handling. Called once for each character
205 received from the phone/phone. */
206 void MBUS_RX_StateMachine(unsigned char rx_byte) {
208 static struct timeval time_now, time_last, time_diff;
212 static int checksum[2];
214 #if defined(__svr4__) || defined(__FreeBSD__) || defined(DEBUG)
219 if (strcmp(GSM_Info->MBUSModels, "mbussniff"))
223 checksum[0]=checksum[1];
224 checksum[1] ^= rx_byte;
228 /* Messages from the phone start with an 0x1f (MBUS).
229 We use this to "synchronise" with the incoming data stream. However,
230 if we see something else, we assume we have lost sync and we require
231 a gap of at least 5ms before we start looking again. This is because
232 the data part of the frame could contain a byte which looks like the
234 case FBUS_RX_Discarding:
236 gettimeofday(&time_now, NULL);
237 timersub(&time_now, &time_last, &time_diff);
238 if (time_diff.tv_sec == 0 && time_diff.tv_usec < 5000) {
239 time_last = time_now; /* no gap seen, continue discarding */
242 /* else fall through to... */
247 if (rx_byte == MBUS_FRAME_ID) {
251 RX_State = FBUS_RX_GetDestination;
253 /* Initialize checksum. */
254 checksum[1] = MBUS_FRAME_ID;
256 /* Lost frame sync */
257 RX_State = FBUS_RX_Discarding;
259 gettimeofday(&time_last, NULL);
265 case FBUS_RX_GetDestination:
267 MessageDestination=rx_byte;
268 RX_State = FBUS_RX_GetSource;
270 /* When there is a checksum error and things get out of sync we have to manage to resync */
271 /* If doing a data call at the time, finding a 0x1e etc is really quite likely in the data stream */
272 /* Then all sorts of horrible things happen because the packet length etc is wrong... */
273 /* Therefore we test here for a destination of 0x0c and return to the top if it is not */
274 /* The same testing for MBUS. Only one change: MBUS returns, what we send.
275 So, the byte can be 0x10 (destination MBUS) or 0x00 (phone) */
276 if (rx_byte!=MBUS_DEVICE_PC1 && rx_byte!=MBUS_DEVICE_PC2 && rx_byte!=FBUS_DEVICE_PHONE) {
277 RX_State=FBUS_RX_Sync;
279 fprintf(stdout,"The mbus stream is out of sync - expected 0x10 or 0x00, got %2x\n",rx_byte);
285 case FBUS_RX_GetSource:
287 MessageSource=rx_byte;
288 RX_State = FBUS_RX_GetType;
290 /* Source should be 0x00 or 0x10 */
291 if (rx_byte!=FBUS_DEVICE_PHONE && rx_byte!=MBUS_DEVICE_PC1 && rx_byte!=MBUS_DEVICE_PC2) {
292 RX_State=FBUS_RX_Sync;
294 fprintf(stdout,"The mbus stream is out of sync - expected 0x00 or 0x10, got %2x\n",rx_byte);
300 case FBUS_RX_GetType:
304 RX_State = FBUS_RX_GetLength1;
308 case FBUS_RX_GetLength1:
312 /* MW:Here are problems with conversion. For chars 0-127 it's OK, for
313 higher not (probably because rx_byte is char type) - improtant
314 for MBUS. So, I make it double and strange - generally it should be
315 more simple and make simple convert rx_byte into MessageLength */
318 MessageLength=max*256;
321 RX_State = FBUS_RX_GetLength2;
325 case FBUS_RX_GetLength2:
327 /* MW:Here are problems with conversion. For chars 0-127 it's OK, for
328 higher not (probably because rx_byte is char type) - improtant
329 for MBUS. So, I make it double and strange - generally it should be
330 more simple and make simple convert rx_byte into MessageLength */
331 #if defined(__svr4__) || defined(__FreeBSD__)
333 for (i=0;i<rx_byte;i++)
334 MessageLength=MessageLength++;
339 MessageLength=MessageLength+max;
343 RX_State = FBUS_RX_GetMessage;
345 /* In MBUS ACK ends here */
346 if (MessageType==FBUS_FRTYPE_ACK)
349 fprintf(stdout, _("[Received Ack from phone]\n"));
351 RX_State = FBUS_RX_Sync;
356 case FBUS_RX_GetMessage:
358 MessageBuffer[BufferCount] = rx_byte;
361 /* If this is the last byte, it's the checksum. */
362 if (BufferCount == MessageLength+2) {
364 /* Is the checksum correct? */
365 if (checksum[0] == rx_byte) {
367 /* We do not want to send ACK of ACKs and ACK of RLP frames. */
368 if (MessageType != FBUS_FRTYPE_ACK && MessageType != 0xf1
369 && (MessageDestination==MBUS_DEVICE_PC1 || MessageDestination==MBUS_DEVICE_PC2)) {
370 MBUS_SendAck(MessageType, MessageBuffer[BufferCount-2]);
373 /* We don't write info about messages sent to phone */
374 if (MessageDestination!=FBUS_DEVICE_PHONE) {
376 /* Do not debug Ack and RLP frames to detail. */
377 if (MessageType != FBUS_FRTYPE_ACK && MessageType != 0xf1)
378 MBUS_RX_DisplayMessage();
381 GSM->DispatchMessage(MessageLength, MessageBuffer, MessageType);
385 if (strstr(GSM_Info->MBUSModels, "sniff") != NULL) {
386 fprintf(stdout, _("PC: "));
388 fprintf(stdout, "%02x:", MBUS_FRAME_ID);
389 fprintf(stdout, "%02x:", MBUS_DEVICE_PC1);
390 fprintf(stdout, "%02x:", FBUS_DEVICE_PHONE);
391 fprintf(stdout, "%02x:", MessageType);
392 fprintf(stdout, "%02x:", MessageLength/256);
393 fprintf(stdout, "%02x:", MessageLength%256);
395 // NULL_TX_DisplayMessage(current, out_buffer);
397 for (i = 0; i < BufferCount; i++)
398 fprintf(stdout, "%02x:", MessageBuffer[i]);
400 fprintf(stdout, "\n");
406 fprintf(stdout, _("Bad checksum %02x (should be %02x), msg len=%i !\n"),rx_byte,checksum[0],MessageLength);
409 RX_State = FBUS_RX_Sync;
417 if (isprint(rx_byte))
418 fprintf(stdout, "[%02x%c]", rx_byte, rx_byte);
420 fprintf(stdout, "[%02x ]", rx_byte);
427 /* Called by initialisation code to open comm port in asynchronous mode. */
428 bool MBUS_OpenSerial(void)
431 fprintf(stdout, _("Setting MBUS communication...\n"));
434 device_changespeed(9600);
438 if (strstr(GSM_Info->MBUSModels, "sniff") == NULL) {
440 /* leave RTS high, DTR low for duration of session. */
441 device_setdtrrts(0, 1);
450 /* Initialise variables and state machine. */
451 GSM_Error MBUS_Initialise(char *port_device, char *initlength,
452 GSM_ConnectionType connection,
453 void (*rlp_callback)(RLP_F96Frame *frame))
455 if (!StartConnection (port_device,true,connection))
456 return GE_INTERNALERROR;
458 CurrentConnectionType = connection;
460 if (MBUS_OpenSerial() != true) {
461 /* Fail so sit here till calling code works out there is a problem. */
462 // while (!CurrentRequestTerminate)
465 return GE_INTERNALERROR;
471 bool MBUS_WritePhone (u16 length, u8 *buffer) {
473 if (!CurrentDisableKeepAlive)
476 if (device_write(buffer,length)!=length)