gnokii-users
[Top][All Lists]
Advanced

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

3110 SMS rework (big patch)


From: Osma Suominen
Subject: 3110 SMS rework (big patch)
Date: Wed, 19 Feb 2003 20:58:41 +0200 (EET)

Hello again,

My recent statmachine stuff has not yet gone into CVS but I'm still
continuing with my 3110 work assuming it gets accepted in one way or
another. (putting the new functions in gsm-statemachine.c and/or
renaming them is fine with me)

I did some reworking of 3110 SMS handling. Unfortunately it's quite a
big patch - the SMS code was still pretty rough so rather than target
small pieces at a time I ended up rewriting large sections of it.

There's also a bugfix for the block_many_timeout() function that
appeared in my previous patch. The function didn't clean up afterwards
properly.

I've fixed the issue of SMS data encoding by doing encoding/decoding
back and forth using the existing functions in gsm-encoding.c. The
problem (for those unfamiliar with the issue) is that newer phones want
their data in 7bit packed format whereas the 3110 expects plain ASCII
(ISO Latin-1 actually I think, I haven't investigated thoroughly, but I
should do it sometime). Since the internal format of gnokii is the 7bit
packed format (in the raw_sms data structure) there is a problem. So
I've added two functions to encode/decode the data so that it's suitable
for the 3110. These may not be very useful right now but the situation
might change later - for example, what if gnokii is fed something like
UCS-8 data that (luckily) only contains valid GSM default alphabet
characters? Then gnokii has to do conversion from UCS-8 to 7bit and then
the driver to Latin-1. Just copying over the data won't work anymore,
and it is good to have the phone driver translate between phone format
(Latin-1) and gnokii internal format (7bit). Otherwise the gnokii
internals could get messy.

I've added support for most of the SMS flags like delivery report
requesting and also done message validity properly. Whether all of this
works is still somewhat unclear - I'm not even sure what all the flags
are used for and how to test whether they work or not.

After these modifications I was able to send 8 SMS's in a row without
problms, but then the phone again started giving 0x65 0x15 error
messages, which seem to be some kind of general errors (you get the same
error for e.g. a malformed recipient number). So SMS sending is still
not terribly reliable on the 3110 but at least it has gotten better.
Also the driver should no longer segfault in some "special" situations
(don't rely on that, though).

Again the usual disclaimer, if you think there's something suspicious
feel free to reject this patch and I'll rework it.

The next thing will probably be phonebook handling, then a review of the
remaining old code including data calls...

-Osma

Index: nk3110.h
===================================================================
RCS file: /cvsroot/gnokii/gnokii/include/phones/nk3110.h,v
retrieving revision 1.7
diff -u -r1.7 nk3110.h
--- nk3110.h    14 Feb 2003 23:54:12 -0000      1.7
+++ nk3110.h    19 Feb 2003 18:37:03 -0000
@@ -44,6 +44,7 @@

 typedef struct {
        bool sim_available;
+       unsigned char user_data[GN_SMS_LONG_MAX_LENGTH];
        int user_data_count;
 } nk3110_driver_instance;


--- common/phones/nk3110-sm.c   Wed Feb 19 18:47:13 2003
+++ common/phones/nk3110.c      Wed Feb 19 20:32:58 2003
@@ -92,6 +92,8 @@
 static gn_error P3110_IncomingPhoneInfo(int messagetype, unsigned char 
*buffer, int length, gn_data *data, struct gn_statemachine *state);

 static int sms_header_encode(gn_data *data, struct gn_statemachine *state, 
unsigned char *req, int ulength, bool save_sms);
+static int sms_data_encode(int in_length, int out_length, unsigned char 
*input, unsigned char *output, unsigned int dcs);
+static int sms_data_decode(int in_length, unsigned char *input, unsigned char 
*output, unsigned int dcs);
 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);
@@ -359,6 +361,11 @@
                        if (error != GN_ERR_NONE) return error;
                } while (DRVINSTANCE(state)->user_data_count < 
data->raw_sms->length);

