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.12.1 2001/11/27 23:34:48 short
20 Update: orig2001_11_27_05_17 -> orig2001_11_27_22_58
22 Revision 1.1.1.1.8.1 2001/11/27 23:06:09 short
23 Update: orig2001_11_27_05_17 -> orig2001_11_27_22_58
25 Revision 1.1.1.1.2.1 2001/11/27 22:48:37 short
26 Update: orig2001_11_27_05_17 -> orig2001_11_27_22_58
28 Revision 1.1.1.2 2001/11/27 22:01:16 short
29 :pserver:cvs@pserver.samba.org:/cvsroot - gnokii - Tue Nov 27 22:58 CET 2001
31 Revision 1.3 2001/11/27 12:19:01 pkot
32 Cleanup, indentation, ANSI complaint preprocesor symbols (Jan Kratochvil, me)
34 Revision 1.2 2001/11/09 14:25:04 pkot
37 Revision 1.1 2001/11/09 12:55:07 pkot
38 Forgot about fbus support for 3110. FIXME: is it really needed?
43 /* System header files */
49 /* Various header file */
53 #include "gsm-common.h"
54 #include "gsm-ringtones.h"
55 #include "gsm-networks.h"
56 #include "gsm-statemachine.h"
57 #include "links/utils.h"
62 # include "win32/winserial.h"
63 # define device_write(a, b) WriteCommBlock(a, b)
64 # define device_read(a, b) ReadCommBlock(a, b)
65 # define sleep(x) Sleep((x) * 1000)
66 # define usleep(x) Sleep(((x) < 1000) ? 1 : ((x) / 1000))
69 #define __links_fbus_3110_c
70 #include "links/fbus-3110.h"
72 /* FIXME - pass device_* the link stuff?? */
73 /* FIXME - win32 stuff! */
78 static GSM_Link *glink;
79 static GSM_Statemachine *statemachine;
80 static FB3110_Link flink; /* FBUS specific stuff, internal to this file */
83 /*--------------------------------------------*/
85 bool FB3110_OpenSerial(void)
89 if (OpenConnection(glink->PortDevice, FB3110_RX_StateMachine, NULL)) {
91 if (!device_open(glink->PortDevice, false, false, false, GCT_Serial)) {
93 perror(_("Couldn't open FBUS device"));
96 device_changespeed(115200);
102 /* RX_State machine for receive handling. Called once for each character
103 received from the phone. */
105 void FB3110_RX_StateMachine(unsigned char rx_byte)
107 FB3110_IncomingFrame *i = &flink.i;
112 /* Phone is currently off. Wait for 0x55 before
114 case FB3110_RX_Discarding:
118 /* Seen 0x55, restart at 0x04 */
119 i->State = FB3110_RX_Sync;
121 dprintf("restarting.\n");
125 /* Messages from the phone start with an 0x04 during
126 "normal" operation, 0x03 when in data/fax mode. We
127 use this to "synchronise" with the incoming data
130 if (rx_byte == 0x04 || rx_byte == 0x03) {
131 i->FrameType = rx_byte;
132 i->Checksum = rx_byte;
133 i->State = FB3110_RX_GetLength;
137 /* Next byte is the length of the message including
138 the message type byte but not including the checksum. */
139 case FB3110_RX_GetLength:
140 i->FrameLength = rx_byte;
142 i->Checksum ^= rx_byte;
143 i->State = FB3110_RX_GetMessage;
146 /* Get each byte of the message. We deliberately
147 get one too many bytes so we get the checksum
149 case FB3110_RX_GetMessage:
150 i->Buffer[i->BufferCount] = rx_byte;
153 if (i->BufferCount > FB3110_MAX_FRAME_LENGTH) {
154 dprintf("FBUS: Message buffer overun - resetting\n");
155 i->State = FB3110_RX_Sync;
159 /* If this is the last byte, it's the checksum. */
160 if (i->BufferCount > i->FrameLength) {
162 /* Is the checksum correct? */
163 if (rx_byte == i->Checksum) {
165 if (i->FrameType == 0x03) {
166 /* FIXME: modify Buffer[0] to code FAX frame types */
169 dprintf("--> %02x:%02x:", i->FrameType, i->FrameLength);
170 for (count = 0; count < i->BufferCount; count++)
171 dprintf("%02hhx:", i->Buffer[count]);
173 /* Transfer message to state machine */
174 SM_IncomingFunction(statemachine, i->Buffer[0], i->Buffer, i->FrameLength);
177 FB3110_TX_SendAck(i->Buffer, i->FrameLength);
180 /* Checksum didn't match so ignore. */
181 dprintf("Bad checksum!\n");
183 i->State = FB3110_RX_Sync;
185 i->Checksum ^= rx_byte;
191 /* This is the main loop function which must be called regularly */
192 /* timeout can be used to make it 'busy' or not */
194 GSM_Error FB3110_Loop(struct timeval *timeout)
197 unsigned char buffer[255];
200 res = device_select(timeout);
202 res = device_read(buffer, 255);
203 for (count = 0; count < res; count++)
204 FB3110_RX_StateMachine(buffer[count]);
208 /* This traps errors from device_read */
212 return GE_INTERNALERROR;
220 /* Prepares the message header and sends it, prepends the
221 message start byte (0x01) and other values according
222 the value specified when called. Calculates checksum
223 and then sends the lot down the pipe... */
225 GSM_Error FB3110_TX_SendFrame(u8 message_length, u8 message_type, u8 sequence_byte, u8 * buffer)
228 u8 out_buffer[FB3110_MAX_TRANSMIT_LENGTH];
229 int count, current = 0;
230 unsigned char checksum;
232 /* Check message isn't too long, once the necessary
233 header and trailer bytes are included. */
234 if ((message_length + 5) > FB3110_MAX_TRANSMIT_LENGTH) {
235 fprintf(stderr, _("FB3110_TX_SendFrame - message too long!\n"));
236 return (GE_INTERNALERROR);
239 /* Now construct the message header. */
240 out_buffer[current++] = FB3110_FRAME_ID; /* Start of frame */
241 out_buffer[current++] = message_length + 2; /* Length */
242 out_buffer[current++] = message_type; /* Type */
243 out_buffer[current++] = sequence_byte; /* Sequence number */
245 /* Copy in data if any. */
246 if (message_length != 0) {
247 memcpy(out_buffer + current, buffer, message_length);
248 current += message_length;
251 /* Now calculate checksum over entire message
252 and append to message. */
254 for (count = 0; count < current; count++)
255 checksum ^= out_buffer[count];
256 out_buffer[current++] = checksum;
259 for (count = 0; count < current; count++)
260 dprintf("%02hhx:", out_buffer[count]);
264 if (device_write(out_buffer, current) != current)
265 return (GE_INTERNALERROR);
271 /* Main function to send an fbus message */
273 GSM_Error FB3110_SendMessage(u16 messagesize, u8 messagetype, void *message)
277 FB3110_UpdateSequenceNumber();
278 seqnum = flink.RequestSequenceNumber;
280 return FB3110_TX_SendFrame(messagesize, messagetype, seqnum, message);
284 /* Sends the "standard" acknowledge message back to the phone in
285 response to a message it sent automatically or in response to
286 a command sent to it. The ack. algorithm isn't 100% understood
289 void FB3110_TX_SendAck(u8 *message, int length)
295 /* We send 0x0a messages to make a call so don't ack. */
297 /* We send 0x0c message to answer to incoming call
300 /* We send 0x0f message to hang up so don't ack */
302 /* 0x15 messages are sent by the phone in response to the
303 init sequence sent so we don't acknowledge them! */
305 /* We send 0x20 message to phone to send DTFM, so don't ack */
307 /* We send 0x23 messages to phone as a header for outgoing SMS
308 messages. So we don't acknowledge it. */
310 /* We send 0x24 messages to phone as a header for storing SMS
311 messages in memory. So we don't acknowledge it. :) */
313 /* We send 0x25 messages to phone to request an SMS message
314 be dumped. Thus we don't acknowledge it. */
316 /* We send 0x26 messages to phone to delete an SMS message
317 so it's not acknowledged. */
319 /* We send an 0x3f message to the phone to request a different
320 type of status dump - this one seemingly concerned with
321 SMS message center details. Phone responds with an ack to
322 our 0x3f request then sends an 0x41 message that has the
323 actual data in it. */
325 /* 0x4a message is a response to our 0x4a request, assumed to
326 be a keepalive message of sorts. No response required. */
328 /* We send 0x4c to request IMEI, Revision and Model info. */
331 /* 0x27 messages are a little different in that both ends of
332 the link send them. So, first we have to check if this
333 is an acknowledgement or a message to be acknowledged */
334 if (length == 0x02) break;
336 /* Standard acknowledge seems to be to return an empty message
337 with the sequence number set to equal the sequence number
339 if (FB3110_TX_SendFrame(0, t, (message[1] & 0x1f) - 0x08, NULL) != GE_NONE)
340 dprintf("Failed to acknowledge message type %02x.\n", t);
342 dprintf("Acknowledged message type %02x.\n", t);
347 /* Initialise variables and start the link */
348 /* newlink is actually part of state - but the link code should not anything about state */
349 /* state is only passed around to allow for muliple state machines (one day...) */
351 GSM_Error FB3110_Initialise(GSM_Link *newlink, GSM_Statemachine *state)
353 unsigned char init_char = 0x55;
358 if (try > 2) return GE_DEVICEOPENFAILED;
359 /* 'Copy in' the global structures */
361 statemachine = state;
363 /* Fill in the link functions */
364 glink->Loop = &FB3110_Loop;
365 glink->SendMessage = &FB3110_SendMessage;
367 /* Check for a valid init length */
368 if (glink->InitLength == 0)
369 glink->InitLength = 100;
371 /* Start up the link */
373 flink.RequestSequenceNumber = 0x10;
375 if (!FB3110_OpenSerial()) return GE_DEVICEOPENFAILED;
377 /* Send init string to phone, this is a bunch of 0x55 characters.
378 Timing is empirical. I believe that we need/can do this for any
379 phone to get the UART synced */
380 for (count = 0; count < glink->InitLength; count++) {
382 device_write(&init_char, 1);
386 flink.i.State = FB3110_RX_Sync;
392 /* Any command we originate must have a unique SequenceNumber.
393 Observation to date suggests that these values startx at 0x10
394 and cycle up to 0x17 before repeating again. Perhaps more
395 accurately, the numbers cycle 0,1,2,3..7 with bit 4 of the byte
398 void FB3110_UpdateSequenceNumber(void)
400 flink.RequestSequenceNumber++;
402 if (flink.RequestSequenceNumber > 0x17 || flink.RequestSequenceNumber < 0x10) {
403 flink.RequestSequenceNumber = 0x10;