--- /dev/null
+/*
+
+ G N O K I I
+
+ A Linux/Unix toolset and driver for Nokia mobile phones.
+
+ Released under the terms of the GNU GPL, see file COPYING for more details.
+
+ This file provides an API for support for MBUS protocol
+
+*/
+
+/* "Turn on" prototypes in MBUS.h */
+#define __MBUS_c
+
+/* System header files */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#ifdef WIN32
+ #include <windows.h>
+ #include "misc_win32.h"
+#else
+ #include <ctype.h>
+#endif
+
+/* Various header file */
+#include "devices/device.h"
+#include "gsm-api.h"
+#include "protocol/mbus.h"
+#include "protocol/fbus.h"
+
+GSM_Protocol MBUS_Functions = {
+ MBUS_Initialise,
+ MBUS_SendMessage,
+ MBUS_SendFrame,
+ MBUS_WritePhone,
+ MBUS_Terminate,
+ MBUS_RX_StateMachine
+};
+
+/* Local variables */
+enum FBUS_RX_States RX_State;
+
+u8 MessageDestination, MessageSource;
+
+u16 BufferCount;
+
+u16 MessageLength;
+
+u8 MessageType;
+
+u8 MessageBuffer[MBUS_MAX_RECEIVE_LENGTH * 6];
+
+static u8 RequestSequenceNumber = 0x00;
+
+#ifdef DEBUG
+char *MBUS_PrintDevice(int Device)
+{
+ switch (Device) {
+
+ case FBUS_DEVICE_PHONE:
+ return _("Phone");
+
+ case MBUS_DEVICE_PC1:
+ return _("PC");
+
+ case MBUS_DEVICE_PC2:
+ return _("PC");
+
+ default:
+ return _("Unknown");
+
+ }
+}
+
+/* N61_RX_DisplayMessage is called when a message we don't know about is
+ received so that the user can see what is going back and forth, and perhaps
+ shed some more light/explain another message type! */
+void MBUS_RX_DisplayMessage()
+{
+ fprintf(stdout, _("Msg Dest: %s\n"), MBUS_PrintDevice(MessageDestination));
+ fprintf(stdout, _("Msg Source: %s\n"), MBUS_PrintDevice(MessageSource));
+ fprintf(stdout, _("Msg Type: %02x\n"), MessageType);
+
+ hexdump(MessageLength,MessageBuffer);
+}
+
+#endif /* DEBUG */
+
+/* Prepares the message header and sends it, prepends the message start byte
+ (0x1e) and other values according the value specified when called.
+ Calculates checksum and then sends the lot down the pipe... */
+int MBUS_SendFrame(u16 message_length, u8 message_type, u8 *buffer) {
+ u8 out_buffer[MBUS_MAX_CONTENT_LENGTH + 2];
+
+ int count, current=0;
+ unsigned char checksum;
+
+ /* FIXME - we should check for the message length ... */
+
+ /* Now construct the message header. */
+
+ out_buffer[current++] = MBUS_FRAME_ID; /* Start of the frame indicator */
+
+ out_buffer[current++] = FBUS_DEVICE_PHONE; /* Destination */
+
+ out_buffer[current++] = MBUS_DEVICE_PC1; /* Source */
+
+ out_buffer[current++] = message_type; /* Type */
+
+ out_buffer[current++] = (message_length-1)/256; /* Length1 */
+ out_buffer[current++] = (message_length-1)%256; /* Length2 */
+
+ /* Copy in data if any. */
+
+ if (message_length != 0) {
+ memcpy(out_buffer + current, buffer, message_length);
+ current+=message_length;
+ }
+
+ /* Now calculate checksum over entire message and append to message. */
+
+ /* All bytes */
+ checksum = 0;
+ for (count = 0; count < current; count++)
+ checksum ^= out_buffer[count];
+
+ out_buffer[current++] = checksum;
+
+#ifdef DEBUG
+ NULL_TX_DisplayMessage(current, out_buffer);
+#endif /* DEBUG */
+
+ /* Send it out... */
+ if (!MBUS_WritePhone(current,out_buffer))
+ return (false);
+
+ return (true);
+}
+
+int MBUS_SendMessage(u16 message_length, u8 message_type, u8 *buffer) {
+
+ u8 frame_buffer[MBUS_MAX_CONTENT_LENGTH + 2];
+
+ RequestSequenceNumber++;
+
+ memcpy(frame_buffer, buffer, message_length);
+ frame_buffer[message_length] = RequestSequenceNumber;
+ MBUS_SendFrame(message_length + 1, message_type, frame_buffer);
+
+ return (true);
+}
+
+int MBUS_SendAck(u8 message_type, u8 message_seq) {
+
+ unsigned char request[6];
+
+ int count;
+
+ request[0]=MBUS_FRAME_ID;
+ request[1]=FBUS_DEVICE_PHONE;
+ request[2]=MBUS_DEVICE_PC1;
+ request[3]=FBUS_FRTYPE_ACK;
+ request[4] = message_seq;
+ request[5]=0;
+
+ /* Checksum */
+ for (count = 0; count < 5; count++)
+ request[5] ^= request[count];
+
+#ifdef DEBUG
+ fprintf(stdout, _("[Sending Ack of type %02x, seq: %x]\n"), message_type, message_seq);
+
+ NULL_TX_DisplayMessage(5, request);
+#endif /* DEBUG */
+
+ if (!MBUS_WritePhone(6, request)) {
+#ifdef DEBUG
+ fprintf(stdout,_("Sending ACK failed %i !\n"),count);
+#endif
+ return (false);
+ }
+
+ return(true);
+}
+
+/* Applications should call MBUS_Terminate to shut down the MBUS thread and
+ close the serial port. */
+void MBUS_Terminate(void)
+{
+ /* Request termination of thread */
+ CurrentRequestTerminate = true;
+
+ /* RTS low */
+ device_setdtrrts(0, 0);
+
+ /* Close serial port. */
+ device_close();
+}
+
+/* RX_State machine for receive handling. Called once for each character
+ received from the phone/phone. */
+void MBUS_RX_StateMachine(unsigned char rx_byte) {
+
+ static struct timeval time_now, time_last, time_diff;
+
+ unsigned char max;
+
+ static int checksum[2];
+
+#if defined(__svr4__) || defined(__FreeBSD__) || defined(DEBUG)
+ int i=0;
+#endif
+
+#ifdef DEBUG
+ if (strcmp(GSM_Info->MBUSModels, "sniff"))
+ {
+#endif
+
+ checksum[0]=checksum[1];
+ checksum[1] ^= rx_byte;
+
+ switch (RX_State) {
+
+ /* Messages from the phone start with an 0x1f (MBUS).
+ We use this to "synchronise" with the incoming data stream. However,
+ if we see something else, we assume we have lost sync and we require
+ a gap of at least 5ms before we start looking again. This is because
+ the data part of the frame could contain a byte which looks like the
+ sync byte */
+ case FBUS_RX_Discarding:
+#ifndef VC6
+ gettimeofday(&time_now, NULL);
+ timersub(&time_now, &time_last, &time_diff);
+ if (time_diff.tv_sec == 0 && time_diff.tv_usec < 5000) {
+ time_last = time_now; /* no gap seen, continue discarding */
+ break;
+ }
+ /* else fall through to... */
+#endif
+
+ case FBUS_RX_Sync:
+
+ if (rx_byte == MBUS_FRAME_ID) {
+
+ BufferCount = 0;
+
+ RX_State = FBUS_RX_GetDestination;
+
+ /* Initialize checksum. */
+ checksum[1] = MBUS_FRAME_ID;
+ } else {
+ /* Lost frame sync */
+ RX_State = FBUS_RX_Discarding;
+#ifndef VC6
+ gettimeofday(&time_last, NULL);
+#endif
+ }
+
+ break;
+
+ case FBUS_RX_GetDestination:
+
+ MessageDestination=rx_byte;
+ RX_State = FBUS_RX_GetSource;
+
+ /* When there is a checksum error and things get out of sync we have to manage to resync */
+ /* If doing a data call at the time, finding a 0x1e etc is really quite likely in the data stream */
+ /* Then all sorts of horrible things happen because the packet length etc is wrong... */
+ /* Therefore we test here for a destination of 0x0c and return to the top if it is not */
+ /* The same testing for MBUS. Only one change: MBUS returns, what we send.
+ So, the byte can be 0x10 (destination MBUS) or 0x00 (phone) */
+ if (rx_byte!=MBUS_DEVICE_PC1 && rx_byte!=MBUS_DEVICE_PC2 && rx_byte!=FBUS_DEVICE_PHONE) {
+ RX_State=FBUS_RX_Sync;
+#ifdef DEBUG
+ fprintf(stdout,"The mbus stream is out of sync - expected 0x10 or 0x00, got %2x\n",rx_byte);
+#endif
+ }
+
+ break;
+
+ case FBUS_RX_GetSource:
+
+ MessageSource=rx_byte;
+ RX_State = FBUS_RX_GetType;
+
+ /* Source should be 0x00 or 0x10 */
+ if (rx_byte!=FBUS_DEVICE_PHONE && rx_byte!=MBUS_DEVICE_PC1 && rx_byte!=MBUS_DEVICE_PC2) {
+ RX_State=FBUS_RX_Sync;
+#ifdef DEBUG
+ fprintf(stdout,"The mbus stream is out of sync - expected 0x00 or 0x10, got %2x\n",rx_byte);
+#endif
+ }
+
+ break;
+
+ case FBUS_RX_GetType:
+
+ MessageType=rx_byte;
+
+ RX_State = FBUS_RX_GetLength1;
+
+ break;
+
+ case FBUS_RX_GetLength1:
+
+ MessageLength=0;
+
+ /* MW:Here are problems with conversion. For chars 0-127 it's OK, for
+ higher not (probably because rx_byte is char type) - improtant
+ for MBUS. So, I make it double and strange - generally it should be
+ more simple and make simple convert rx_byte into MessageLength */
+ if (rx_byte!=0) {
+ max=rx_byte;
+ MessageLength=max*256;
+ }
+
+ RX_State = FBUS_RX_GetLength2;
+
+ break;
+
+ case FBUS_RX_GetLength2:
+
+ /* MW:Here are problems with conversion. For chars 0-127 it's OK, for
+ higher not (probably because rx_byte is char type) - improtant
+ for MBUS. So, I make it double and strange - generally it should be
+ more simple and make simple convert rx_byte into MessageLength */
+#if defined(__svr4__) || defined(__FreeBSD__)
+ if (rx_byte!=0) {
+ for (i=0;i<rx_byte;i++)
+ MessageLength=MessageLength++;
+ }
+#else
+ if (rx_byte!=0) {
+ max=rx_byte;
+ MessageLength=MessageLength+max;
+ }
+#endif
+
+ RX_State = FBUS_RX_GetMessage;
+
+ /* In MBUS ACK ends here */
+ if (MessageType==FBUS_FRTYPE_ACK)
+ {
+#ifdef DEBUG
+ fprintf(stdout, _("[Received Ack from phone]\n"));
+#endif /* DEBUG */
+ RX_State = FBUS_RX_Sync;
+ }
+
+ break;
+
+ case FBUS_RX_GetMessage:
+
+ MessageBuffer[BufferCount] = rx_byte;
+ BufferCount ++;
+
+ /* If this is the last byte, it's the checksum. */
+ if (BufferCount == MessageLength+2) {
+
+ /* Is the checksum correct? */
+ if (checksum[0] == rx_byte) {
+
+ /* We do not want to send ACK of ACKs and ACK of RLP frames. */
+ if (MessageType != FBUS_FRTYPE_ACK && MessageType != 0xf1
+ && (MessageDestination==MBUS_DEVICE_PC1 || MessageDestination==MBUS_DEVICE_PC2)) {
+ MBUS_SendAck(MessageType, MessageBuffer[BufferCount-2]);
+ }
+
+ /* We don't write info about messages sent to phone */
+ if (MessageDestination!=FBUS_DEVICE_PHONE) {
+#ifdef DEBUG
+ /* Do not debug Ack and RLP frames to detail. */
+ if (MessageType != FBUS_FRTYPE_ACK && MessageType != 0xf1)
+ MBUS_RX_DisplayMessage();
+#endif /* DEBUG */
+
+ GSM->DispatchMessage(MessageLength, MessageBuffer, MessageType);
+
+ } else {
+#ifdef DEBUG
+ if (strstr(GSM_Info->MBUSModels, "6110sniff") != NULL) {
+ fprintf(stdout, _("PC: "));
+
+ fprintf(stdout, "%02x:", MBUS_FRAME_ID);
+ fprintf(stdout, "%02x:", MBUS_DEVICE_PC1);
+ fprintf(stdout, "%02x:", FBUS_DEVICE_PHONE);
+ fprintf(stdout, "%02x:", MessageType);
+ fprintf(stdout, "%02x:", MessageLength/256);
+ fprintf(stdout, "%02x:", MessageLength%256);
+
+// NULL_TX_DisplayMessage(current, out_buffer);
+
+ for (i = 0; i < BufferCount; i++)
+ fprintf(stdout, "%02x:", MessageBuffer[i]);
+
+ fprintf(stdout, "\n");
+ }
+#endif /* DEBUG */
+ }
+ } else {
+#ifdef DEBUG
+ fprintf(stdout, _("Bad checksum %02x (should be %02x), msg len=%i !\n"),rx_byte,checksum[0],MessageLength);
+#endif /* DEBUG */
+ }
+ RX_State = FBUS_RX_Sync;
+ }
+ break;
+ }
+
+#ifdef DEBUG
+
+ } else {
+ if (isprint(rx_byte))
+ fprintf(stdout, "[%02x%c]", rx_byte, rx_byte);
+ else
+ fprintf(stdout, "[%02x ]", rx_byte);
+
+ }
+
+#endif
+}
+
+/* Called by initialisation code to open comm port in asynchronous mode. */
+bool MBUS_OpenSerial(void)
+{
+#ifdef DEBUG
+ fprintf(stdout, _("Setting MBUS communication...\n"));
+#endif /* DEBUG */
+
+ device_changespeed(9600);
+
+ usleep(100);
+
+ if (strstr(GSM_Info->MBUSModels, "sniff") == NULL) {
+
+ /* leave RTS high, DTR low for duration of session. */
+ device_setdtrrts(0, 1);
+
+ usleep(100);
+ }
+
+ return (true);
+
+}
+
+/* Initialise variables and state machine. */
+GSM_Error MBUS_Initialise(char *port_device, char *initlength,
+ GSM_ConnectionType connection,
+ void (*rlp_callback)(RLP_F96Frame *frame))
+{
+ if (!StartConnection (port_device,true,connection))
+ return GE_INTERNALERROR;
+
+ CurrentConnectionType = connection;
+
+ if (MBUS_OpenSerial() != true) {
+ /* Fail so sit here till calling code works out there is a problem. */
+// while (!CurrentRequestTerminate)
+// usleep (100000);
+
+ return GE_INTERNALERROR;
+ }
+
+ return (GE_NONE);
+}
+
+bool MBUS_WritePhone (u16 length, u8 *buffer) {
+
+ if (!CurrentDisableKeepAlive)
+ usleep(150);
+
+ if (device_write(buffer,length)!=length)
+ return false;
+ else
+ return true;
+}