7 A Linux/Unix toolset and driver for Nokia mobile phones.
9 Copyright (C) 1999, 2000 Hugh Blemings & Pavel JanÃk ml.
11 Released under the terms of the GNU GPL, see file COPYING for more details.
14 Revision 1.1.1.1 2001/11/25 21:59:01 short
15 :pserver:cvs@pserver.samba.org:/cvsroot - gnokii - Sun Nov 25 22:56 CET 2001
17 Revision 1.7 2001/11/17 20:16:42 pkot
20 Revision 1.6 2001/11/08 16:49:19 pkot
23 Revision 1.5 2001/09/09 21:45:49 machek
24 Cleanups from Ladislav Michl <ladis@psi.cz>:
26 *) do *not* internationalize debug messages
28 *) some whitespace fixes, do not use //
30 *) break is unneccessary after return
32 Revision 1.4 2001/07/27 00:02:20 pkot
33 Generic AT support for the new structure (Manfred Jonsson)
35 Revision 1.3 2001/06/10 11:26:56 machek
36 Warn if Link.Loop is not defined.
38 Revision 1.2 2001/05/07 14:01:51 machek
39 Warn when phone functions are missing, but do not segfault.
41 Revision 1.1 2001/03/21 23:36:04 chris
42 Added the statemachine
43 This will break gnokii --identify and --monitor except for 6210/7110
48 #include "gsm-common.h"
49 #include "gsm-statemachine.h"
51 GSM_Error SM_Initialise(GSM_Statemachine *state)
53 state->CurrentState = Initialised;
54 state->NumWaitingFor = 0;
55 state->NumReceived = 0;
60 GSM_Error SM_SendMessage(GSM_Statemachine *state, u16 messagesize, u8 messagetype, void *message)
62 if (state->CurrentState != Startup) {
63 state->LastMsgSize = messagesize;
64 state->LastMsgType = messagetype;
65 state->LastMsg = message;
66 state->CurrentState = MessageSent;
68 /* FIXME - clear KeepAlive timer */
69 return state->Link.SendMessage(messagesize, messagetype, message);
71 else return GE_NOTREADY;
74 GSM_State SM_Loop(GSM_Statemachine *state, int timeout)
76 struct timeval loop_timeout;
79 loop_timeout.tv_sec = 0;
80 loop_timeout.tv_usec = 100000;
82 if (!state->Link.Loop) {
83 dprintf("No Loop function. Aborting.\n");
86 for (i = 0; i < timeout; i++) {
87 state->Link.Loop(&loop_timeout);
90 /* FIXME - add calling a KeepAlive function here */
91 return state->CurrentState;
94 void SM_Reset(GSM_Statemachine *state)
96 /* Don't reset to initialised if we aren't! */
97 if (state->CurrentState != Startup) {
98 state->CurrentState = Initialised;
99 state->NumWaitingFor = 0;
100 state->NumReceived = 0;
106 void SM_IncomingFunction(GSM_Statemachine *state, u8 messagetype, void *message, u16 messagesize)
111 GSM_Data *data = &emptydata;
112 GSM_Error res = GE_INTERNALERROR;
115 GSM_DataClear(&emptydata);
117 /* See if we need to pass the function the data struct */
118 if (state->CurrentState == WaitingForResponse)
119 for (c = 0; c < state->NumWaitingFor; c++)
120 if (state->WaitingFor[c] == messagetype) {
121 data = state->Data[c];
126 /* Pass up the message to the correct phone function, with data if necessary */
128 while (state->Phone.IncomingFunctions[c].Functions) {
129 if (state->Phone.IncomingFunctions[c].MessageType == messagetype) {
130 dprintf("Received message type %02x\n\r", messagetype);
131 res = state->Phone.IncomingFunctions[c].Functions(messagetype, message, messagesize, data);
137 dprintf("Unknown Frame Type %02x\n\r", messagetype);
138 state->Phone.DefaultFunction(messagetype, message, messagesize);
143 if (state->CurrentState == WaitingForResponse) {
144 /* Check if we were waiting for a response and we received it */
145 if (waitingfor != -1) {
146 state->ResponseError[waitingfor] = res;
147 state->NumReceived++;
150 /* Check if all waitingfors have been received */
151 if (state->NumReceived == state->NumWaitingFor) {
152 state->CurrentState = ResponseReceived;
159 /* This returns the error recorded from the phone function and indicates collection */
161 GSM_Error SM_GetError(GSM_Statemachine *state, unsigned char messagetype)
164 GSM_Error error = GE_NOTREADY;
166 if (state->CurrentState==ResponseReceived) {
167 for(c = 0; c < state->NumReceived; c++)
168 if (state->WaitingFor[c] == messagetype) {
169 error = state->ResponseError[c];
170 for(d = c + 1 ;d < state->NumReceived; d++){
171 state->ResponseError[d-1] = state->ResponseError[d];
172 state->WaitingFor[d-1] = state->WaitingFor[d];
173 state->Data[d-1] = state->Data[d];
175 state->NumReceived--;
176 state->NumWaitingFor--;
177 c--; /* For neatness continue in the correct place */
179 if (state->NumReceived == 0) {
180 state->NumWaitingFor = 0;
181 state->CurrentState = Initialised;
190 /* Indicate that the phone code is waiting for an response */
191 /* This does not actually wait! */
193 GSM_Error SM_WaitFor(GSM_Statemachine *state, GSM_Data *data, unsigned char messagetype)
196 /* If we've received a response, we have to call SM_GetError first */
197 if ((state->CurrentState == Startup) || (state->CurrentState == ResponseReceived))
200 if (state->NumWaitingFor == SM_MAXWAITINGFOR) return GE_NOTREADY;
201 state->WaitingFor[state->NumWaitingFor] = messagetype;
202 state->Data[state->NumWaitingFor] = data;
203 state->ResponseError[state->NumWaitingFor] = GE_BUSY;
204 state->NumWaitingFor++;
205 state->CurrentState = WaitingForResponse;
211 /* This function is for convinience only */
212 /* It is called after SM_SendMessage and blocks until a response is received */
214 GSM_Error SM_Block(GSM_Statemachine *state, GSM_Data *data, int waitfor)
221 for (retry = 0; retry < 3; retry++) {
223 err = SM_WaitFor(state, data, waitfor);
224 if (err != GE_NONE) return err;
226 do { /* ~3secs timeout */
227 s = SM_Loop(state, 1); /* Timeout=100ms */
229 } while ((timeout > 0) && (s == WaitingForResponse));
231 if (s == ResponseReceived) return SM_GetError(state, waitfor);
233 dprintf("SM_Block Retry - %d\n\r", retry);
235 if (retry<2) SM_SendMessage(state, state->LastMsgSize, state->LastMsgType, state->LastMsg);
242 /* Just to do things neatly */
244 GSM_Error SM_Functions(GSM_Operation op, GSM_Data *data, GSM_Statemachine *sm)
246 if (!sm->Phone.Functions) {
247 dprintf("Sorry, phone has not yet been converted to new style. Phone.Functions == NULL!\n");
248 return GE_INTERNALERROR;
250 return sm->Phone.Functions(op, data, sm);