gnokii-users
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

3110 statemachine handling (patch)


From: Osma Suominen
Subject: 3110 statemachine handling (patch)
Date: Mon, 17 Feb 2003 17:56:05 +0200 (EET)

Hello,

continuing with my headaches with the 3110 and statemachine code, I
finally decided to resolve the problems by writing two (3 actually) new
functions similar to but still different from the sm_block family.
I placed them now in nk3110.c but they could as well be placed in
gsm-statemachine.c depending on the viewpoint. This has started to look
very much like private problems of the 3110 protocol so that's why I'm
placing these functions together with the 3110 code.

One function expects a message, without making the assumption that it is
a response to a recently sent message (this assumption is made by
sm_block and friends). This is used in the situation where the phone
responds to a GetSMS message with a header message immediately followed
by one or more data messages, with no separate request for the data.

Another new function, in two versions, is the disputed block_many that I
decided to write on my own instead of tweaking sm_block, because
although the two functions are very similar in purpose, the code
differences are still substantial. (The statemachine is built with the
assumption that all messages on the "waiting for" list are eventually
received, which is not the case when there are alternative message types
to indicate either success or failure.)

The patch also changes the GetSMS and DeleteSMS operations for the 3110
to use the new functions. Other operations will be converted soon.

Finally, the patch reverts my last change to __sm_block_timeout(), which
was a desperate attempt at clearing its assumption that it is called
immediately after sm_message_send. That approach didn't work too well
but it took a while for me to figure out.

I'm sorry that this patch contains so many different things in one heap
but they are all closely related to each other. If you disagree with the
concepts just reject the whole patch, state what the problem is and I'll
then rework the code.

-Osma

--- common/gsm-statemachine.c   16 Feb 2003 23:53:10 -0000      1.42
+++ common/gsm-statemachine.c   17 Feb 2003 15:35:42 -0000
@@ -231,7 +231,7 @@
                do {
                        s = gn_sm_loop(1, state);  /* Timeout=100ms */
                        gettimeofday(&now, NULL);
-               } while (timercmp(&next, &now, >) && (s == GN_SM_MessageSent || 
s == GN_SM_Initialised));
+               } while (timercmp(&next, &now, >) && (s == GN_SM_MessageSent));

                if (s == GN_SM_WaitingForResponse || s == 
GN_SM_ResponseReceived) break;

--- common/phones/nk3110.c      16 Feb 2003 23:56:46 -0000      1.30
+++ common/phones/nk3110.c      17 Feb 2003 15:35:42 -0000
@@ -93,6 +93,9 @@

 static int sms_header_encode(gn_data *data, struct gn_statemachine *state, 
unsigned char *req, int ulength, bool save_sms);
 static int get_memory_type(gn_memory_type memory_type);
