7 A Linux/Unix toolset and driver for Nokia mobile phones.
9 Copyright (C) 2000 Hugh Blemings & Pavel JanÃk ml.
11 Released under the terms of the GNU GPL, see file COPYING for more details.
13 This file provides an API for accessing functions via fbus.
14 See README for more details on supported mobile phones.
16 The various routines are called FBUS_(whatever).
19 Revision 1.1.1.1.2.1 2001/11/27 22:48:37 short
20 Update: orig2001_11_27_05_17 -> orig2001_11_27_22_58
22 Revision 1.1.1.2 2001/11/27 22:01:16 short
23 :pserver:cvs@pserver.samba.org:/cvsroot - gnokii - Tue Nov 27 22:58 CET 2001
25 Revision 1.3 2001/11/27 12:19:01 pkot
26 Cleanup, indentation, ANSI complaint preprocesor symbols (Jan Kratochvil, me)
28 Revision 1.2 2001/11/09 14:25:04 pkot
31 Revision 1.1 2001/11/09 12:55:07 pkot
32 Forgot about fbus support for 3110. FIXME: is it really needed?
37 /* System header files */
43 /* Various header file */
47 #include "gsm-common.h"
48 #include "gsm-ringtones.h"
49 #include "gsm-networks.h"
50 #include "gsm-statemachine.h"
51 #include "links/utils.h"
56 # include "win32/winserial.h"
57 # define device_write(a, b) WriteCommBlock(a, b)
58 # define device_read(a, b) ReadCommBlock(a, b)
59 # define sleep(x) Sleep((x) * 1000)
60 # define usleep(x) Sleep(((x) < 1000) ? 1 : ((x) / 1000))
63 #define __links_fbus_3110_c
64 #include "links/fbus-3110.h"
66 /* FIXME - pass device_* the link stuff?? */
67 /* FIXME - win32 stuff! */
72 static GSM_Link *glink;
73 static GSM_Statemachine *statemachine;
74 static FB3110_Link flink; /* FBUS specific stuff, internal to this file */
77 /*--------------------------------------------*/
79 bool FB3110_OpenSerial(void)
83 if (OpenConnection(glink->PortDevice, FB3110_RX_StateMachine, NULL)) {
85 if (!device_open(glink->PortDevice, false, false, false, GCT_Serial)) {
87 perror(_("Couldn't open FBUS device"));
90 device_changespeed(115200);
96 /* RX_State machine for receive handling. Called once for each character
97 received from the phone. */
99 void FB3110_RX_StateMachine(unsigned char rx_byte)
101 FB3110_IncomingFrame *i = &flink.i;
106 /* Phone is currently off. Wait for 0x55 before
108 case FB3110_RX_Discarding:
112 /* Seen 0x55, restart at 0x04 */
113 i->State = FB3110_RX_Sync;
115 dprintf("restarting.\n");
119 /* Messages from the phone start with an 0x04 during
120 "normal" operation, 0x03 when in data/fax mode. We
121 use this to "synchronise" with the incoming data
124 if (rx_byte == 0x04 || rx_byte == 0x03) {
125 i->FrameType = rx_byte;
126 i->Checksum = rx_byte;
127 i->State = FB3110_RX_GetLength;
131 /* Next byte is the length of the message including
132 the message type byte but not including the checksum. */
133 case FB3110_RX_GetLength:
134 i->FrameLength = rx_byte;
136 i->Checksum ^= rx_byte;
137 i->State = FB3110_RX_GetMessage;
140 /* Get each byte of the message. We deliberately
141 get one too many bytes so we get the checksum
143 case FB3110_RX_GetMessage:
144 i->Buffer[i->BufferCount] = rx_byte;
147 if (i->BufferCount > FB3110_MAX_FRAME_LENGTH) {
148 dprintf("FBUS: Message buffer overun - resetting\n");
149 i->State = FB3110_RX_Sync;
153 /* If this is the last byte, it's the checksum. */
154 if (i->BufferCount > i->FrameLength) {
156 /* Is the checksum correct? */
157 if (rx_byte == i->Checksum) {
159 if (i->FrameType == 0x03) {
160 /* FIXME: modify Buffer[0] to code FAX frame types */
163 dprintf("--> %02x:%02x:", i->FrameType, i->FrameLength);
164 for (count = 0; count < i->BufferCount; count++)
165 dprintf("%02hhx:", i->Buffer[count]);
167 /* Transfer message to state machine */
168 SM_IncomingFunction(statemachine, i->Buffer[0], i->Buffer, i->FrameLength);
171 FB3110_TX_SendAck(i->Buffer, i->FrameLength);
174 /* Checksum didn't match so ignore. */
175 dprintf("Bad checksum!\n");
177 i->State = FB3110_RX_Sync;
179 i->Checksum ^= rx_byte;
185 /* This is the main loop function which must be called regularly */
186 /* timeout can be used to make it 'busy' or not */
188 GSM_Error FB3110_Loop(struct timeval *timeout)
191 unsigned char buffer[255];
194 res = device_select(timeout);
196 res = device_read(buffer, 255);
197 for (count = 0; count < res; count++)
198 FB3110_RX_StateMachine(buffer[count]);
202 /* This traps errors from device_read */
206 return GE_INTERNALERROR;
214 /* Prepares the message header and sends it, prepends the
215 message start byte (0x01) and other values according
216 the value specified when called. Calculates checksum
217 and then sends the lot down the pipe... */
219 GSM_Error FB3110_TX_SendFrame(u8 message_length, u8 message_type, u8 sequence_byte, u8 * buffer)
222 u8 out_buffer[FB3110_MAX_TRANSMIT_LENGTH];
223 int count, current = 0;
224 unsigned char checksum;
226 /* Check message isn't too long, once the necessary
227 header and trailer bytes are included. */
228 if ((message_length + 5) > FB3110_MAX_TRANSMIT_LENGTH) {
229 fprintf(stderr, _("FB3110_TX_SendFrame - message too long!\n"));
230 return (GE_INTERNALERROR);
233 /* Now construct the message header. */
234 out_buffer[current++] = FB3110_FRAME_ID; /* Start of frame */
235 out_buffer[current++] = message_length + 2; /* Length */
236 out_buffer[current++] = message_type; /* Type */
237 out_buffer[current++] = sequence_byte; /* Sequence number */
239 /* Copy in data if any. */
240 if (message_length != 0) {
241 memcpy(out_buffer + current, buffer, message_length);
242 current += message_length;
245 /* Now calculate checksum over entire message
246 and append to message. */
248 for (count = 0; count < current; count++)
249 checksum ^= out_buffer[count];
250 out_buffer[current++] = checksum;
253 for (count = 0; count < current; count++)
254 dprintf("%02hhx:", out_buffer[count]);
258 if (device_write(out_buffer, current) != current)
259 return (GE_INTERNALERROR);
265 /* Main function to send an fbus message */
267 GSM_Error FB3110_SendMessage(u16 messagesize, u8 messagetype, void *message)
271 FB3110_UpdateSequenceNumber();
272 seqnum = flink.RequestSequenceNumber;
274 return FB3110_TX_SendFrame(messagesize, messagetype, seqnum, message);
278 /* Sends the "standard" acknowledge message back to the phone in
279 response to a message it sent automatically or in response to
280 a command sent to it. The ack. algorithm isn't 100% understood
283 void FB3110_TX_SendAck(u8 *message, int length)
289 /* We send 0x0a messages to make a call so don't ack. */
291 /* We send 0x0c message to answer to incoming call
294 /* We send 0x0f message to hang up so don't ack */
296 /* 0x15 messages are sent by the phone in response to the
297 init sequence sent so we don't acknowledge them! */
299 /* We send 0x20 message to phone to send DTFM, so don't ack */
301 /* We send 0x23 messages to phone as a header for outgoing SMS
302 messages. So we don't acknowledge it. */
304 /* We send 0x24 messages to phone as a header for storing SMS
305 messages in memory. So we don't acknowledge it. :) */
307 /* We send 0x25 messages to phone to request an SMS message
308 be dumped. Thus we don't acknowledge it. */
310 /* We send 0x26 messages to phone to delete an SMS message
311 so it's not acknowledged. */
313 /* We send an 0x3f message to the phone to request a different
314 type of status dump - this one seemingly concerned with
315 SMS message center details. Phone responds with an ack to
316 our 0x3f request then sends an 0x41 message that has the
317 actual data in it. */
319 /* 0x4a message is a response to our 0x4a request, assumed to
320 be a keepalive message of sorts. No response required. */
322 /* We send 0x4c to request IMEI, Revision and Model info. */
325 /* 0x27 messages are a little different in that both ends of
326 the link send them. So, first we have to check if this
327 is an acknowledgement or a message to be acknowledged */
328 if (length == 0x02) break;
330 /* Standard acknowledge seems to be to return an empty message
331 with the sequence number set to equal the sequence number
333 if (FB3110_TX_SendFrame(0, t, (message[1] & 0x1f) - 0x08, NULL) != GE_NONE)
334 dprintf("Failed to acknowledge message type %02x.\n", t);
336 dprintf("Acknowledged message type %02x.\n", t);
341 /* Initialise variables and start the link */
342 /* newlink is actually part of state - but the link code should not anything about state */
343 /* state is only passed around to allow for muliple state machines (one day...) */
345 GSM_Error FB3110_Initialise(GSM_Link *newlink, GSM_Statemachine *state)
347 unsigned char init_char = 0x55;
352 if (try > 2) return GE_DEVICEOPENFAILED;
353 /* 'Copy in' the global structures */
355 statemachine = state;
357 /* Fill in the link functions */
358 glink->Loop = &FB3110_Loop;
359 glink->SendMessage = &FB3110_SendMessage;
361 /* Check for a valid init length */
362 if (glink->InitLength == 0)
363 glink->InitLength = 100;
365 /* Start up the link */
367 flink.RequestSequenceNumber = 0x10;
369 if (!FB3110_OpenSerial()) return GE_DEVICEOPENFAILED;
371 /* Send init string to phone, this is a bunch of 0x55 characters.
372 Timing is empirical. I believe that we need/can do this for any
373 phone to get the UART synced */
374 for (count = 0; count < glink->InitLength; count++) {
376 device_write(&init_char, 1);
380 flink.i.State = FB3110_RX_Sync;
386 /* Any command we originate must have a unique SequenceNumber.
387 Observation to date suggests that these values startx at 0x10
388 and cycle up to 0x17 before repeating again. Perhaps more
389 accurately, the numbers cycle 0,1,2,3..7 with bit 4 of the byte
392 void FB3110_UpdateSequenceNumber(void)
394 flink.RequestSequenceNumber++;
396 if (flink.RequestSequenceNumber > 0x17 || flink.RequestSequenceNumber < 0x10) {
397 flink.RequestSequenceNumber = 0x10;