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.2 2001/11/27 22:01:16 short
20 :pserver:cvs@pserver.samba.org:/cvsroot - gnokii - Tue Nov 27 22:58 CET 2001
22 Revision 1.3 2001/11/27 12:19:01 pkot
23 Cleanup, indentation, ANSI complaint preprocesor symbols (Jan Kratochvil, me)
25 Revision 1.2 2001/11/09 14:25:04 pkot
28 Revision 1.1 2001/11/09 12:55:07 pkot
29 Forgot about fbus support for 3110. FIXME: is it really needed?
34 /* System header files */
40 /* Various header file */
44 #include "gsm-common.h"
45 #include "gsm-ringtones.h"
46 #include "gsm-networks.h"
47 #include "gsm-statemachine.h"
48 #include "links/utils.h"
53 # include "win32/winserial.h"
54 # define device_write(a, b) WriteCommBlock(a, b)
55 # define device_read(a, b) ReadCommBlock(a, b)
56 # define sleep(x) Sleep((x) * 1000)
57 # define usleep(x) Sleep(((x) < 1000) ? 1 : ((x) / 1000))
60 #define __links_fbus_3110_c
61 #include "links/fbus-3110.h"
63 /* FIXME - pass device_* the link stuff?? */
64 /* FIXME - win32 stuff! */
69 static GSM_Link *glink;
70 static GSM_Statemachine *statemachine;
71 static FB3110_Link flink; /* FBUS specific stuff, internal to this file */
74 /*--------------------------------------------*/
76 bool FB3110_OpenSerial(void)
80 if (OpenConnection(glink->PortDevice, FB3110_RX_StateMachine, NULL)) {
82 if (!device_open(glink->PortDevice, false, false, false, GCT_Serial)) {
84 perror(_("Couldn't open FBUS device"));
87 device_changespeed(115200);
93 /* RX_State machine for receive handling. Called once for each character
94 received from the phone. */
96 void FB3110_RX_StateMachine(unsigned char rx_byte)
98 FB3110_IncomingFrame *i = &flink.i;
103 /* Phone is currently off. Wait for 0x55 before
105 case FB3110_RX_Discarding:
109 /* Seen 0x55, restart at 0x04 */
110 i->State = FB3110_RX_Sync;
112 dprintf("restarting.\n");
116 /* Messages from the phone start with an 0x04 during
117 "normal" operation, 0x03 when in data/fax mode. We
118 use this to "synchronise" with the incoming data
121 if (rx_byte == 0x04 || rx_byte == 0x03) {
122 i->FrameType = rx_byte;
123 i->Checksum = rx_byte;
124 i->State = FB3110_RX_GetLength;
128 /* Next byte is the length of the message including
129 the message type byte but not including the checksum. */
130 case FB3110_RX_GetLength:
131 i->FrameLength = rx_byte;
133 i->Checksum ^= rx_byte;
134 i->State = FB3110_RX_GetMessage;
137 /* Get each byte of the message. We deliberately
138 get one too many bytes so we get the checksum
140 case FB3110_RX_GetMessage:
141 i->Buffer[i->BufferCount] = rx_byte;
144 if (i->BufferCount > FB3110_MAX_FRAME_LENGTH) {
145 dprintf("FBUS: Message buffer overun - resetting\n");
146 i->State = FB3110_RX_Sync;
150 /* If this is the last byte, it's the checksum. */
151 if (i->BufferCount > i->FrameLength) {
153 /* Is the checksum correct? */
154 if (rx_byte == i->Checksum) {
156 if (i->FrameType == 0x03) {
157 /* FIXME: modify Buffer[0] to code FAX frame types */
160 dprintf("--> %02x:%02x:", i->FrameType, i->FrameLength);
161 for (count = 0; count < i->BufferCount; count++)
162 dprintf("%02hhx:", i->Buffer[count]);
164 /* Transfer message to state machine */
165 SM_IncomingFunction(statemachine, i->Buffer[0], i->Buffer, i->FrameLength);
168 FB3110_TX_SendAck(i->Buffer, i->FrameLength);
171 /* Checksum didn't match so ignore. */
172 dprintf("Bad checksum!\n");
174 i->State = FB3110_RX_Sync;
176 i->Checksum ^= rx_byte;
182 /* This is the main loop function which must be called regularly */
183 /* timeout can be used to make it 'busy' or not */
185 GSM_Error FB3110_Loop(struct timeval *timeout)
188 unsigned char buffer[255];
191 res = device_select(timeout);
193 res = device_read(buffer, 255);
194 for (count = 0; count < res; count++)
195 FB3110_RX_StateMachine(buffer[count]);
199 /* This traps errors from device_read */
203 return GE_INTERNALERROR;
211 /* Prepares the message header and sends it, prepends the
212 message start byte (0x01) and other values according
213 the value specified when called. Calculates checksum
214 and then sends the lot down the pipe... */
216 GSM_Error FB3110_TX_SendFrame(u8 message_length, u8 message_type, u8 sequence_byte, u8 * buffer)
219 u8 out_buffer[FB3110_MAX_TRANSMIT_LENGTH];
220 int count, current = 0;
221 unsigned char checksum;
223 /* Check message isn't too long, once the necessary
224 header and trailer bytes are included. */
225 if ((message_length + 5) > FB3110_MAX_TRANSMIT_LENGTH) {
226 fprintf(stderr, _("FB3110_TX_SendFrame - message too long!\n"));
227 return (GE_INTERNALERROR);
230 /* Now construct the message header. */
231 out_buffer[current++] = FB3110_FRAME_ID; /* Start of frame */
232 out_buffer[current++] = message_length + 2; /* Length */
233 out_buffer[current++] = message_type; /* Type */
234 out_buffer[current++] = sequence_byte; /* Sequence number */
236 /* Copy in data if any. */
237 if (message_length != 0) {
238 memcpy(out_buffer + current, buffer, message_length);
239 current += message_length;
242 /* Now calculate checksum over entire message
243 and append to message. */
245 for (count = 0; count < current; count++)
246 checksum ^= out_buffer[count];
247 out_buffer[current++] = checksum;
250 for (count = 0; count < current; count++)
251 dprintf("%02hhx:", out_buffer[count]);
255 if (device_write(out_buffer, current) != current)
256 return (GE_INTERNALERROR);
262 /* Main function to send an fbus message */
264 GSM_Error FB3110_SendMessage(u16 messagesize, u8 messagetype, void *message)
268 FB3110_UpdateSequenceNumber();
269 seqnum = flink.RequestSequenceNumber;
271 return FB3110_TX_SendFrame(messagesize, messagetype, seqnum, message);
275 /* Sends the "standard" acknowledge message back to the phone in
276 response to a message it sent automatically or in response to
277 a command sent to it. The ack. algorithm isn't 100% understood
280 void FB3110_TX_SendAck(u8 *message, int length)
286 /* We send 0x0a messages to make a call so don't ack. */
288 /* We send 0x0c message to answer to incoming call
291 /* We send 0x0f message to hang up so don't ack */
293 /* 0x15 messages are sent by the phone in response to the
294 init sequence sent so we don't acknowledge them! */
296 /* We send 0x20 message to phone to send DTFM, so don't ack */
298 /* We send 0x23 messages to phone as a header for outgoing SMS
299 messages. So we don't acknowledge it. */
301 /* We send 0x24 messages to phone as a header for storing SMS
302 messages in memory. So we don't acknowledge it. :) */
304 /* We send 0x25 messages to phone to request an SMS message
305 be dumped. Thus we don't acknowledge it. */
307 /* We send 0x26 messages to phone to delete an SMS message
308 so it's not acknowledged. */
310 /* We send an 0x3f message to the phone to request a different
311 type of status dump - this one seemingly concerned with
312 SMS message center details. Phone responds with an ack to
313 our 0x3f request then sends an 0x41 message that has the
314 actual data in it. */
316 /* 0x4a message is a response to our 0x4a request, assumed to
317 be a keepalive message of sorts. No response required. */
319 /* We send 0x4c to request IMEI, Revision and Model info. */
322 /* 0x27 messages are a little different in that both ends of
323 the link send them. So, first we have to check if this
324 is an acknowledgement or a message to be acknowledged */
325 if (length == 0x02) break;
327 /* Standard acknowledge seems to be to return an empty message
328 with the sequence number set to equal the sequence number
330 if (FB3110_TX_SendFrame(0, t, (message[1] & 0x1f) - 0x08, NULL) != GE_NONE)
331 dprintf("Failed to acknowledge message type %02x.\n", t);
333 dprintf("Acknowledged message type %02x.\n", t);
338 /* Initialise variables and start the link */
339 /* newlink is actually part of state - but the link code should not anything about state */
340 /* state is only passed around to allow for muliple state machines (one day...) */
342 GSM_Error FB3110_Initialise(GSM_Link *newlink, GSM_Statemachine *state)
344 unsigned char init_char = 0x55;
349 if (try > 2) return GE_DEVICEOPENFAILED;
350 /* 'Copy in' the global structures */
352 statemachine = state;
354 /* Fill in the link functions */
355 glink->Loop = &FB3110_Loop;
356 glink->SendMessage = &FB3110_SendMessage;
358 /* Check for a valid init length */
359 if (glink->InitLength == 0)
360 glink->InitLength = 100;
362 /* Start up the link */
364 flink.RequestSequenceNumber = 0x10;
366 if (!FB3110_OpenSerial()) return GE_DEVICEOPENFAILED;
368 /* Send init string to phone, this is a bunch of 0x55 characters.
369 Timing is empirical. I believe that we need/can do this for any
370 phone to get the UART synced */
371 for (count = 0; count < glink->InitLength; count++) {
373 device_write(&init_char, 1);
377 flink.i.State = FB3110_RX_Sync;
383 /* Any command we originate must have a unique SequenceNumber.
384 Observation to date suggests that these values startx at 0x10
385 and cycle up to 0x17 before repeating again. Perhaps more
386 accurately, the numbers cycle 0,1,2,3..7 with bit 4 of the byte
389 void FB3110_UpdateSequenceNumber(void)
391 flink.RequestSequenceNumber++;
393 if (flink.RequestSequenceNumber > 0x17 || flink.RequestSequenceNumber < 0x10) {
394 flink.RequestSequenceNumber = 0x10;