This commit was generated by cvs2svn to compensate for changes in r164,
[gnokii.git] / common / gsm-statemachine.c
1 /*
2
3   $Id$
4
5   G N O K I I
6
7   A Linux/Unix toolset and driver for Nokia mobile phones.
8
9   Copyright (C) 1999, 2000 Hugh Blemings & Pavel Janík ml.
10
11   Released under the terms of the GNU GPL, see file COPYING for more details.
12
13   $Log$
14   Revision 1.1.1.4  2002/04/03 00:07:57  short
15   Found in "gnokii-working" directory, some November-patches version
16
17   Revision 1.5  2001/09/09 21:45:49  machek
18   Cleanups from Ladislav Michl <ladis@psi.cz>:
19
20   *) do *not* internationalize debug messages
21
22   *) some whitespace fixes, do not use //
23
24   *) break is unneccessary after return
25
26   Revision 1.4  2001/07/27 00:02:20  pkot
27   Generic AT support for the new structure (Manfred Jonsson)
28
29   Revision 1.3  2001/06/10 11:26:56  machek
30   Warn if Link.Loop is not defined.
31
32   Revision 1.2  2001/05/07 14:01:51  machek
33   Warn when phone functions are missing, but do not segfault.
34
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
38
39
40 */
41
42 #include "gsm-common.h"
43 #include "gsm-statemachine.h"
44 #include "gsm-api.h"
45
46 GSM_Error SM_Initialise(GSM_Statemachine *state)
47 {
48         state->CurrentState=Initialised;
49         state->NumWaitingFor=0;
50         state->NumReceived=0; 
51         
52         return GE_NONE;
53 }
54
55 GSM_Error SM_SendMessage(GSM_Statemachine *state, u16 messagesize, u8 messagetype, void *message)
56 {
57         if (state->CurrentState!=Startup) {
58                 state->LastMsgSize=messagesize;
59                 state->LastMsgType=messagetype;
60                 state->LastMsg=message;
61                 state->CurrentState=MessageSent;
62
63                 /* FIXME - clear KeepAlive timer */
64                 return state->Link.SendMessage(messagesize, messagetype, message);
65         }
66         else return GE_NOTREADY;
67 }
68
69 GSM_State SM_Loop(GSM_Statemachine *state, int timeout)
70 {
71         struct timeval loop_timeout;
72         int i;
73
74         loop_timeout.tv_sec = 0;
75         loop_timeout.tv_usec = 100000;
76
77         if (!state->Link.Loop) {
78                 fprintf(stderr, "No Loop function. Aborting.\n");
79                 abort();
80         }
81         for (i = 0; i < timeout; i++) {
82                 state->Link.Loop(&loop_timeout);
83         }
84
85         /* FIXME - add calling a KeepAlive function here */
86
87         return state->CurrentState;
88 }
89
90 void SM_Reset(GSM_Statemachine *state)
91 {
92         /* Don't reset to initialised if we aren't! */
93         
94         if (state->CurrentState!=Startup) {
95                 state->CurrentState=Initialised;
96                 state->NumWaitingFor=0;
97                 state->NumReceived=0;       
98         }
99 }
100
101
102
103 void SM_IncomingFunction(GSM_Statemachine *state, u8 messagetype, void *message, u16 messagesize)
104 {
105         int c;
106         int temp=1;
107         GSM_Data emptydata;
108         GSM_Data *data=&emptydata;
109         GSM_Error res=GE_INTERNALERROR;
110         int waitingfor=-1;
111
112         GSM_DataClear(&emptydata);
113
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) {
118                                 data=state->Data[c];
119                                 waitingfor=c;
120                         }
121                        
122       
123         /* Pass up the message to the correct phone function, with data if necessary */
124         c=0;
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);
129                         temp=0;
130                 }
131                 c++;
132         }
133         if (temp != 0) {
134                 dprintf("Unknown Frame Type %02x\n\r", messagetype);
135                 state->Phone.DefaultFunction(messagetype, message, messagesize);
136
137                 return;
138         }
139
140         if (state->CurrentState==WaitingForResponse) {
141                 
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++;
146                 }
147                 
148                 /* Check if all waitingfors have been received */
149                 if (state->NumReceived==state->NumWaitingFor) {
150                         state->CurrentState=ResponseReceived;   
151                 }
152                 
153         }
154 }
155
156
157 /* This returns the error recorded from the phone function and indicates collection */
158
159 GSM_Error SM_GetError(GSM_Statemachine *state, unsigned char messagetype)
160 {
161         int c,d;
162         GSM_Error error=GE_NOTREADY;
163         
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];
172                                 }
173                                 state->NumReceived--;
174                                 state->NumWaitingFor--;
175                                 c--; /* For neatness continue in the correct place */
176                         }
177                 if (state->NumReceived==0) {
178                         state->NumWaitingFor=0;
179                         state->CurrentState=Initialised;
180                 }
181         }
182         
183         return error;
184 }
185
186
187
188 /* Indicate that the phone code is waiting for an response */
189 /* This does not actually wait! */
190
191 GSM_Error SM_WaitFor(GSM_Statemachine *state, GSM_Data *data, unsigned char messagetype)
192 {
193
194         /* If we've received a response, we have to call SM_GetError first */
195         if ((state->CurrentState==Startup) || (state->CurrentState==ResponseReceived)) 
196                 return GE_NOTREADY;
197         
198         if (state->NumWaitingFor==SM_MAXWAITINGFOR) return GE_NOTREADY;
199 ;
200         state->WaitingFor[state->NumWaitingFor]=messagetype;
201         state->Data[state->NumWaitingFor]=data;
202         state->NumWaitingFor++;
203         state->CurrentState=WaitingForResponse;
204
205         return GE_NONE;
206 }
207
208
209 /* This function is for convinience only */
210 /* It is called after SM_SendMessage and blocks until a response is received */
211
212 GSM_Error SM_Block(GSM_Statemachine *state, GSM_Data *data, int waitfor) 
213 {
214         int retry;
215         int timeout;
216         GSM_State s;
217         GSM_Error err;
218
219         for (retry=0; retry<3; retry++) {
220                 timeout=30;
221                 err=SM_WaitFor(state,data,waitfor);
222                 if (err!=GE_NONE) return err; 
223
224                 do {            /* ~3secs timeout */
225                         s=SM_Loop(state, 1);  /* Timeout=100ms */
226                         timeout--;
227                 } while ((timeout>0) && (s==WaitingForResponse));
228                 
229                 if (s==ResponseReceived) return SM_GetError(state, waitfor);
230
231                 dprintf("SM_Block Retry - %d\n\r", retry);
232                 SM_Reset(state);
233                 if (retry<2) SM_SendMessage(state, state->LastMsgSize, state->LastMsgType, state->LastMsg);
234         }
235
236         return GE_TIMEOUT;
237 }
238
239
240 /* Just to do things neatly */
241
242 GSM_Error SM_Functions(GSM_Operation op, GSM_Data *data, GSM_Statemachine *sm)
243 {
244 GSM_Error err;
245
246         if (!sm->Phone.Functions)
247                 err=GE_NOTIMPLEMENTED;
248         else
249                 err=sm->Phone.Functions(op, data, sm);
250         if (err==GE_NOTIMPLEMENTED)
251                 err=compat_Phone_Functions(op, data, sm);
252         return(err);
253 }