X-Git-Url: https://git.jankratochvil.net/?p=gnokii.git;a=blobdiff_plain;f=common%2Flinks%2Ffbus.c;fp=common%2Flinks%2Ffbus.c;h=49c133220886428314123d3d2d8175b0679b4ace;hp=0000000000000000000000000000000000000000;hb=bc18a8d35c8a9b13b538ea7129402130097e140f;hpb=ae0ef1dec0b1ac636cb391dbe4f97024b3f0d048 diff --git a/common/links/fbus.c b/common/links/fbus.c new file mode 100644 index 0000000..49c1332 --- /dev/null +++ b/common/links/fbus.c @@ -0,0 +1,587 @@ +/* + + $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. + Copyright (C) 2000 Chris Kemp + + 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.13 2001/11/17 20:14:15 pkot + Nasty bug with counting message length. Workaround applied. Needs fixing. + + Revision 1.12 2001/11/15 12:04:05 pkot + Faster initialization for 6100 series (don't check for dlr3 cable) + + Revision 1.11 2001/09/09 21:45:49 machek + Cleanups from Ladislav Michl : + + *) do *not* internationalize debug messages + + *) some whitespace fixes, do not use // + + *) break is unneccessary after return + + Revision 1.10 2001/08/20 23:27:37 pkot + Add hardware shakehand to the link layer (Manfred Jonsson) + + Revision 1.9 2001/05/28 09:25:16 pkot + Fixed autodetecting of the cable type in 6110 and 7110 series. DLR-3 is + tried first now. Seems to work ok with either 6130 or 6210. + + Revision 1.8 2001/05/07 16:24:03 pkot + DLR-3P temporary fix. How should I do it better? + + Revision 1.7 2001/03/22 16:17:05 chris + Tidy-ups and fixed gnokii/Makefile and gnokii/ChangeLog which I somehow corrupted. + + Revision 1.6 2001/03/21 23:36:05 chris + Added the statemachine + This will break gnokii --identify and --monitor except for 6210/7110 + + Revision 1.5 2001/03/19 23:44:56 pkot + DLR3 cable support + + Revision 1.4 2001/03/13 01:24:02 pkot + Code cleanup - no warnings during compilation + + Revision 1.3 2001/03/13 01:23:18 pkot + Windows updates (Manfred Jonsson) + + Revision 1.2 2001/03/11 11:18:39 machek + Made fbus link_dispatch (and fixed minor memory leak) + + Revision 1.1 2001/02/21 19:57:06 chris + More fiddling with the directory layout + + Revision 1.1 2001/02/16 14:29:52 chris + Restructure of common/. Fixed a problem in fbus-phonet.c + Lots of dprintfs for Marcin + Any size xpm can now be loaded (eg for 7110 startup logos) + nk7110 code detects 7110/6210 and alters startup logo size to suit + Moved Marcin's extended phonebook code into gnokii.c + + Revision 1.3 2001/02/06 21:15:34 chris + Preliminary irda support for 7110 etc. Not well tested! + + Revision 1.2 2001/02/03 23:56:14 chris + Start of work on irda support (now we just need fbus-irda.c!) + Proper unicode support in 7110 code (from pkot) + + Revision 1.1 2001/01/14 22:46:59 chris + Preliminary 7110 support (dlr9 only) and the beginnings of a new structure + + +*/ + +/* System header files */ + +#include +#include +#include + +/* 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_c +#include "links/fbus.h" + +/* FIXME - pass device_* the link stuff?? */ +/* FIXME - win32 stuff! */ + + +/* Some globals */ + +static GSM_Link *glink; +static GSM_Statemachine *statemachine; +static FBUS_Link flink; /* FBUS specific stuff, internal to this file */ + + +/*--------------------------------------------*/ + +bool FBUS_OpenSerial(bool dlr3) +{ + if (dlr3) dlr3 = 1; + /* Open device. */ +#ifdef WIN32 + if (OpenConnection(glink->PortDevice, FBUS_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); + + /* clearing the RTS bit and setting the DTR bit */ + device_setdtrrts((1-dlr3), 0); + + return (true); +} + + +/* RX_State machine for receive handling. Called once for each character + received from the phone. */ + +void FBUS_RX_StateMachine(unsigned char rx_byte) +{ + + struct timeval time_diff; + FBUS_IncomingFrame *i = &flink.i; + int frm_num, seq_num; + FBUS_IncomingMessage *m; + +#if 0 + if (isprint(rx_byte)) + dprintf("[%02x%c]", (unsigned char) rx_byte, rx_byte); + else + dprintf("[%02x ]", (unsigned char) rx_byte); +#endif + + /* XOR the byte with the current checksum */ + i->checksum[i->BufferCount & 1] ^= rx_byte; + + switch (i->state) { + + /* Messages from the phone start with an 0x1e (cable) or 0x1c (IR). + 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: + gettimeofday(&i->time_now, NULL); + timersub(&i->time_now, &i->time_last, &time_diff); + if (time_diff.tv_sec == 0 && time_diff.tv_usec < 5000) { + i->time_last = i->time_now; /* no gap seen, continue discarding */ + break; + } + + /* else fall through to... */ + + case FBUS_RX_Sync: + if (glink->ConnectionType == GCT_Infrared) { + if (rx_byte == FBUS_IR_FRAME_ID) { + /* Initialize checksums. */ + i->checksum[0] = FBUS_IR_FRAME_ID; + i->checksum[1] = 0; + i->state = FBUS_RX_GetDestination; + } else { + /* Lost frame sync */ + i->state = FBUS_RX_Discarding; + gettimeofday(&i->time_last, NULL); + } + + } else { /* glink->ConnectionType == GCT_Serial */ + if (rx_byte == FBUS_FRAME_ID) { + /* Initialize checksums. */ + i->checksum[0] = FBUS_FRAME_ID; + i->checksum[1] = 0; + i->state = FBUS_RX_GetDestination; + } else { + /* Lost frame sync */ + i->state = FBUS_RX_Discarding; + gettimeofday(&i->time_last, NULL); + } + } + + break; + + case FBUS_RX_GetDestination: + + i->MessageDestination = rx_byte; + i->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 */ + + if (rx_byte != 0x0c) { + i->state = FBUS_RX_Sync; + dprintf("The fbus stream is out of sync - expected 0x0c, got %2x\n", rx_byte); + } + + break; + + case FBUS_RX_GetSource: + + i->MessageSource = rx_byte; + i->state = FBUS_RX_GetType; + + /* Source should be 0x00 */ + + if (rx_byte != 0x00) { + i->state = FBUS_RX_Sync; + dprintf("The fbus stream is out of sync - expected 0x00, got %2x\n",rx_byte); + } + + break; + + case FBUS_RX_GetType: + + i->MessageType = rx_byte; + i->state = FBUS_RX_GetLength1; + + break; + + case FBUS_RX_GetLength1: + + i->FrameLength = rx_byte << 8; + i->state = FBUS_RX_GetLength2; + + break; + + case FBUS_RX_GetLength2: + + i->FrameLength = i->FrameLength + rx_byte; + i->state = FBUS_RX_GetMessage; + i->BufferCount = 0; + + break; + + case FBUS_RX_GetMessage: + + i->MessageBuffer[i->BufferCount] = rx_byte; + i->BufferCount++; + + if (i->BufferCount > FBUS_MAX_FRAME_LENGTH) { + dprintf("FBUS: Message buffer overun - resetting\n"); + i->state = FBUS_RX_Sync; + break; + } + + /* If this is the last byte, it's the checksum. */ + + if (i->BufferCount == i->FrameLength + (i->FrameLength % 2) + 2) { + /* Is the checksum correct? */ + if (i->checksum[0] == i->checksum[1]) { + + /* Deal with exceptions to the rules - acks and rlp.. */ + + if (i->MessageType == 0x7f) { + dprintf("[Received Ack of type %02x, seq: %2x]\n", + i->MessageBuffer[0],(unsigned char) i->MessageBuffer[1]); + + } else { /* Normal message type */ + + /* Add data to the relevant Message buffer */ + /* having checked the sequence number */ + + m = &flink.messages[i->MessageType]; + + frm_num = i->MessageBuffer[i->FrameLength - 2]; + seq_num = i->MessageBuffer[i->FrameLength - 1]; + + + /* 0x40 in the sequence number indicates first frame of a message */ + + if ((seq_num & 0x40) == 0x40) { + /* Fiddle around and malloc some memory */ + m->MessageLength = 0; + m->FramesToGo = frm_num; + if (m->Malloced != 0) { + free(m->MessageBuffer); + m->Malloced = 0; + m->MessageBuffer = NULL; + } + m->Malloced = frm_num * m->MessageLength; + m->MessageBuffer = (char *) malloc(m->Malloced); + + } else if (m->FramesToGo != frm_num) { + dprintf("Missed a frame in a multiframe message.\n"); + /* FIXME - we should make sure we don't ack the rest etc */ + } + + if (m->Malloced < m->MessageLength + i->FrameLength) { + m->Malloced = m->MessageLength + i->FrameLength; + m->MessageBuffer = (char *) realloc(m->MessageBuffer, m->Malloced); + } + + memcpy(m->MessageBuffer + m->MessageLength, i->MessageBuffer, + i->FrameLength - 2);/* - (i->FrameLength % 2)); */ + + m->MessageLength += i->FrameLength - 2;/* - (i->FrameLength % 2); */ + + m->FramesToGo--; + + /* Finally dispatch if ready */ + + if (m->FramesToGo == 0) { + SM_IncomingFunction(statemachine, i->MessageType, m->MessageBuffer, m->MessageLength); + free(m->MessageBuffer); + m->MessageBuffer = NULL; + m->Malloced = 0; + } + + /* Send an ack (for all for now) */ + + FBUS_TX_SendAck(i->MessageType, seq_num & 0x0f); + + } + } else { + dprintf("Bad checksum!\n"); + } + i->state = FBUS_RX_Sync; + } + break; + } +} + + +/* This is the main loop function which must be called regularly */ +/* timeout can be used to make it 'busy' or not */ + +GSM_Error FBUS_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++) + FBUS_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 + (0x1e) and other values according the value specified when called. + Calculates checksum and then sends the lot down the pipe... */ + +int FBUS_TX_SendFrame(u8 message_length, u8 message_type, u8 * buffer) +{ + + u8 out_buffer[FBUS_MAX_TRANSMIT_LENGTH + 5]; + int count, current = 0; + unsigned char checksum; + + /* FIXME - we should check for the message length ... */ + + /* Now construct the message header. */ + + if (glink->ConnectionType == GCT_Infrared) + out_buffer[current++] = FBUS_IR_FRAME_ID; /* Start of the IR frame indicator */ + else /* ConnectionType == GCT_Serial */ + out_buffer[current++] = FBUS_FRAME_ID; /* Start of the frame indicator */ + + out_buffer[current++] = FBUS_DEVICE_PHONE; /* Destination */ + out_buffer[current++] = FBUS_DEVICE_PC; /* Source */ + + out_buffer[current++] = message_type; /* Type */ + + out_buffer[current++] = 0; /* Length */ + + out_buffer[current++] = message_length; /* Length */ + + /* Copy in data if any. */ + + if (message_length != 0) { + memcpy(out_buffer + current, buffer, message_length); + current += message_length; + } + + /* If the message length is odd we should add pad byte 0x00 */ + if (message_length % 2) + out_buffer[current++] = 0x00; + + /* Now calculate checksums over entire message and append to message. */ + + /* Odd bytes */ + + checksum = 0; + for (count = 0; count < current; count += 2) + checksum ^= out_buffer[count]; + + out_buffer[current++] = checksum; + + /* Even bytes */ + + checksum = 0; + for (count = 1; count < current; count += 2) + checksum ^= out_buffer[count]; + + out_buffer[current++] = checksum; + +#ifdef DEBUG + fprintf(stderr, _("PC: ")); + + for (count = 0; count < current; count++) + fprintf(stderr, "%02x:", out_buffer[count]); + + fprintf(stderr, "\n"); +#endif /* DEBUG */ + + /* Send it out... */ + + if (device_write(out_buffer, current) != current) + return (false); + + return (true); +} + + +/* Main function to send an fbus message */ +/* Splits up the message into frames if necessary */ + +GSM_Error FBUS_SendMessage(u16 messagesize, u8 messagetype, void *message) +{ + + u8 seqnum, frame_buffer[FBUS_MAX_CONTENT_LENGTH + 2]; + u8 nom, lml; /* number of messages, last message len */ + int i; + + seqnum = 0x40 + flink.RequestSequenceNumber; + flink.RequestSequenceNumber = + (flink.RequestSequenceNumber + 1) & 0x07; + + if (messagesize > FBUS_MAX_CONTENT_LENGTH) { + + nom = (messagesize + FBUS_MAX_CONTENT_LENGTH - 1) + / FBUS_MAX_CONTENT_LENGTH; + lml = messagesize - ((nom - 1) * FBUS_MAX_CONTENT_LENGTH); + + for (i = 0; i < nom - 1; i++) { + + memcpy(frame_buffer, message + (i * FBUS_MAX_CONTENT_LENGTH), + FBUS_MAX_CONTENT_LENGTH); + frame_buffer[FBUS_MAX_CONTENT_LENGTH] = nom - i; + frame_buffer[FBUS_MAX_CONTENT_LENGTH + 1] = seqnum; + + FBUS_TX_SendFrame(FBUS_MAX_CONTENT_LENGTH + 2, + messagetype, frame_buffer); + + seqnum = flink.RequestSequenceNumber; + flink.RequestSequenceNumber = (flink.RequestSequenceNumber + 1) & 0x07; + } + + memcpy(frame_buffer, message + ((nom - 1) * FBUS_MAX_CONTENT_LENGTH), lml); + frame_buffer[lml] = 0x01; + frame_buffer[lml + 1] = seqnum; + FBUS_TX_SendFrame(lml + 2, messagetype, frame_buffer); + + } else { + + memcpy(frame_buffer, message, messagesize); + frame_buffer[messagesize] = 0x01; + frame_buffer[messagesize + 1] = seqnum; + FBUS_TX_SendFrame(messagesize + 2, messagetype, + frame_buffer); + } + return (GE_NONE); +} + + +int FBUS_TX_SendAck(u8 message_type, u8 message_seq) +{ + + unsigned char request[2]; + + request[0] = message_type; + request[1] = message_seq; + + dprintf("[Sending Ack of type %02x, seq: %x]\n",message_type, message_seq); + + return FBUS_TX_SendFrame(2, 0x7f, request); +} + + +/* 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 FBUS_Initialise(GSM_Link *newlink, GSM_Statemachine *state, int type) +{ + unsigned char init_char = 0x55; + unsigned char count; + + if (type > 2) return GE_DEVICEOPENFAILED; + /* 'Copy in' the global structures */ + glink = newlink; + statemachine = state; + + /* Fill in the link functions */ + glink->Loop = &FBUS_Loop; + glink->SendMessage = &FBUS_SendMessage; + + /* Check for a valid init length */ + if (glink->InitLength == 0) + glink->InitLength = 250; + + /* Start up the link */ + flink.RequestSequenceNumber = 0; + + if (glink->ConnectionType == GCT_Infrared) { + /* FIXME!! */ + return GE_DEVICEOPENFAILED; + } else { /* ConnectionType == GCT_Serial */ + /* FBUS_OpenSerial(0) - try dau-9p + * FBUS_OpenSerial(n != 0) - try dlr-3p */ + if (!FBUS_OpenSerial(type)) + 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(100); + device_write(&init_char, 1); + } + + /* Init variables */ + flink.i.state = FBUS_RX_Sync; + flink.i.BufferCount = 0; + for (count = 0; count < FBUS_MAX_MESSAGE_TYPES; count++) { + flink.messages[count].Malloced = 0; + flink.messages[count].FramesToGo = 0; + flink.messages[count].MessageLength = 0; + } + + return GE_NONE; +}