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.
15 #include "gsm-common.h"
16 #include "gsm-statemachine.h"
18 GSM_Error SM_Initialise(GSM_Statemachine *state)
20 state->CurrentState = Initialised;
21 state->NumWaitingFor = 0;
22 state->NumReceived = 0;
27 GSM_Error SM_SendMessage(GSM_Statemachine *state, u16 messagesize, u8 messagetype, void *message)
29 if (state->CurrentState != Startup) {
30 state->LastMsgSize = messagesize;
31 state->LastMsgType = messagetype;
32 state->LastMsg = message;
33 state->CurrentState = MessageSent;
35 /* FIXME - clear KeepAlive timer */
36 return state->Link.SendMessage(messagesize, messagetype, message);
38 else return GE_NOTREADY;
41 GSM_State SM_Loop(GSM_Statemachine *state, int timeout)
43 struct timeval loop_timeout;
46 loop_timeout.tv_sec = 0;
47 loop_timeout.tv_usec = 100000;
49 if (!state->Link.Loop) {
50 dprintf("No Loop function. Aborting.\n");
53 for (i = 0; i < timeout; i++) {
54 state->Link.Loop(&loop_timeout);
57 /* FIXME - add calling a KeepAlive function here */
58 return state->CurrentState;
61 void SM_Reset(GSM_Statemachine *state)
63 /* Don't reset to initialised if we aren't! */
64 if (state->CurrentState != Startup) {
65 state->CurrentState = Initialised;
66 state->NumWaitingFor = 0;
67 state->NumReceived = 0;
73 void SM_IncomingFunction(GSM_Statemachine *state, u8 messagetype, void *message, u16 messagesize)
78 GSM_Data *data = &emptydata;
79 GSM_Error res = GE_INTERNALERROR;
82 GSM_DataClear(&emptydata);
84 /* See if we need to pass the function the data struct */
85 if (state->CurrentState == WaitingForResponse)
86 for (c = 0; c < state->NumWaitingFor; c++)
87 if (state->WaitingFor[c] == messagetype) {
88 data = state->Data[c];
93 /* Pass up the message to the correct phone function, with data if necessary */
95 while (state->Phone.IncomingFunctions[c].Functions) {
96 if (state->Phone.IncomingFunctions[c].MessageType == messagetype) {
97 dprintf("Received message type %02x\n\r", messagetype);
98 res = state->Phone.IncomingFunctions[c].Functions(messagetype, message, messagesize, data);
104 dprintf("Unknown Frame Type %02x\n\r", messagetype);
105 state->Phone.DefaultFunction(messagetype, message, messagesize);
110 if (state->CurrentState == WaitingForResponse) {
111 /* Check if we were waiting for a response and we received it */
112 if (waitingfor != -1) {
113 state->ResponseError[waitingfor] = res;
114 state->NumReceived++;
117 /* Check if all waitingfors have been received */
118 if (state->NumReceived == state->NumWaitingFor) {
119 state->CurrentState = ResponseReceived;
126 /* This returns the error recorded from the phone function and indicates collection */
128 GSM_Error SM_GetError(GSM_Statemachine *state, unsigned char messagetype)
131 GSM_Error error = GE_NOTREADY;
133 if (state->CurrentState==ResponseReceived) {
134 for(c = 0; c < state->NumReceived; c++)
135 if (state->WaitingFor[c] == messagetype) {
136 error = state->ResponseError[c];
137 for(d = c + 1 ;d < state->NumReceived; d++){
138 state->ResponseError[d-1] = state->ResponseError[d];
139 state->WaitingFor[d-1] = state->WaitingFor[d];
140 state->Data[d-1] = state->Data[d];
142 state->NumReceived--;
143 state->NumWaitingFor--;
144 c--; /* For neatness continue in the correct place */
146 if (state->NumReceived == 0) {
147 state->NumWaitingFor = 0;
148 state->CurrentState = Initialised;
157 /* Indicate that the phone code is waiting for an response */
158 /* This does not actually wait! */
160 GSM_Error SM_WaitFor(GSM_Statemachine *state, GSM_Data *data, unsigned char messagetype)
163 /* If we've received a response, we have to call SM_GetError first */
164 if ((state->CurrentState == Startup) || (state->CurrentState == ResponseReceived))
167 if (state->NumWaitingFor == SM_MAXWAITINGFOR) return GE_NOTREADY;
168 state->WaitingFor[state->NumWaitingFor] = messagetype;
169 state->Data[state->NumWaitingFor] = data;
170 state->ResponseError[state->NumWaitingFor] = GE_BUSY;
171 state->NumWaitingFor++;
172 state->CurrentState = WaitingForResponse;
178 /* This function is for convinience only */
179 /* It is called after SM_SendMessage and blocks until a response is received */
181 GSM_Error SM_Block(GSM_Statemachine *state, GSM_Data *data, int waitfor)
188 for (retry = 0; retry < 3; retry++) {
190 err = SM_WaitFor(state, data, waitfor);
191 if (err != GE_NONE) return err;
193 do { /* ~3secs timeout */
194 s = SM_Loop(state, 1); /* Timeout=100ms */
196 } while ((timeout > 0) && (s == WaitingForResponse));
198 if (s == ResponseReceived) return SM_GetError(state, waitfor);
200 dprintf("SM_Block Retry - %d\n\r", retry);
202 if (retry < 2) SM_SendMessage(state, state->LastMsgSize, state->LastMsgType, state->LastMsg);
209 /* Just to do things neatly */
211 GSM_Error SM_Functions(GSM_Operation op, GSM_Data *data, GSM_Statemachine *sm)
213 if (!sm->Phone.Functions) {
214 dprintf("Sorry, phone has not yet been converted to new style. Phone.Functions == NULL!\n");
215 return GE_INTERNALERROR;
217 return sm->Phone.Functions(op, data, sm);