+               sms_data_decode(DRVINSTANCE(state)->user_data_count,
+                               DRVINSTANCE(state)->user_data,
+                               data->raw_sms->user_data,
+                               data->raw_sms->dcs);
+
                /* the message has been successfully retrieved! */
                return GN_ERR_NONE;
        case 0x2d:
@@ -410,32 +417,27 @@
 {
        unsigned char msgtype, hreq[256], req[256], udata[256];
                /* FIXME hardcoded buffer sizes are ugly */
-       int c, response, hsize, retry_count, timeout;
+       int hsize, retry_count, waitfor[2], response;
        int block_count, uoffset, uremain, ulength, blength;
        gn_error error = GN_ERR_NONE;

+       if(save_sms) {
+               msgtype = 0x24;
+               waitfor[0] = 0x2a;
+               waitfor[1] = 0x2b;
+       } else {
+               msgtype = 0x23;
+               waitfor[0] = 0x28;
+               waitfor[1] = 0x29;
+       }
+
        msgtype = save_sms ? 0x24 : 0x23;

-       /* FIXME Dirty hacks ahead:
-        * The message data can either be unpacked from the raw_sms
-        * structure - which is stupid - or it can be read directly from
-        * the data->sms structure - which is ugly and breaks the code
-        * structure. But the latter seems to work a bit better with
-        * special characters, not sure why, but anyway this is not the
-        * way things should be done, but it should be fixed elsewhere. */
-
-#if 0
-       /* The phone expects ASCII data instead of 7bit packed data, which
-        * is the format used in raw_sms. So the data has to be unpacked
-        * again. */
-
-       ulength = char_7bit_unpack(0, data->raw_sms->user_data_length,
-                                       sizeof(udata),
-                                       data->raw_sms->user_data, udata);
-#else
-       ulength = strlen(data->sms->user_data[0].u.text);
-       memcpy(udata, data->sms->user_data[0].u.text, ulength);
-#endif
+       ulength = sms_data_encode(data->raw_sms->user_data_length,
+                                 sizeof(udata),
+                                 data->raw_sms->user_data,
+                                 udata,
+                                 data->raw_sms->dcs);

        hsize = sms_header_encode(data, state, hreq, ulength, save_sms);

@@ -448,9 +450,10 @@

        while (retry_count > 0) {
                if (sm_message_send(hsize, msgtype, hreq, state) != 
GN_ERR_NONE) return GN_ERR_NOTREADY;
-
+               dprintf("header sent\n");
                error = sm_block(msgtype, data, state);
                if (error != GN_ERR_NONE) return error;
+               dprintf("header ack received\n");

                /* Now send as many blocks of maximum 55 characters as required
                   to send complete message. */
@@ -479,36 +482,10 @@
                        uoffset += blength;
                }

-               /* Now wait for response from network which will see
-                  CurrentSMSMessageError change from busy. */
-               if (save_sms) {
-                       sm_wait_for(0x2a, data, state);
-                       sm_wait_for(0x2b, data, state);
-               } else {
-                       sm_wait_for(0x28, data, state);
-                       sm_wait_for(0x29, data, state);
-               }
-
-               timeout = 1200; /* 120secs 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;
+               /* Now wait for response from network */

-               /* 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_timeout(waitfor, 2, &response, 1200, data, 
state);
+               if (error == GN_ERR_TIMEOUT) return error;

                /* process response */
                switch (response) {
@@ -516,8 +493,9 @@
                        return error;
                case 0x29:
                        /* Got a retry response so try again! */
-                       dprintf("SMS send attempt failed, trying again...\n");
+                       dprintf("SMS send attempt failed.\n");
                        retry_count--;
+                       if (retry_count > 0) dprintf("Trying again...\n");
                        /* After an empirically determined pause... */
                        usleep(500000); /* 0.5 seconds. */
                        break;
@@ -529,7 +507,6 @@
                default:
                        return GN_ERR_INTERNALERROR;
                }
-
        }

        /* Retries must have failed. */
@@ -683,8 +660,13 @@
           if so then nothing to do */
        if (length == 0x02) return GN_ERR_NONE;

