--- /dev/null
+/*
+
+ $Id$
+
+ G N O K I I
+
+ A Linux/Unix toolset and driver for Nokia mobile phones.
+
+ Copyright (C) 2000 Hugh Blemings & Pavel Janík ml.
+
+ Released under the terms of the GNU GPL, see file COPYING for more details.
+
+ This file provides an API for accessing functions via fbus.
+ See README for more details on supported mobile phones.
+
+ The various routines are called FBUS_(whatever).
+
+ $Log$
+ Revision 1.1.1.1 2001/11/25 21:59:10 short
+ :pserver:cvs@pserver.samba.org:/cvsroot - gnokii - Sun Nov 25 22:56 CET 2001
+
+ Revision 1.2 2001/11/09 14:25:04 pkot
+ DEBUG cleanups
+
+ Revision 1.1 2001/11/09 12:55:07 pkot
+ Forgot about fbus support for 3110. FIXME: is it really needed?
+
+
+*/
+
+/* System header files */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+/* Various header file */
+
+#include "config.h"
+#include "misc.h"
+#include "gsm-common.h"
+#include "gsm-ringtones.h"
+#include "gsm-networks.h"
+#include "gsm-statemachine.h"
+#include "links/utils.h"
+
+#ifndef WIN32
+ #include "device.h"
+#else
+ #include "win32/winserial.h"
+ #define device_write(a, b) WriteCommBlock(a, b)
+ #define device_read(a, b) ReadCommBlock(a, b)
+ #define sleep(x) Sleep((x) * 1000)
+ #define usleep(x) Sleep(((x) < 1000) ? 1 : ((x) / 1000))
+#endif
+
+#define __links_fbus_3110_c
+#include "links/fbus-3110.h"
+
+/* FIXME - pass device_* the link stuff?? */
+/* FIXME - win32 stuff! */
+
+
+/* Some globals */
+
+static GSM_Link *glink;
+static GSM_Statemachine *statemachine;
+static FB3110_Link flink; /* FBUS specific stuff, internal to this file */
+
+
+/*--------------------------------------------*/
+
+bool FB3110_OpenSerial(void)
+{
+ /* Open device. */
+#ifdef WIN32
+ if (OpenConnection(glink->PortDevice, FB3110_RX_StateMachine, NULL)) {
+#else
+ if (!device_open(glink->PortDevice, false, false, false, GCT_Serial)) {
+#endif
+ perror(_("Couldn't open FBUS device"));
+ return false;
+ }
+ device_changespeed(115200);
+
+ return (true);
+}
+
+
+/* RX_State machine for receive handling. Called once for each character
+ received from the phone. */
+
+void FB3110_RX_StateMachine(unsigned char rx_byte)
+{
+ FB3110_IncomingFrame *i = &flink.i;
+ int count;
+
+ switch (i->State) {
+
+ /* Phone is currently off. Wait for 0x55 before
+ restarting */
+ case FB3110_RX_Discarding:
+ if (rx_byte != 0x55)
+ break;
+
+ /* Seen 0x55, restart at 0x04 */
+ i->State = FB3110_RX_Sync;
+
+ dprintf("restarting.\n");
+
+ /* FALLTHROUGH */
+
+ /* Messages from the phone start with an 0x04 during
+ "normal" operation, 0x03 when in data/fax mode. We
+ use this to "synchronise" with the incoming data
+ stream. */
+ case FB3110_RX_Sync:
+ if (rx_byte == 0x04 || rx_byte == 0x03) {
+ i->FrameType = rx_byte;
+ i->Checksum = rx_byte;
+ i->State = FB3110_RX_GetLength;
+ }
+ break;
+
+ /* Next byte is the length of the message including
+ the message type byte but not including the checksum. */
+ case FB3110_RX_GetLength:
+ i->FrameLength = rx_byte;
+ i->BufferCount = 0;
+ i->Checksum ^= rx_byte;
+ i->State = FB3110_RX_GetMessage;
+ break;
+
+ /* Get each byte of the message. We deliberately
+ get one too many bytes so we get the checksum
+ here as well. */
+ case FB3110_RX_GetMessage:
+ i->Buffer[i->BufferCount] = rx_byte;
+ i->BufferCount++;
+
+ if (i->BufferCount > FB3110_MAX_FRAME_LENGTH) {
+ dprintf("FBUS: Message buffer overun - resetting\n");
+ i->State = FB3110_RX_Sync;
+ break;
+ }
+
+ /* If this is the last byte, it's the checksum. */
+ if (i->BufferCount > i->FrameLength) {
+
+ /* Is the checksum correct? */
+ if (rx_byte == i->Checksum) {
+
+ if (i->FrameType == 0x03) {
+ /* FIXME: modify Buffer[0] to code FAX frame types */
+ }
+
+ dprintf("--> %02x:%02x:", i->FrameType, i->FrameLength);
+ for (count = 0; count < i->BufferCount; count++)
+ dprintf("%02hhx:", i->Buffer[count]);
+ dprintf("\n");
+ /* Transfer message to state machine */
+ SM_IncomingFunction(statemachine, i->Buffer[0], i->Buffer, i->FrameLength);
+
+ /* Send an ack */
+ FB3110_TX_SendAck(i->Buffer, i->FrameLength);
+
+ } else {
+ /* Checksum didn't match so ignore. */
+ dprintf("Bad checksum!\n");
+ }
+ i->State = FB3110_RX_Sync;
+ }
+ i->Checksum ^= rx_byte;
+ break;
+ }
+}
+
+
+/* This is the main loop function which must be called regularly */
+/* timeout can be used to make it 'busy' or not */
+
+GSM_Error FB3110_Loop(struct timeval *timeout)
+{
+#ifndef WIN32
+ unsigned char buffer[255];
+ int count, res;
+
+ res = device_select(timeout);
+ if (res > 0) {
+ res = device_read(buffer, 255);
+ for (count = 0; count < res; count++)
+ FB3110_RX_StateMachine(buffer[count]);
+ } else
+ return GE_TIMEOUT;
+
+ /* This traps errors from device_read */
+ if (res > 0)
+ return GE_NONE;
+ else
+ return GE_INTERNALERROR;
+#else
+ return GE_NONE;
+#endif
+}
+
+
+
+/* Prepares the message header and sends it, prepends the
+ message start byte (0x01) and other values according
+ the value specified when called. Calculates checksum
+ and then sends the lot down the pipe... */
+
+GSM_Error FB3110_TX_SendFrame(u8 message_length, u8 message_type, u8 sequence_byte, u8 * buffer)
+{
+
+ u8 out_buffer[FB3110_MAX_TRANSMIT_LENGTH];
+ int count, current = 0;
+ unsigned char checksum;
+
+ /* Check message isn't too long, once the necessary
+ header and trailer bytes are included. */
+ if ((message_length + 5) > FB3110_MAX_TRANSMIT_LENGTH) {
+ fprintf(stderr, _("FB3110_TX_SendFrame - message too long!\n"));
+ return (GE_INTERNALERROR);
+ }
+
+ /* Now construct the message header. */
+ out_buffer[current++] = FB3110_FRAME_ID; /* Start of frame */
+ out_buffer[current++] = message_length + 2; /* Length */
+ out_buffer[current++] = message_type; /* Type */
+ out_buffer[current++] = sequence_byte; /* Sequence number */
+
+ /* 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. */
+ checksum = 0;
+ for (count = 0; count < current; count++)
+ checksum ^= out_buffer[count];
+ out_buffer[current++] = checksum;
+
+ dprintf("<-- ");
+ for (count = 0; count < current; count++)
+ dprintf("%02hhx:", out_buffer[count]);
+ dprintf("\n");
+
+ /* Send it out... */
+ if (device_write(out_buffer, current) != current)
+ return (GE_INTERNALERROR);
+
+ return (GE_NONE);
+}
+
+
+/* Main function to send an fbus message */
+
+GSM_Error FB3110_SendMessage(u16 messagesize, u8 messagetype, void *message)
+{
+ u8 seqnum;
+
+ FB3110_UpdateSequenceNumber();
+ seqnum = flink.RequestSequenceNumber;
+
+ return FB3110_TX_SendFrame(messagesize, messagetype, seqnum, message);
+}
+
+
+/* Sends the "standard" acknowledge message back to the phone in
+ response to a message it sent automatically or in response to
+ a command sent to it. The ack. algorithm isn't 100% understood
+ at this time. */
+
+void FB3110_TX_SendAck(u8 *message, int length)
+{
+ u8 t = message[0];
+
+ switch (t) {
+ case 0x0a:
+ /* We send 0x0a messages to make a call so don't ack. */
+ case 0x0c:
+ /* We send 0x0c message to answer to incoming call
+ so don't ack */
+ case 0x0f:
+ /* We send 0x0f message to hang up so don't ack */
+ case 0x15:
+ /* 0x15 messages are sent by the phone in response to the
+ init sequence sent so we don't acknowledge them! */
+ case 0x20:
+ /* We send 0x20 message to phone to send DTFM, so don't ack */
+ case 0x23:
+ /* We send 0x23 messages to phone as a header for outgoing SMS
+ messages. So we don't acknowledge it. */
+ case 0x24:
+ /* We send 0x24 messages to phone as a header for storing SMS
+ messages in memory. So we don't acknowledge it. :) */
+ case 0x25:
+ /* We send 0x25 messages to phone to request an SMS message
+ be dumped. Thus we don't acknowledge it. */
+ case 0x26:
+ /* We send 0x26 messages to phone to delete an SMS message
+ so it's not acknowledged. */
+ case 0x3f:
+ /* We send an 0x3f message to the phone to request a different
+ type of status dump - this one seemingly concerned with
+ SMS message center details. Phone responds with an ack to
+ our 0x3f request then sends an 0x41 message that has the
+ actual data in it. */
+ case 0x4a:
+ /* 0x4a message is a response to our 0x4a request, assumed to
+ be a keepalive message of sorts. No response required. */
+ case 0x4c:
+ /* We send 0x4c to request IMEI, Revision and Model info. */
+ break;
+ case 0x27:
+ /* 0x27 messages are a little different in that both ends of
+ the link send them. So, first we have to check if this
+ is an acknowledgement or a message to be acknowledged */
+ if (length == 0x02) break;
+ default:
+ /* Standard acknowledge seems to be to return an empty message
+ with the sequence number set to equal the sequence number
+ sent minus 0x08. */
+ if (FB3110_TX_SendFrame(0, t, (message[1] & 0x1f) - 0x08, NULL) != GE_NONE)
+ dprintf("Failed to acknowledge message type %02x.\n", t);
+ else
+ dprintf("Acknowledged message type %02x.\n", t);
+ }
+}
+
+
+/* Initialise variables and start the link */
+/* newlink is actually part of state - but the link code should not anything about state */
+/* state is only passed around to allow for muliple state machines (one day...) */
+
+GSM_Error FB3110_Initialise(GSM_Link *newlink, GSM_Statemachine *state)
+{
+ unsigned char init_char = 0x55;
+ unsigned char count;
+ static int try = 0;
+
+ try++;
+ if (try > 2) return GE_DEVICEOPENFAILED;
+ /* 'Copy in' the global structures */
+ glink = newlink;
+ statemachine = state;
+
+ /* Fill in the link functions */
+ glink->Loop = &FB3110_Loop;
+ glink->SendMessage = &FB3110_SendMessage;
+
+ /* Check for a valid init length */
+ if (glink->InitLength == 0)
+ glink->InitLength = 100;
+
+ /* Start up the link */
+
+ flink.RequestSequenceNumber = 0x10;
+
+ if (!FB3110_OpenSerial()) return GE_DEVICEOPENFAILED;
+
+ /* Send init string to phone, this is a bunch of 0x55 characters.
+ Timing is empirical. I believe that we need/can do this for any
+ phone to get the UART synced */
+ for (count = 0; count < glink->InitLength; count++) {
+ usleep(1000);
+ device_write(&init_char, 1);
+ }
+
+ /* Init variables */
+ flink.i.State = FB3110_RX_Sync;
+
+ return GE_NONE;
+}
+
+
+/* Any command we originate must have a unique SequenceNumber.
+ Observation to date suggests that these values startx at 0x10
+ and cycle up to 0x17 before repeating again. Perhaps more
+ accurately, the numbers cycle 0,1,2,3..7 with bit 4 of the byte
+ premanently set. */
+
+void FB3110_UpdateSequenceNumber(void)
+{
+ flink.RequestSequenceNumber++;
+
+ if (flink.RequestSequenceNumber > 0x17 || flink.RequestSequenceNumber < 0x10) {
+ flink.RequestSequenceNumber = 0x10;
+ }
+}