1 /*
2
3 $Id$
4
5 G N O K I I
6
7 A Linux/Unix toolset and driver for the mobile phones.
8
9 This file is part of gnokii.
10
11 Gnokii is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2 of the License, or
14 (at your option) any later version.
15
16 Gnokii is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with gnokii; if not, write to the Free Software
23 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24
25 Copyright (C) 1999-2000 Hugh Blemings & Pavel Janik ml.
26 Copyright (C) 2001 Chris Kemp, Manfred Jonsson
27 Copyright (C) 2001-2002 Pavel Machek, Ladis Michl
28 Copyright (C) 2001-2003 Pawel Kot
29 Copyright (C) 2002-2004 BORBELY Zoltan
30 Copyright (C) 2003 Osma Suominen
31
32 */
33
34 #include "config.h"
35
36 #include "gnokii-internal.h"
37 #include "gnokii.h"
38 #include "misc.h"
39
sm_initialise(struct gn_statemachine * state)40 gn_error sm_initialise(struct gn_statemachine *state)
41 {
42 state->current_state = GN_SM_Initialised;
43 state->waiting_for_number = 0;
44 state->received_number = 0;
45
46 return GN_ERR_NONE;
47 }
48
sm_message_send(u16 messagesize,u8 messagetype,void * message,struct gn_statemachine * state)49 gn_error sm_message_send(u16 messagesize, u8 messagetype, void *message, struct gn_statemachine *state)
50 {
51 if (state->current_state != GN_SM_Startup) {
52 #ifdef DEBUG
53 dprintf("Message sent: ");
54 sm_message_dump(gn_log_debug, messagetype, message, messagesize);
55 #endif
56 state->last_msg_size = messagesize;
57 state->last_msg_type = messagetype;
58 state->last_msg = message;
59 state->current_state = GN_SM_MessageSent;
60
61 /* FIXME - clear KeepAlive timer */
62 return state->link.send_message(messagesize, messagetype, message, state);
63 }
64 else return GN_ERR_NOTREADY;
65 }
66
gn_sm_loop(int timeout,struct gn_statemachine * state)67 GNOKII_API gn_state gn_sm_loop(int timeout, struct gn_statemachine *state)
68 {
69 struct timeval loop_timeout;
70 int i;
71
72 if (!state->link.loop) {
73 dprintf("No Loop function. Aborting.\n");
74 abort();
75 }
76 for (i = 0; i < timeout; i++) {
77 /*
78 * Some select() implementation (e.g. Linux) will modify the
79 * timeval structure - bozo
80 */
81 loop_timeout.tv_sec = 0;
82 loop_timeout.tv_usec = 100000;
83
84 state->link.loop(&loop_timeout, state);
85 }
86
87 /* FIXME - add calling a KeepAlive function here */
88 return state->current_state;
89 }
90
sm_reset(struct gn_statemachine * state)91 void sm_reset(struct gn_statemachine *state)
92 {
93 /* Don't reset to initialised if we aren't! */
94 if (state->current_state != GN_SM_Startup) {
95 state->current_state = GN_SM_Initialised;
96 state->waiting_for_number = 0;
97 state->received_number = 0;
98 if (state->link.reset)
99 state->link.reset(state);
100 }
101 }
102
sm_incoming_function(u8 messagetype,void * message,u16 messagesize,struct gn_statemachine * state)103 void sm_incoming_function(u8 messagetype, void *message, u16 messagesize, struct gn_statemachine *state)
104 {
105 int c;
106 int temp = 1;
107 gn_data *data, *edata;
108 gn_error res = GN_ERR_INTERNALERROR;
109 int waitingfor = -1;
110
111 #ifdef DEBUG
112 dprintf("Message received: ");
113 sm_message_dump(gn_log_debug, messagetype, message, messagesize);
114 #endif
115 edata = (gn_data *)calloc(1, sizeof(gn_data));
116 data = edata;
117
118 /* See if we need to pass the function the data struct */
119 if (state->current_state == GN_SM_WaitingForResponse)
120 for (c = 0; c < state->waiting_for_number; c++)
121 if (state->waiting_for[c] == messagetype) {
122 data = state->data[c];
123 waitingfor = c;
124 }
125
126 /* Pass up the message to the correct phone function, with data if necessary */
127 c = 0;
128 while (state->driver.incoming_functions[c].functions) {
129 if (state->driver.incoming_functions[c].message_type == messagetype) {
130 dprintf("Received message type %02x\n", messagetype);
131 res = state->driver.incoming_functions[c].functions(messagetype, message, messagesize, data, state);
132 temp = 0;
133 break;
134 }
135 c++;
136 }
137 if (res == GN_ERR_UNSOLICITED) {
138 dprintf("Unsolicited frame, skipping...\n");
139 free(edata);
140 return;
141 } else if (res == GN_ERR_UNHANDLEDFRAME) {
142 sm_unhandled_frame_dump(messagetype, message, messagesize, state);
143 } else if (res == GN_ERR_WAITING) {
144 free(edata);
145 return;
146 }
147 if (temp != 0) {
148 dprintf("Unknown Frame Type %02x\n", messagetype);
149 state->driver.default_function(messagetype, message, messagesize, state);
150 free(edata);
151 return;
152 }
153
154 if (state->current_state == GN_SM_WaitingForResponse) {
155 /* Check if we were waiting for a response and we received it */
156 if (waitingfor != -1) {
157 state->response_error[waitingfor] = res;
158 state->received_number++;
159 }
160
161 /* Check if all waitingfors have been received */
162 if (state->received_number == state->waiting_for_number) {
163 state->current_state = GN_SM_ResponseReceived;
164 }
165 }
166 free(edata);
167 }
168
169 /* This returns the error recorded from the phone function and indicates collection */
sm_error_get(unsigned char messagetype,struct gn_statemachine * state)170 gn_error sm_error_get(unsigned char messagetype, struct gn_statemachine *state)
171 {
172 int c, d;
173 gn_error error = GN_ERR_NOTREADY;
174
175 switch (state->current_state) {
176 case GN_SM_ResponseReceived:
177 for (c = 0; c < state->received_number; c++)
178 if (state->waiting_for[c] == messagetype) {
179 error = state->response_error[c];
180 for (d = c + 1 ; d < state->received_number; d++) {
181 state->response_error[d-1] = state->response_error[d];
182 state->waiting_for[d-1] = state->waiting_for[d];
183 state->data[d-1] = state->data[d];
184 }
185 state->received_number--;
186 state->waiting_for_number--;
187 c--; /* For neatness continue in the correct place */
188 }
189 if (state->received_number == 0) {
190 state->waiting_for_number = 0;
191 state->current_state = GN_SM_Initialised;
192 }
193 break;
194 /* Here we are fine! */
195 case GN_SM_Initialised:
196 error = GN_ERR_NONE;
197 break;
198 default:
199 break;
200 }
201
202 return error;
203 }
204
205
206
207 /* Indicate that the phone code is waiting for a response */
208 /* This does not actually wait! */
sm_wait_for(unsigned char messagetype,gn_data * data,struct gn_statemachine * state)209 gn_error sm_wait_for(unsigned char messagetype, gn_data *data, struct gn_statemachine *state)
210 {
211 /* If we've received a response, we have to call SM_GetError first */
212 if ((state->current_state == GN_SM_Startup) || (state->current_state == GN_SM_ResponseReceived))
213 return GN_ERR_NOTREADY;
214
215 if (state->waiting_for_number == GN_SM_WAITINGFOR_MAX_NUMBER) return GN_ERR_NOTREADY;
216 state->waiting_for[state->waiting_for_number] = messagetype;
217 state->data[state->waiting_for_number] = data;
218 state->response_error[state->waiting_for_number] = GN_ERR_BUSY;
219 state->waiting_for_number++;
220
221 return GN_ERR_NONE;
222 }
223
sm_incoming_acknowledge(struct gn_statemachine * state)224 void sm_incoming_acknowledge(struct gn_statemachine *state)
225 {
226 if (state->current_state == GN_SM_MessageSent)
227 state->current_state = GN_SM_WaitingForResponse;
228 }
229
230
231 /* This function is for convinience only.
232 It is called after SM_SendMessage and blocks until a response is received.
233 t is in tenths of second.
234 */
__sm_block_timeout(int waitfor,int t,gn_data * data,struct gn_statemachine * state)235 static gn_error __sm_block_timeout(int waitfor, int t, gn_data *data, struct gn_statemachine *state)
236 {
237 int retry;
238 gn_state s;
239 gn_error err;
240 struct timeval now, next, timeout;
241
242 s = state->current_state;
243 timeout.tv_sec = 3;
244 timeout.tv_usec = 0;
245 gettimeofday(&now, NULL);
246 for (retry = 0; retry < 2; retry++) {
247 err = sm_wait_for(waitfor, data, state);
248 if (err != GN_ERR_NONE) return err;
249
250 timeradd(&now, &timeout, &next);
251 do {
252 s = gn_sm_loop(1, state); /* Timeout=100ms */
253 gettimeofday(&now, NULL);
254 } while (timercmp(&next, &now, >) && (s == GN_SM_MessageSent));
255 if (s == GN_SM_WaitingForResponse || s == GN_SM_ResponseReceived) break;
256
257 if (state->config.sm_retry) {
258 dprintf("SM_Block Retry - %d\n", retry);
259 sm_reset(state);
260 sm_message_send(state->last_msg_size, state->last_msg_type, state->last_msg, state);
261 } else {
262 /* If we don't want retry, we should exit the loop */
263 dprintf("SM_Block: exiting the retry loop\n");
264 break;
265 }
266 }
267
268 if (s == GN_SM_ResponseReceived)
269 return sm_error_get(waitfor, state);
270
271 timeout.tv_sec = t / 10;
272 timeout.tv_usec = (t % 10) * 100000;
273 timeradd(&now, &timeout, &next);
274 do {
275 s = gn_sm_loop(1, state); /* Timeout=100ms */
276 gettimeofday(&now, NULL);
277 } while (timercmp(&next, &now, >) && (s != GN_SM_ResponseReceived));
278
279 if (s == GN_SM_ResponseReceived)
280 return sm_error_get(waitfor, state);
281
282 sm_reset(state);
283
284 return GN_ERR_TIMEOUT;
285 }
286
sm_block_timeout(int waitfor,int t,gn_data * data,struct gn_statemachine * state)287 gn_error sm_block_timeout(int waitfor, int t, gn_data *data, struct gn_statemachine *state)
288 {
289 int retry;
290 gn_error err;
291
292 for (retry = 0; retry < 3; retry++) {
293 err = __sm_block_timeout(waitfor, t, data, state);
294 if (err == GN_ERR_NONE || err != GN_ERR_TIMEOUT)
295 return err;
296 if (retry < 2) {
297 sm_message_send(state->last_msg_size, state->last_msg_type, state->last_msg, state);
298 }
299 }
300 return GN_ERR_TIMEOUT;
301 }
302
sm_block(int waitfor,gn_data * data,struct gn_statemachine * state)303 gn_error sm_block(int waitfor, gn_data *data, struct gn_statemachine *state)
304 {
305 return sm_block_timeout(waitfor, 40, data, state);
306 }
307
308 /* This function is equal to sm_block_timeout except it does not retry the message */
sm_block_no_retry_timeout(int waitfor,int t,gn_data * data,struct gn_statemachine * state)309 gn_error sm_block_no_retry_timeout(int waitfor, int t, gn_data *data, struct gn_statemachine *state)
310 {
311 return __sm_block_timeout(waitfor, t, data, state);
312 }
313
314 /* This function is equal to sm_block except it does not retry the message */
sm_block_no_retry(int waitfor,gn_data * data,struct gn_statemachine * state)315 gn_error sm_block_no_retry(int waitfor, gn_data *data, struct gn_statemachine *state)
316 {
317 return sm_block_no_retry_timeout(waitfor, 100, data, state);
318 }
319
320 /* Block waiting for an ack, don't wait for a reply message of any sort */
sm_block_ack(struct gn_statemachine * state)321 gn_error sm_block_ack(struct gn_statemachine *state)
322 {
323 int retry;
324 gn_state s;
325 gn_error err;
326 struct timeval now, next, timeout;
327
328 s = state->current_state;
329 timeout.tv_sec = 3;
330 timeout.tv_usec = 0;
331 gettimeofday(&now, NULL);
332 for (retry = 0; retry < 2; retry++) {
333 timeradd(&now, &timeout, &next);
334 do {
335 s = gn_sm_loop(1, state); /* Timeout=100ms */
336 gettimeofday(&now, NULL);
337 } while (timercmp(&next, &now, >) && (s == GN_SM_MessageSent));
338
339 if (s == GN_SM_WaitingForResponse || s == GN_SM_ResponseReceived)
340 return GN_ERR_NONE;
341
342 dprintf("sm_block_ack Retry - %d\n", retry);
343 sm_reset(state);
344 err = sm_message_send(state->last_msg_size, state->last_msg_type, state->last_msg, state);
345 if (err != GN_ERR_NONE) return err;
346 }
347
348 sm_reset(state);
349
350 return GN_ERR_TIMEOUT;
351 }
352
353 /* Just to do things neatly */
gn_sm_functions(gn_operation op,gn_data * data,struct gn_statemachine * sm)354 GNOKII_API gn_error gn_sm_functions(gn_operation op, gn_data *data, struct gn_statemachine *sm)
355 {
356 if (!sm->driver.functions) {
357 dprintf("Sorry, gnokii internal structures were not correctly initialized (op == %d)\n", op);
358 return GN_ERR_INTERNALERROR;
359 }
360 return sm->driver.functions(op, data, sm);
361 }
362
363 /* Dumps a message */
sm_message_dump(gn_log_func_t lfunc,int messagetype,unsigned char * message,int messagesize)364 void sm_message_dump(gn_log_func_t lfunc, int messagetype, unsigned char *message, int messagesize)
365 {
366 int i;
367 char buf[17];
368
369 buf[16] = 0;
370
371 lfunc("0x%02x / 0x%04x", messagetype, messagesize);
372
373 for (i = 0; i < messagesize; i++) {
374 if (i % 16 == 0) {
375 if (i != 0) lfunc("| %s", buf);
376 lfunc("\n");
377 memset(buf, ' ', 16);
378 }
379 lfunc("%02x ", message[i]);
380 if (isprint(message[i])) buf[i % 16] = message[i];
381 }
382
383 if (i != 0) lfunc("%*s| %s", i % 16 ? 3 * (16 - i % 16) : 0, "", buf);
384 lfunc("\n");
385 }
386
387 /* Prints a warning message about unhandled frames */
sm_unhandled_frame_dump(int messagetype,unsigned char * message,int messagesize,struct gn_statemachine * state)388 void sm_unhandled_frame_dump(int messagetype, unsigned char *message, int messagesize, struct gn_statemachine *state)
389 {
390 dump(_("UNHANDLED FRAME RECEIVED\nrequest: "));
391 sm_message_dump(gn_elog_write, state->last_msg_type, state->last_msg, state->last_msg_size);
392
393 dump(_("reply: "));
394 sm_message_dump(gn_elog_write, messagetype, message, messagesize);
395
396 dump(_("Please read Docs/Bugs and send a bug report!\n"));
397 }
398