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