+       if (!data->raw_sms) {
+               dprintf("Unrequested SMS data frame received, ignoring.\n");
+               return GN_ERR_INTERNALERROR;
+       }
+
        /* This function may be called several times; it accumulates the
-        * SMS content in data->raw_sms->user_data.
+        * SMS content in DRVINSTANCE(state)->user_data
         * DRVINSTANCE(state)->user_data_count is used as a counter. */

        /* If this is the first block, reset accumulated message length. */
@@ -693,7 +675,7 @@

        count = DRVINSTANCE(state)->user_data_count + length - 3;

-       memcpy(data->raw_sms->user_data + DRVINSTANCE(state)->user_data_count, 
message + 3, length - 3);
+       memcpy(DRVINSTANCE(state)->user_data + 
DRVINSTANCE(state)->user_data_count, message + 3, length - 3);

        DRVINSTANCE(state)->user_data_count += length - 3;

@@ -774,14 +756,7 @@
        else
                data->raw_sms->udh_indicator = 0;

-
        data->raw_sms->dcs = message[7];
-       /* FIXME the DCS is set to indicate an 8-bit message in order
-        * to avoid the conversion from 7bit in gsm-sms.c
-        * This really should be done some other way... */
-       data->raw_sms->dcs = 0xf4;
-
-       /* Set message length */
        data->raw_sms->length = message[15];

        /* Only received messages have meaningful timestamps and numbers,
@@ -1109,10 +1084,9 @@
 static int sms_header_encode(gn_data *data, struct gn_statemachine *state, 
unsigned char *req, int ulength, bool save_sms)
 {
        int pos = 0;
-       unsigned char fo;       /* some magic flags */
        unsigned char smsc[256], remote[256];

-       /* why the heck is this necessary? gsm-sms.c does this too  -Osma 
Suominen */
+       /* convert length units from decimal digit count to BCD byte count */
        data->raw_sms->remote_number[0] = (data->raw_sms->remote_number[0] + 1) 
/ 2 + 1;

        /* SMSC and remote number are in BCD format, but the phone wants them
@@ -1121,17 +1095,33 @@
        snprintf(smsc, sizeof(smsc), "%s", 
char_bcd_number_get(data->raw_sms->message_center));
        snprintf(remote, sizeof(remote), "%s", 
char_bcd_number_get(data->raw_sms->remote_number));

+
        dprintf("smsc:'%s' remote:'%s'", smsc, remote);

-       if (save_sms) { /* make header for saving SMS */
+       if (save_sms) { /* make header for saving SMS */
                req[pos++] = get_memory_type(data->raw_sms->memory_type);
                req[pos++] = data->raw_sms->status;
                req[pos++] = 0x01;      /* status byte for "saved SMS" */
-       } else { /* make header for sending SMS */
-               /* the magic "first octet" or FO */
-               fo = 0x31;      /* FO_SUBMIT | FO_VPF_REL | FO_SRR */
-               if (data->raw_sms->udh_indicator)       fo |= 0x40;
-               req[pos++] = fo;
+       } else {        /* make header for sending SMS */
+               /* the magic "first octet" specifying flags */
+               if(data->raw_sms->type != GN_SMS_MT_Deliver)
+                       req[pos] = 0x01;        /* SMS Submit */
+               else
+                       req[pos] = 0x00;        /* SMS Deliver */
+               if(data->raw_sms->reply_via_same_smsc)  req[pos] |= 0x80;
+               if(data->raw_sms->reject_duplicates)    req[pos] |= 0x04;
+               if(data->raw_sms->report)               req[pos] |= 0x20;
+               if(data->raw_sms->udh_indicator)        req[pos] |= 0x40;
+               if(data->raw_sms->type != GN_SMS_MT_Deliver) {
+                       switch(data->raw_sms->validity_indicator) {
+                       case GN_SMS_VP_None: default:   break;
+                       case GN_SMS_VP_RelativeFormat:  req[pos] |= 0x10; break;
+                       case GN_SMS_VP_AbsoluteFormat:  req[pos] |= 0x18; break;
+                       case GN_SMS_VP_EnhancedFormat:  req[pos] |= 0x08; break;
+                       }
+               }
+               dprintf("First Octet: %02x\n", req[pos]);
+               pos++;
        }

        req[pos++] = data->raw_sms->pid;