+static gn_error expect_message(int waitfor, gn_data *data, struct 
gn_statemachine *state);
+static gn_error block_many_timeout(int waitfor[], int waitfor_length, int 
*response, int t, gn_data *data, struct gn_statemachine *state);
+static gn_error block_many(int waitfor[], int waitfor_length, int *response, 
gn_data *data, struct gn_statemachine *state);

 static gn_incoming_function_type incoming_functions[] = {
        { 0x0a, P3110_IncomingNothing },
@@ -321,9 +324,9 @@

 static gn_error P3110_GetSMSMessage(gn_data *data, struct gn_statemachine 
*state)
 {
-       int timeout, c, memory_type;
-       u8 response = 0, request[2];
-       gn_error error = GN_ERR_INTERNALERROR;
+       int memory_type, response = 0, waitfor[] = { 0x2c, 0x2d };
+       unsigned char request[2];
+       gn_error error;

        dprintf("Getting SMS message...\n");

@@ -343,45 +346,23 @@
           for valid locations, 0x2d for empty ones. */

        if (sm_message_send(2, 0x25, request, state) != GN_ERR_NONE) return 
GN_ERR_NOTREADY;
-       sm_wait_for(0x2d, data, state);
-       sm_wait_for(0x2c, data, state);
-
-       timeout = 30; /* ~3secs timeout */
-
-       do {
-               gn_sm_loop(1, state);
-               timeout--;
-       } while ((timeout > 0) && state->received_number == 0);

-       /* timeout */
-       if (state->received_number == 0) return GN_ERR_TIMEOUT;
-
-       /* find response in state machine */
-       for (c = 0; c < state->waiting_for_number; c++) {
-               if (state->ResponseError[c] != GN_ERR_BUSY) {
-                       response = state->waiting_for[c];
-                       error = state->ResponseError[c];
-               }
-       }
+       error = block_many(waitfor, 2, &response, data, state);
+       if (error == GN_ERR_TIMEOUT) return error;

-       /* if (!data->raw_data) return GN_ERR_INTERNALERROR; */
-
-       /* reset state machine */
-       sm_reset(state);
-
-       /* process response */
        switch (response) {
        case 0x2c:
                if (error != GN_ERR_NONE) return error;
-
-               /* Block for subsequent content frames... */
                do {
                        dprintf("Waiting for content frames...\n");
-                       sm_block(0x27, data, state);
+                       error = expect_message(0x27, data, state);
+                       if (error != GN_ERR_NONE) return error;
                } while (DRVINSTANCE(state)->user_data_count < 
data->raw_sms->length);

+               /* the message has been successfully retrieved! */
                return GN_ERR_NONE;
        case 0x2d:
+               /* the incoming functions report success or failure */
                return error;
        default:
                return GN_ERR_INTERNALERROR;
@@ -391,8 +372,8 @@

 static gn_error P3110_DeleteSMSMessage(gn_data *data, struct gn_statemachine 
*state)
 {
-       int timeout, c, memory_type;
-       u8 response = 0, request[2];
+       int memory_type, response, waitfor[] = { 0x2e, 0x2f };
+       unsigned char request[2];
        gn_error error = GN_ERR_INTERNALERROR;

        dprintf("Deleting SMS message...\n");
@@ -411,34 +392,13 @@
           valid 0x2e is still returned. */
        if (sm_message_send(2, 0x26, request, state) != GN_ERR_NONE) return 
GN_ERR_NOTREADY;

-       sm_wait_for(0x2e, data, state);
-       sm_wait_for(0x2f, data, state);
-
-       timeout = 30; /* ~3secs timeout */
-
-       do {
-               gn_sm_loop(1, state);
-               timeout--;
-       } while ((timeout > 0) && state->received_number == 0);
-
-       /* timeout */
-       if (state->received_number == 0) return GN_ERR_TIMEOUT;
-
-       /* find response in state machine */
-       for (c = 0; c < state->waiting_for_number; c++) {
-               if (state->ResponseError[c] != GN_ERR_BUSY) {
-                       response = state->waiting_for[c];
-                       error = state->ResponseError[c];
-               }
-       }
-
-       /* reset state machine */
-       sm_reset(state);
+       error = block_many(waitfor, 2, &response, data, state);
+       if (error == GN_ERR_TIMEOUT) return error;

-       /* process response */
        switch (response) {
        case 0x2e:
        case 0x2f:
+               /* the incoming functions report success or failure */
                return error;
        default:
                return GN_ERR_INTERNALERROR;
@@ -878,6 +838,7 @@

 static gn_error P3110_IncomingSMSError(int messagetype, unsigned char 
*message, int length, gn_data *data, struct gn_statemachine *state)
 {
+       dprintf("message[2]: %02x\n", message[2]);
        if (message[2] == 0x74)
                return GN_ERR_INVALIDLOCATION;
        else
@@ -1225,4 +1186,100 @@
        default:        result = 0; break;      /* error code */
        }
        return result;
+}
+
+/* The following are convenience functions to handle the statemachine on a
+ * higher level, used in situations where the sm_block family of functions
+ * is not suitable. */
+
+
+/* Expect some message type to appear, without having sent anything.
+ * If the specified message type does not appear within 3 seconds, return
+ * a timeout error. If it comes it will be handled correctly. */
+
+static gn_error expect_message(int waitfor, gn_data *data, struct 
gn_statemachine *state)
+{
+       gn_error err;
+       gn_state s;
+       struct timeval now, next, timeout;
+
+       timeout.tv_sec = 3;
+       timeout.tv_usec = 0;
+       gettimeofday(&now, NULL);
+
+       sm_reset(state);
+
+       err = sm_wait_for(waitfor, data, state);
+       if (err != GN_ERR_NONE) return err;
+
+       timeradd(&now, &timeout, &next);
+       do {
+               s = gn_sm_loop(1, state);
+               gettimeofday(&now, NULL);
+       } while(timercmp(&next, &now, >) && (s != GN_SM_ResponseReceived));
+
+       if (s != GN_SM_ResponseReceived) return GN_ERR_TIMEOUT;
+
+       return sm_error_get(waitfor, state);
+}
+
+/* Wait for any one of several possible message types to appear. The types
+ * are given in the waitfor[] array with the array length given in
+ * waitfor_length. The received response (message type) is saved into the
+ * location pointed to by response, unless it is NULL. If nothing appears
+ * within (t / 10) seconds, returns a timeout error. */
+
+static gn_error block_many_timeout(int waitfor[], int waitfor_length, int 
*response, int t, gn_data *data, struct gn_statemachine *state)
+{
+       int retry, i;
+       gn_error err;
+       struct timeval now, next, timeout;
+
+       timeout.tv_sec =  t / 10;
+       timeout.tv_usec = (t % 10) * 100000;
+       gettimeofday(&now, NULL);
+
+       for(retry = 0; retry < 3; retry++) {
+               for(i = 0; i < waitfor_length; i++) {
+                       err = sm_wait_for(waitfor[i], data, state);
+                       dprintf("sm_wait_for response: %d\n", err);
+                       if (err != GN_ERR_NONE) return err;
+               }
+
+               timeradd(&now, &timeout, &next);
+               do {
+                       gn_sm_loop(1, state);
+                       gettimeofday(&now, NULL);
+               } while(timercmp(&next, &now, >) && (state->received_number == 
0));
+
+               if (state->received_number > 0 || retry == 2) break;
+
+               dprintf("expect_message_many retry - %d\n", retry);
+               sm_reset(state);
+               sm_message_send(state->last_msg_size, state->last_msg_type, 
state->last_msg, state);
+       }
+
+       if (state->received_number == 0) return GN_ERR_TIMEOUT;
+
+       /* Since the state machine still waits for the other message, the
+        * result has to be dug up from its internals. sm_error_get() is
+        * useless here. */
+
+       for (i = 0; i < state->waiting_for_number; i++) {
+               if (state->ResponseError[i] != GN_ERR_BUSY) {
+                       if(response != NULL)
+                               *response = state->waiting_for[i];
+                       return state->ResponseError[i];
+               }
+       }
+
+       dprintf("End of expect_message_many reached - should not happen!\n");
+       return GN_ERR_INTERNALERROR;
+}
+
+/* Same as block_many_timeout but with a default timeout of 3 seconds */
+
+static gn_error block_many(int waitfor[], int waitfor_length, int *response, 
gn_data *data, struct gn_statemachine *state)
+{
+       return block_many_timeout(waitfor, waitfor_length, response, 30, data, 
state);
 }


-- 
*** Osma Suominen *** address@hidden *** http://www.iki.fi/ozone/ ***




reply via email to

[Prev in Thread] Current Thread [Next in Thread]