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.4 2002/04/03 00:07:57 short
15 Found in "gnokii-working" directory, some November-patches version
17 Revision 1.5 2001/09/09 21:45:49 machek
18 Cleanups from Ladislav Michl <ladis@psi.cz>:
20 *) do *not* internationalize debug messages
22 *) some whitespace fixes, do not use //
24 *) break is unneccessary after return
26 Revision 1.4 2001/07/27 00:02:20 pkot
27 Generic AT support for the new structure (Manfred Jonsson)
29 Revision 1.3 2001/06/10 11:26:56 machek
30 Warn if Link.Loop is not defined.
32 Revision 1.2 2001/05/07 14:01:51 machek
33 Warn when phone functions are missing, but do not segfault.
35 Revision 1.1 2001/03/21 23:36:04 chris
36 Added the statemachine
37 This will break gnokii --identify and --monitor except for 6210/7110
42 #include "gsm-common.h"
43 #include "gsm-statemachine.h"
46 GSM_Error SM_Initialise(GSM_Statemachine *state)
48 state->CurrentState=Initialised;
49 state->NumWaitingFor=0;
55 GSM_Error SM_SendMessage(GSM_Statemachine *state, u16 messagesize, u8 messagetype, void *message)
57 if (state->CurrentState!=Startup) {
58 state->LastMsgSize=messagesize;
59 state->LastMsgType=messagetype;
60 state->LastMsg=message;
61 state->CurrentState=MessageSent;
63 /* FIXME - clear KeepAlive timer */
64 return state->Link.SendMessage(messagesize, messagetype, message);
66 else return GE_NOTREADY;
69 GSM_State SM_Loop(GSM_Statemachine *state, int timeout)
71 struct timeval loop_timeout;
74 loop_timeout.tv_sec = 0;
75 loop_timeout.tv_usec = 100000;
77 if (!state->Link.Loop) {
78 fprintf(stderr, "No Loop function. Aborting.\n");
81 for (i = 0; i < timeout; i++) {
82 state->Link.Loop(&loop_timeout);
85 /* FIXME - add calling a KeepAlive function here */
87 return state->CurrentState;
90 void SM_Reset(GSM_Statemachine *state)
92 /* Don't reset to initialised if we aren't! */
94 if (state->CurrentState!=Startup) {
95 state->CurrentState=Initialised;
96 state->NumWaitingFor=0;
103 void SM_IncomingFunction(GSM_Statemachine *state, u8 messagetype, void *message, u16 messagesize)
108 GSM_Data *data=&emptydata;
109 GSM_Error res=GE_INTERNALERROR;
112 GSM_DataClear(&emptydata);
114 /* See if we need to pass the function the data struct */
115 if (state->CurrentState==WaitingForResponse)
116 for (c=0; c<state->NumWaitingFor; c++)
117 if (state->WaitingFor[c]==messagetype) {
123 /* Pass up the message to the correct phone function, with data if necessary */
125 while (state->Phone.IncomingFunctions[c].Functions) {
126 if (state->Phone.IncomingFunctions[c].MessageType == messagetype) {
127 dprintf("Received message type %02x\n\r", messagetype);
128 res=state->Phone.IncomingFunctions[c].Functions(messagetype, message, messagesize, data);
134 dprintf("Unknown Frame Type %02x\n\r", messagetype);
135 state->Phone.DefaultFunction(messagetype, message, messagesize);
140 if (state->CurrentState==WaitingForResponse) {
142 /* Check if we were waiting for a response and we received it */
143 if (waitingfor!=-1) {
144 state->ResponseError[waitingfor]=res;
145 state->NumReceived++;
148 /* Check if all waitingfors have been received */
149 if (state->NumReceived==state->NumWaitingFor) {
150 state->CurrentState=ResponseReceived;
157 /* This returns the error recorded from the phone function and indicates collection */
159 GSM_Error SM_GetError(GSM_Statemachine *state, unsigned char messagetype)
162 GSM_Error error=GE_NOTREADY;
164 if (state->CurrentState==ResponseReceived) {
165 for(c=0; c < state->NumReceived; c++)
166 if (state->WaitingFor[c]==messagetype) {
167 error=state->ResponseError[c];
168 for( d=c+1 ; d < state->NumReceived; d++){
169 state->ResponseError[d-1]=state->ResponseError[d];
170 state->WaitingFor[d-1]=state->WaitingFor[d];
171 state->Data[d-1]=state->Data[d];
173 state->NumReceived--;
174 state->NumWaitingFor--;
175 c--; /* For neatness continue in the correct place */
177 if (state->NumReceived==0) {
178 state->NumWaitingFor=0;
179 state->CurrentState=Initialised;
188 /* Indicate that the phone code is waiting for an response */
189 /* This does not actually wait! */
191 GSM_Error SM_WaitFor(GSM_Statemachine *state, GSM_Data *data, unsigned char messagetype)
194 /* If we've received a response, we have to call SM_GetError first */
195 if ((state->CurrentState==Startup) || (state->CurrentState==ResponseReceived))
198 if (state->NumWaitingFor==SM_MAXWAITINGFOR) return GE_NOTREADY;
200 state->WaitingFor[state->NumWaitingFor]=messagetype;
201 state->Data[state->NumWaitingFor]=data;
202 state->NumWaitingFor++;
203 state->CurrentState=WaitingForResponse;
209 /* This function is for convinience only */
210 /* It is called after SM_SendMessage and blocks until a response is received */
212 GSM_Error SM_Block(GSM_Statemachine *state, GSM_Data *data, int waitfor)
219 for (retry=0; retry<3; retry++) {
221 err=SM_WaitFor(state,data,waitfor);
222 if (err!=GE_NONE) return err;
224 do { /* ~3secs timeout */
225 s=SM_Loop(state, 1); /* Timeout=100ms */
227 } while ((timeout>0) && (s==WaitingForResponse));
229 if (s==ResponseReceived) return SM_GetError(state, waitfor);
231 dprintf("SM_Block Retry - %d\n\r", retry);
233 if (retry<2) SM_SendMessage(state, state->LastMsgSize, state->LastMsgType, state->LastMsg);
240 /* Just to do things neatly */
242 GSM_Error SM_Functions(GSM_Operation op, GSM_Data *data, GSM_Statemachine *sm)
246 if (!sm->Phone.Functions)
247 err=GE_NOTIMPLEMENTED;
249 err=sm->Phone.Functions(op, data, sm);
250 if (err==GE_NOTIMPLEMENTED)
251 err=compat_Phone_Functions(op, data, sm);