@@ -1142,13 +1132,8 @@
         * into the garbage you get in the date bytes when you read a saved
         * SMS. So we'll just put validity in here now. */

-       req[pos++] = 0xff;      /* FIXME Max validity - hardcoded! */
-       req[pos++] = 0x00;
-       req[pos++] = 0x00;
-       req[pos++] = 0x00;
-       req[pos++] = 0x00;
-       req[pos++] = 0x00;
-       req[pos++] = 0x00;
+       memcpy(req + pos, data->raw_sms->validity, 7);
+       pos += 7;

        req[pos++] = ulength;   /* user data length */

@@ -1174,6 +1159,61 @@
        return pos;     /* length of encoded header is returned */
 }

+/* Encode and decode messages, ASCII format to/from 7bit packed format.
+ * The 3110 does this encoding itself and wants ASCII but the data->raw_sms
+ * structure uses 7bit packed data, so conversion is required both ways.
+ * An alternative would be for gsm-sms.c to recognize the possibility that
+ * not all phones want 7bit packed (PDU) data and deal with those phones
+ * (only the 3110 series AFAIK) separately, avoiding conversions entirely.
+ * Note that for 8bit and Unicode messages there is no need to do conversion
+ * as these are passed right through by the phone. */
+
+static int sms_data_encode(int in_length, int out_length,
+                          unsigned char *input, unsigned char *output,
+                          unsigned int dcs)
+{
+       int ulength;
+
+       if (   (dcs & 0x08) == 0x08     /* Unicode */
+           || (dcs & 0xf4) == 0xf4 ) { /* 8bit */
+
+               ulength = in_length;
+               memcpy(output, input, in_length);
+
+       } else {        /* 7bit default alphabet */
+               /* The phone expects ASCII data instead of 7bit packed data,
+                * which is the format used in raw_sms. So the data has to
+                * be unpacked again. */
+
+               ulength = char_7bit_unpack(0, in_length, out_length,
+                                          input, output);
+               char_ascii_decode(output, output, ulength);
+               ulength = strlen(output);
+       }
+       return ulength;
+}
+
+static int sms_data_decode(int in_length, unsigned char *input,
+                          unsigned char *output, unsigned int dcs)
+{
+
+       if (   (dcs & 0x08) == 0x08     /* Unicode */
+           || (dcs & 0xf4) == 0xf4 ) { /* 8bit */
+
+               memcpy(output, input, in_length);
+
+       } else {        /* 7bit default alphabet */
+               /* The phone sends ASCII data instead of 7bit packed data,
+                * which is the format used in raw_sms. So the data has to
+                * be packed - to be later unpacked again! */
+
+               in_length = 0;
+               char_7bit_pack(0, input, output, &in_length);
+       }
+       return in_length;
+}
+
+
 static int get_memory_type(gn_memory_type memory_type)
 {
        int result;
@@ -1259,7 +1299,12 @@
                sm_message_send(state->last_msg_size, state->last_msg_type, 
state->last_msg, state);
        }

-       if (state->received_number == 0) return GN_ERR_TIMEOUT;
+       if (state->received_number == 0) {
+               sm_reset(state);
+               return GN_ERR_TIMEOUT;
+       }
+
+       err = GN_ERR_INTERNALERROR;

        /* Since the state machine still waits for the other message, the
         * result has to be dug up from its internals. sm_error_get() is
@@ -1269,12 +1314,12 @@
                if (state->ResponseError[i] != GN_ERR_BUSY) {
                        if(response != NULL)
                                *response = state->waiting_for[i];
-                       return state->ResponseError[i];
+                       err = state->ResponseError[i];
                }
        }

-       dprintf("End of expect_message_many reached - should not happen!\n");
-       return GN_ERR_INTERNALERROR;
+       sm_reset(state);
+       return err;
 }

 /* Same as block_many_timeout but with a default timeout of 3 seconds */

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




reply via email to

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