Send commitlog mailing list submissions to
        [email protected]

To subscribe or unsubscribe via the World Wide Web, visit
        http://lists.openmoko.org/mailman/listinfo/commitlog
or, via email, send a message with subject or body 'help' to
        [EMAIL PROTECTED]

You can reach the person managing the list at
        [EMAIL PROTECTED]

When replying, please edit your Subject line so it is more specific
than "Re: Contents of commitlog digest..."
Today's Topics:

   1. r2335 - trunk/src/host/qemu-neo1973/hw ([EMAIL PROTECTED])
   2. r2336 - in trunk/src/host/qemu-neo1973: gnokiigsm hw
      ([EMAIL PROTECTED])
--- Begin Message ---
Author: andrew
Date: 2007-06-23 02:58:06 +0200 (Sat, 23 Jun 2007)
New Revision: 2335

Modified:
   trunk/src/host/qemu-neo1973/hw/s3c2410.c
Log:
Implement S3C UART RxTimeout interrupt (gsmd's buggy read loop depends on this).


Modified: trunk/src/host/qemu-neo1973/hw/s3c2410.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/s3c2410.c    2007-06-23 00:55:52 UTC (rev 
2334)
+++ trunk/src/host/qemu-neo1973/hw/s3c2410.c    2007-06-23 00:58:06 UTC (rev 
2335)
@@ -1320,8 +1320,16 @@
 inline static void s3c_uart_full(struct s3c_uart_state_s *s, int pulse)
 {
     if (s->fcontrol & 1)                       /* FIFOEnable */
-        if (s->rxlen < (((s->fcontrol >> 4) & 3) + 1) * 4)
-            return;
+        if (s->rxlen < (((s->fcontrol >> 4) & 3) + 1) * 4) {
+            if (((s->control >> 0) & 3) != 1 ||        /* ReceiveMode */
+                            !s->rxlen)
+                return;
+            if (!(s->control & (1 << 7)))      /* RxTimeOutEnable */
+                return;
+            /* When the Rx FIFO trigger level is not reached, the interrupt
+             * is generated anyway, just after a small timeout instead of
+             * immediately.  */
+        }
 
     switch ((s->control >> 0) & 3) {           /* ReceiveMode */
     case 1:




--- End Message ---
--- Begin Message ---
Author: andrew
Date: 2007-06-23 03:01:43 +0200 (Sat, 23 Jun 2007)
New Revision: 2336

Modified:
   trunk/src/host/qemu-neo1973/gnokiigsm/at-emulator.c
   trunk/src/host/qemu-neo1973/gnokiigsm/at-emulator.h
   trunk/src/host/qemu-neo1973/gnokiigsm/data.h
   trunk/src/host/qemu-neo1973/gnokiigsm/statemachine.h
   trunk/src/host/qemu-neo1973/hw/modem.c
Log:
Implement many new GSM AT commands (some are undocumented), registering
with network, signal strength, error reporting levels.


Modified: trunk/src/host/qemu-neo1973/gnokiigsm/at-emulator.c
===================================================================
--- trunk/src/host/qemu-neo1973/gnokiigsm/at-emulator.c 2007-06-23 00:58:06 UTC 
(rev 2335)
+++ trunk/src/host/qemu-neo1973/gnokiigsm/at-emulator.c 2007-06-23 01:01:43 UTC 
(rev 2336)
@@ -155,14 +155,15 @@
        gn_sm_functions(GN_OP_SetCallNotification, &data, sm);
 
        /* query model, revision and imei */
-       if (gn_sm_functions(GN_OP_Identify, &data, sm) != GN_ERR_NONE) return 
false;
+       if (gn_sm_functions(GN_OP_Identify, &data, sm) != GN_ERR_NONE)
+               return false;
 
        /* We're ready to roll... */
        gn_atem_initialised = true;
+       data.connected = 0;
        return (true);
 }
 
-
 /* Initialise the "registers" used by the virtual modem. */
 void   gn_atem_registers_init(void)
 {
@@ -287,7 +288,7 @@
                        /* Echo character if appropriate. */
                        if (buffer[count] == ModemRegisters[REG_CR] &&
                                (ModemRegisters[REG_ECHO] & BIT_ECHO)) {
-                               gn_atem_string_out("\r\n");
+                               gn_atem_string_out("\r");       /* XXX */
                        }
 
                        /* Save CTRL-Z and ESCAPE for the parser */
@@ -331,6 +332,22 @@
        }
 }
 
+static char *gn_atem_cme(int code)
+{
+       static char err[80];
+
+       if (!strcmp(data.cmee, "0"))
+               return "ERROR";
+
+       if (!strcmp(data.cmee, "1"))
+               snprintf(err, sizeof(err), "+CME ERROR: %i", code);
+
+       if (!strcmp(data.cmee, "2"))
+               snprintf(err, sizeof(err), "+CME ERROR: phone error");
+
+       return err;
+}
+
 struct gn_atem_op {
        char *op;
        int writable;
@@ -339,6 +356,7 @@
                gn_var_bool,    /* 0,1 */
                gn_var_numbers, /* (1-5),(9-20) */
        } type;
+       bool (*set_val)(char **buf, struct gn_atem_op *op, char *val);
        char *default_val;
        char *string_val[];
 };
@@ -391,6 +409,9 @@
        if (!op->writable)
                return (true);
 
+       if (op->set_val)
+               return op->set_val(buf, op, val);
+
        switch (op->type) {
        case gn_var_string:
                for (strval = op->string_val; *strval; strval++)
@@ -440,6 +461,81 @@
        },
 };
 
+static bool gn_atem_cmee_set(char **buf, struct gn_atem_op *op, char *val)
+{
+       switch (gn_atem_num_get(buf)) {
+       case 0:
+               strcpy(val, "0");
+               return (false);
+       case 1:
+               strcpy(val, "1");
+               return (false);
+       case 2:
+               strcpy(val, "2");
+               return (false);
+       }
+       return (true);
+}
+
+static struct gn_atem_op gn_atem_op_cmee = {
+       .op             = "+CMEE",
+       .writable       = 1,
+       .type           = gn_var_numbers,
+       .default_val    = "0",
+       .string_val     = {
+               "(0-2)",
+       },
+       .set_val        = gn_atem_cmee_set,
+};
+
+static bool gn_atem_clip_set(char **buf, struct gn_atem_op *op, char *val)
+{
+       switch (gn_atem_num_get(buf)) {
+       case 0:
+               strcpy(val, "0,1");     /* CLIP provisioned in this network */
+               return (false);
+       case 1:
+               strcpy(val, "1,1");     /* CLIP provisioned in this network */
+               return (false);
+       }
+       return (true);
+}
+
+static struct gn_atem_op gn_atem_op_clip = {
+       .op             = "+CLIP",
+       .writable       = 1,
+       .type           = gn_var_numbers,
+       .default_val    = "0,1",
+       .string_val     = {
+               "(0,1)",
+       },
+       .set_val        = gn_atem_clip_set,
+};
+
+static bool gn_atem_colp_set(char **buf, struct gn_atem_op *op, char *val)
+{
+       switch (gn_atem_num_get(buf)) {
+       case 0:
+               strcpy(val, "0,1");     /* COLP provisioned in this network */
+               return (false);
+       case 1:
+               strcpy(val, "1,1");     /* COLP provisioned in this network */
+               return (false);
+       }
+       return (true);
+}
+
+static struct gn_atem_op gn_atem_op_colp = {
+       .op             = "+COLP",
+       .writable       = 1,
+       .type           = gn_var_numbers,
+       .default_val    = "0,1",
+       .string_val     = {
+               "(0,1)",
+       },
+       .set_val        = gn_atem_colp_set,
+};
+
 static struct gn_atem_op gn_atem_op_ws46 = {
        .op             = "+WS46",
        .writable       = 1,
@@ -517,6 +613,39 @@
        },
 };
 
+static bool gn_atem_creg_set(char **buf, struct gn_atem_op *op, char *val)
+{
+       /* <stat> values are:
+        * 0    not registered, MT is not currently searching a
+        *      new operator to register to
+        * 1    registered, home network
+        * 2    not registered, but MT is currently searching a
+        *      new operator to register to
+        * 3    registration denied
+        * 4    unknown
+        * 5    registered, roaming
+        */
+       switch (gn_atem_num_get(buf)) {
+       case 0:
+               /* No unsolicited +CREG. */
+               strcpy(val, "0,1");
+               return (false);
+       case 1:
+               /* +CREG Syntax is <stat> when there's a change in network
+                * registration status.
+                */
+               strcpy(val, "1,1");
+               return (false);
+       case 2:
+               /* +CREG Syntax is <stat>[,<lac>,<ci>[,<AcT>]] when we've (MT)
+                * succesfully registered in the network cell.
+                */
+               strcpy(val, "2,1");
+               return (false);
+       }
+       return (true);
+}
+
 static struct gn_atem_op gn_atem_op_creg = {
        .op             = "+CREG",
        .writable       = 1,
@@ -525,13 +654,64 @@
        .string_val     = {
                "(0-2)",
        },
+       .set_val        = gn_atem_creg_set,
 };
 
+static void gn_atem_network_msg(int connected,
+                       struct gn_statemachine *state)
+{
+       char *buffer;
+
+       data.connected = connected;
+       /* TODO: Send +COPS and +CREG separately */
+       /* TODO: Take COPS format and CREG format settings into account */
+       if (connected) {
+               strcpy(data.cops, "1,\"012C\",\"0DCC\"");
+       } else {
+               strcpy(data.cops, "2");
+       }
+       if (strcmp(data.creg, "0"))
+               asprintf(&buffer, "+CREG: %s\r\n", data.cops);
+       else
+               /* +CREG: is disabled, but +COPS is allowed */
+               asprintf(&buffer, "+COPS: %s\r\n", data.cops);
+       gn_atem_string_out(buffer);
+       free(buffer);
+}
+
+static bool gn_atem_cops_set(char **buf, struct gn_atem_op *op, char *val)
+{
+       data.network_change_notification = gn_atem_network_msg;
+
+       /* Syntax is <mode>[,<format>[,<oper>]] */
+       switch (gn_atem_num_get(buf)) { /* Parse <mode> */
+       case 0:
+       case 1:
+       case 4:
+               if (gn_sm_functions(GN_OP_NetworkRegister, &data, sm) !=
+                               GN_ERR_NONE)
+                       break;
+               return (false);
+       case 2:
+               if (gn_sm_functions(GN_OP_NetworkUnregister, &data, sm) !=
+                               GN_ERR_NONE)
+                       break;
+               return (false);
+       case 3: /* Only sets <format>, TODO */
+               return (false);
+       }
+       return (true);
+}
+
 static struct gn_atem_op gn_atem_op_cops = {
        .op             = "+COPS",
        .writable       = 1,
-       .type           = gn_var_bool,
-       .default_val    = "0",
+       .type           = gn_var_numbers,
+       .default_val    = "2",
+       .string_val     = {
+               "(0-4)",
+       },
+       .set_val        = gn_atem_cops_set,
 };
 
 static struct gn_atem_op gn_atem_op_cpas = {
@@ -544,16 +724,52 @@
        },
 };
 
+static bool gn_atem_cfun_set(char **buf, struct gn_atem_op *op, char *val)
+{
+       /* Format is <fun>[,<Rst] */
+       switch (gn_atem_num_get(buf)) { /* Ignore the Reset argument */
+       case 0:
+               /* Minimum functionality */
+               strcpy(val, "0");
+               return (false);
+       case 1:
+               /* Full functionality */
+               strcpy(val, "1");
+               return (false);
+       case 2:
+               /* Disable phone transmit RF circuits only */
+               strcpy(val, "2");
+               return (false);
+       case 3:
+               /* Disable phone receive RF circuits only */
+               strcpy(val, "3");
+               return (false);
+       case 4:
+               /* Disable phone both transmit and receive RF circuits */
+               strcpy(val, "4");
+               return (false);
+       }
+       return (true);
+}
+
 static struct gn_atem_op gn_atem_op_cfun = {
        .op             = "+CFUN",
        .writable       = 1,
        .type           = gn_var_numbers,
        .default_val    = "1",
        .string_val     = {
-               "(0,1,4),(0)",
+               "(0-4),(0)",
        },
+       .set_val        = gn_atem_cfun_set,
 };
 
+static struct gn_atem_op gn_atem_op_ctzr = {
+       .op             = "+CTZR",
+       .writable       = 1,
+       .type           = gn_var_bool,
+       .default_val    = "0",
+};
+
 static struct gn_atem_op gn_atem_op_cbc = {
        .op             = "+CBC",
        .writable       = 1,
@@ -564,6 +780,24 @@
        },
 };
 
+static bool gn_atem_band_set(char **buf, struct gn_atem_op *op, char *val)
+{
+       /* Syntax is <band>[,<mode>] */
+       switch (gn_atem_num_get(buf)) {
+       case 0:
+               /* Automatic */
+               strcpy(val, "0");
+               break;
+       case 1:
+               /* Manual */
+               strcpy(val, "1");
+               break;
+       default:
+               return (true);
+       }
+       return (false);
+}
+
 static struct gn_atem_op gn_atem_op_band = {
        .op             = "%BAND",
        .writable       = 1,
@@ -572,10 +806,51 @@
        .string_val     = {
                "(0-1),(1-31)",
        },
+       .set_val        = gn_atem_band_set,
 };
 
+static bool gn_atem_cpi_set(char **buf, struct gn_atem_op *op, char *val)
+{
+       switch (gn_atem_num_get(buf)) {
+       case 0:
+               /* Disable */
+               strcpy(val, "0");
+               break;
+       case 1:
+               /* Enable */
+               strcpy(val, "1");
+               break;
+       case 2:
+               /* Status */
+               strcpy(val, "2");
+               break;
+       case 3:
+               /* Append cause and ALS bearer state to unsolicited results */
+               strcpy(val, "3");
+               break;
+       case 4:
+               /* Append Advance Cause Code */
+               strcpy(val, "4");
+               break;
+       default:
+               return (true);
+       }
+       return (false);
+}
+
+static struct gn_atem_op gn_atem_op_cpi = {
+       .op             = "%CPI",
+       .writable       = 1,
+       .type           = gn_var_numbers,
+       .default_val    = "1",
+       .string_val     = {
+               "(0-4)",
+       },
+       .set_val        = gn_atem_cpi_set,
+};
+
 static struct gn_atem_op gn_atem_op_cssn = {
-       .op             = "CSSN",
+       .op             = "+CSSN",
        .writable       = 1,
        .type           = gn_var_numbers,
        .default_val    = "0,0",
@@ -594,8 +869,8 @@
        if (!cmd_buffer[0])
                return;
 
-       if (strncasecmp (cmd_buffer, "AT", 2) != 0) {
-               gn_atem_modem_result(MR_ERROR);
+       if (strncasecmp(cmd_buffer, "AT", 2) != 0) {
+               gn_atem_modem_result(sm->info->non_at_ok ? MR_OK : MR_ERROR);
                return;
        }
 
@@ -623,7 +898,6 @@
                        buf++;
                        gn_atem_answer_phone();
                        return;
-                       break;
 
                case 'D':
                        /* Dial Data :-) */
@@ -650,7 +924,6 @@
                                gn_sm_loop(10, sm);
                        }
                        return;
-                       break;
 
                case 'H':
                        /* Hang Up */
@@ -858,14 +1131,12 @@
                /* % is the precursor to another set of commands */
                case '%':
                        buf++;
-                       if (strncasecmp(buf, "BAND", 3) == 0) {
-                               buf += 4;
-                               if (!gn_atem_parse_option(&buf,
-                                               &gn_atem_op_band, data.band))
-                                       break;
+                       /* Returns true if error occured */
+                       if (gn_atem_command_percent(&buf) == true) {
+                               gn_atem_modem_result(MR_ERROR);
+                               return;
                        }
-                       gn_atem_modem_result(MR_ERROR);
-                       return;
+                       break;
 
                default:
                        gn_atem_modem_result(MR_ERROR);
@@ -981,7 +1252,8 @@
                        if (gn_sm_functions(GN_OP_DeleteSMS, &data, sm) == 
GN_ERR_NONE) {
                                gn_atem_modem_result(MR_OK);
                        } else {
-                               gn_atem_modem_result(MR_ERROR);
+                               gn_atem_string_out(gn_atem_cme(21));
+                               gn_atem_string_out("\r\n");
                        }
                        return;
                case 'Q':
@@ -1022,7 +1294,8 @@
                                gn_atem_string_out(buffer);
                                gn_atem_modem_result(MR_OK);
                        } else {
-                               gn_atem_modem_result(MR_ERROR);
+                               gn_atem_string_out(gn_atem_cme(0));
+                               gn_atem_string_out("\r\n");
                        }
                        return;
                } else if (buff[i] == ModemRegisters[REG_ESCAPE]) {
@@ -1060,7 +1333,9 @@
                data.rf_unit = &rfunits;
                data.rf_level = &rflevel;
                if (gn_sm_functions(GN_OP_GetRFLevel, &data, sm) == 
GN_ERR_NONE) {
-                       gsprintf(buffer, MAX_LINE_LENGTH, "+CSQ: %0.0f, 
99\r\n", *(data.rf_level));
+                       gsprintf(buffer, MAX_LINE_LENGTH,
+                                       "+CSQ: %0.0f, 99\r\n",
+                                       *(data.rf_level));
                        gn_atem_string_out(buffer);
                        return (false);
                } else {
@@ -1080,7 +1355,7 @@
        /* AT+CGSN is IMEI */
        if (strncasecmp(*buf, "GSN", 3) == 0) {
                buf[0] += 3;
-               strcpy(data.imei, "+CME ERROR: 0");
+               strcpy(data.imei, gn_atem_cme(0));
                if (gn_sm_functions(GN_OP_GetImei, &data, sm) == GN_ERR_NONE) {
                        gsprintf(buffer, MAX_LINE_LENGTH, "%s\r\n", data.imei);
                        gn_atem_string_out(buffer);
@@ -1093,7 +1368,7 @@
        /* AT+CGMR is Revision (hardware) */
        if (strncasecmp(*buf, "GMR", 3) == 0) {
                buf[0] += 3;
-               strcpy(data.revision, "+CME ERROR: 0");
+               strcpy(data.revision, gn_atem_cme(0));
                if (gn_sm_functions(GN_OP_GetRevision, &data, sm) == 
GN_ERR_NONE) {
                        gsprintf(buffer, MAX_LINE_LENGTH, "%s\r\n", 
data.revision);
                        gn_atem_string_out(buffer);
@@ -1106,7 +1381,7 @@
        /* AT+CGMM is Model code  */
        if (strncasecmp(*buf, "GMM", 3) == 0) {
                buf[0] += 3;
-               strcpy(data.model, "+CME ERROR: 0");
+               strcpy(data.model, gn_atem_cme(0));
                if (gn_sm_functions(GN_OP_GetModel, &data, sm) == GN_ERR_NONE) {
                        gsprintf(buffer, MAX_LINE_LENGTH, "%s\r\n", data.model);
                        gn_atem_string_out(buffer);
@@ -1307,6 +1582,24 @@
                return gn_atem_parse_option(buf, &gn_atem_op_cmux, data.cmux);
        }
 
+       /* AT+CMEE is Mobile Termination error reporting */
+       if (strncasecmp(*buf, "MEE", 3) == 0) {
+               buf[0] += 3;
+               return gn_atem_parse_option(buf, &gn_atem_op_cmee, data.cmee);
+       }
+
+       /* AT+CLIP is calling line identification presentation */
+       if (strncasecmp(*buf, "LIP", 3) == 0) {
+               buf[0] += 3;
+               return gn_atem_parse_option(buf, &gn_atem_op_clip, data.clip);
+       }
+
+       /* AT+COLP is connected line identification presentation */
+       if (strncasecmp(*buf, "OLP", 3) == 0) {
+               buf[0] += 3;
+               return gn_atem_parse_option(buf, &gn_atem_op_colp, data.colp);
+       }
+
        /* AT+CSTA is address type selection */
        if (strncasecmp(*buf, "STA", 3) == 0) {
                buf[0] += 3;
@@ -1337,6 +1630,12 @@
                return gn_atem_parse_option(buf, &gn_atem_op_crc, data.crc);
        }
 
+       /* AT+CREG is network registration */
+       if (strncasecmp(*buf, "REG", 3) == 0) {
+               buf[0] += 3;
+               return gn_atem_parse_option(buf, &gn_atem_op_creg, data.creg);
+       }
+
        /* AT+CR is reporting control */
        if (strncasecmp(*buf, "R", 1) == 0) {
                buf[0] += 1;
@@ -1356,12 +1655,6 @@
                return gn_atem_parse_option(buf, &gn_atem_op_csns, data.csns);
        }
 
-       /* AT+CREG is network registration */
-       if (strncasecmp(*buf, "REG", 3) == 0) {
-               buf[0] += 3;
-               return gn_atem_parse_option(buf, &gn_atem_op_creg, data.creg);
-       }
-
        /* AT+COPS is PLMN selection */
        if (strncasecmp(*buf, "OPS", 3) == 0) {
                buf[0] += 3;
@@ -1380,10 +1673,19 @@
                return gn_atem_parse_option(buf, &gn_atem_op_cfun, data.cfun);
        }
 
+       /* AT+CTZR is time zone reporting */
+       if (strncasecmp(*buf, "TZR", 3) == 0) {
+               buf[0] += 3;
+               return gn_atem_parse_option(buf, &gn_atem_op_ctzr, data.ctzr);
+       }
+
+       /* AT+CBC is battery charge */
        if (strncasecmp(*buf, "BC", 2) == 0) {
                buf[0] += 2;
                return gn_atem_parse_option(buf, &gn_atem_op_cbc, data.cbc);
        }
+
+       /* AT+CSSN is supplementary service notifications */
        if (strncasecmp(*buf, "CSSN", 4) == 0) {
                buf[0] += 4;
                return gn_atem_parse_option(buf, &gn_atem_op_cssn, data.cssn);
@@ -1392,6 +1694,83 @@
        return (true);
 }
 
+static void gn_atem_signal_quality(struct gn_statemachine *state)
+{
+       float           rflevel = -1;
+       gn_rf_unit      rfunits = GN_RF_CSQ;
+       char            buffer[MAX_LINE_LENGTH];
+
+       if (!data.csq)
+               return;
+
+       data.rf_unit = &rfunits;
+       data.rf_level = &rflevel;
+       if (gn_sm_functions(GN_OP_GetRFLevel, &data, sm) == GN_ERR_NONE) {
+               gsprintf(buffer, MAX_LINE_LENGTH,
+                               "%%CSQ: %.f, 99, 2\r\n", *(data.rf_level));
+               gn_atem_string_out(buffer);
+       }
+}
+
+/* Handle AT% commands, this is a quick hack together at this
+   stage. */
+bool   gn_atem_command_percent(char **buf)
+{
+       char            buffer[MAX_LINE_LENGTH];
+
+       /* This command is undocumented.  */
+       if (!strncasecmp(*buf, "CSQ", 3)) {
+               buf[0] += 3;
+               switch (**buf) {
+               case '=':
+                       buf[0]++;
+                       switch (**buf) {
+                       case '0':
+                               buf[0]++;
+                               data.csq = 0;
+                               break;
+                       case '1':
+                               buf[0]++;
+                               data.csq = 1;
+                               data.signal_quality_notification =
+                                       gn_atem_signal_quality;
+                               break;
+                       case '?':
+                               break;
+                       default:
+                               return (true);
+                       }
+                       gsprintf(buffer, MAX_LINE_LENGTH,
+                                       "%%CSQ: %i\r\n", data.csq);
+                       break;
+               case '?':
+                       buf[0]++;
+                       gsprintf(buffer, MAX_LINE_LENGTH,
+                                       "%%CSQ: (0-31,99),(0-7,99)\r\n");
+                       gn_atem_string_out(buffer);
+                       break;
+               default:
+                       return (true);
+               }
+
+               return (false);
+       }
+
+       /* AT%BAND is Frequency Band Information */
+       if (!strncasecmp(*buf, "BAND", 4)) {
+               buf[0] += 4;
+               return gn_atem_parse_option(buf, &gn_atem_op_band, data.band);
+       }
+
+       /* AT%CPI is Call Progress Information */
+       if (!strncasecmp(*buf, "CPI", 3)) {
+               buf[0] += 3;
+               return gn_atem_parse_option(buf, &gn_atem_op_cpi, data.cpi);
+       }
+
+       return (true);
+}
+
 /* AT+G commands.  Some of these responses are a bit tongue in cheek... */
 bool   gn_atem_command_plusg(char **buf)
 {
@@ -1427,11 +1806,21 @@
        if (strncasecmp(*buf, "SN", 3) == 0) {
                buf[0] += 2;
 
-               gsprintf(buffer, MAX_LINE_LENGTH, _("none built in, choose your 
own\r\n"));
+               gsprintf(buffer, MAX_LINE_LENGTH,
+                               _("none built in, choose your own\r\n"));
                gn_atem_string_out(buffer);
                return (false);
        }
 
+       /* AT+GCAP is overall capabilities of TA */
+       if (strncasecmp(*buf, "CAP", 4) == 0) {
+               buf[0] += 3;
+
+               gsprintf(buffer, MAX_LINE_LENGTH, "+GCAP:+CGSM,+FCLASS\r\n");
+               gn_atem_string_out(buffer);
+               return (false);
+       }
+
        return (true);
 }
 
@@ -1473,36 +1862,47 @@
 {
        char    buffer[16];
 
+       gn_atem_string_out("\r\n");     /* XXX Some modems do this */
+
        if (!(ModemRegisters[REG_VERBOSE] & BIT_VERBOSE)) {
                sprintf(buffer, "%d\r\n", code);
                gn_atem_string_out(buffer);
        } else {
                switch (code) {
                        case MR_OK:
-                                       gn_atem_string_out("OK\r\n");
-                                       break;
+                               gn_atem_string_out("OK\r\n");
+                               break;
 
                        case MR_ERROR:
-                                       gn_atem_string_out("ERROR\r\n");
-                                       break;
+                               gn_atem_string_out("ERROR\r\n");
+                               break;
 
                        case MR_CARRIER:
-                                       gn_atem_string_out("CARRIER\r\n");
-                                       break;
+                               gn_atem_string_out("CARRIER\r\n");
+                               break;
 
                        case MR_CONNECT:
-                                       gn_atem_string_out("CONNECT\r\n");
-                                       break;
+                               gn_atem_string_out("CONNECT\r\n");
+                               break;
 
                        case MR_NOCARRIER:
-                                       gn_atem_string_out("NO CARRIER\r\n");
-                                       break;
+                               gn_atem_string_out("NO CARRIER\r\n");
+                               break;
+
                        case MR_RING:
+                               if (!strcmp(data.crc, "1"))
+                                       gn_atem_string_out(
+                                                       "+CRING: VOICE\r\n");
+                               else
                                        gn_atem_string_out("RING\r\n");
-                                       break;
+                               if (!strcmp(data.clip, "1,1"))
+                                       gn_atem_string_out("+CLIP: "
+                                                       "\"313373\",0\r\n");
+                               break;
+
                        default:
-                                       gn_atem_string_out(_("\r\nUnknown 
Result Code!\r\n"));
-                                       break;
+                               gn_atem_string_out(_("\r\nUnknown Result 
Code!\r\n"));
+                               break;
                }
        }
 
@@ -1530,21 +1930,20 @@
        char    out_char;
 
        while (*buffer) {
-
                /* Translate CR/LF/BS as appropriate */
                switch (*buffer) {
-                       case '\r':
-                               out_char = ModemRegisters[REG_CR];
-                               break;
-                       case '\n':
-                               out_char = ModemRegisters[REG_LF];
-                               break;
-                       case '\b':
-                               out_char = ModemRegisters[REG_BS];
-                               break;
-                       default:
-                               out_char = *buffer;
-                               break;
+               case '\r':
+                       out_char = ModemRegisters[REG_CR];
+                       break;
+               case '\n':
+                       out_char = ModemRegisters[REG_LF];
+                       break;
+               case '\b':
+                       out_char = ModemRegisters[REG_BS];
+                       break;
+               default:
+                       out_char = *buffer;
+                       break;
                }
 
                sm->info->write(sm->info->opaque, "%c", out_char);

Modified: trunk/src/host/qemu-neo1973/gnokiigsm/at-emulator.h
===================================================================
--- trunk/src/host/qemu-neo1973/gnokiigsm/at-emulator.h 2007-06-23 00:58:06 UTC 
(rev 2335)
+++ trunk/src/host/qemu-neo1973/gnokiigsm/at-emulator.h 2007-06-23 01:01:43 UTC 
(rev 2336)
@@ -44,6 +44,7 @@
 void   gn_atem_dir_parse(char *cmd_buffer);
 bool   gn_atem_command_plusc(char **buf);
 bool   gn_atem_command_plusg(char **buf);
+bool   gn_atem_command_percent(char **buf);
 int    gn_atem_num_get(char **p);
 void   gn_atem_modem_result(int code);
 void    gn_atem_call_passup(gn_call_status call_status, gn_call_info 
*call_info, struct gn_statemachine *state);

Modified: trunk/src/host/qemu-neo1973/gnokiigsm/data.h
===================================================================
--- trunk/src/host/qemu-neo1973/gnokiigsm/data.h        2007-06-23 00:58:06 UTC 
(rev 2335)
+++ trunk/src/host/qemu-neo1973/gnokiigsm/data.h        2007-06-23 01:01:43 UTC 
(rev 2336)
@@ -108,23 +108,33 @@
        gn_file_list *file_list;
        gn_file *file;
 
+       void (*network_change_notification)(int connected,
+                       struct gn_statemachine *state);
+       int connected;
+       void (*signal_quality_notification)(struct gn_statemachine *state);
        gn_choice cscs;
        gn_choice cmux;
+       gn_choice cmee;
        gn_choice ws46;
        gn_choice csta;
        gn_choice cbst;
        gn_choice crlp;
        gn_choice cr;
        gn_choice crc;
+       gn_choice clip;
        gn_choice cmod;
        gn_choice csns;
        gn_choice creg;
        gn_choice cpas;
        gn_choice cops;
+       gn_choice colp;
        gn_choice cfun;
        gn_choice cbc;
+       gn_choice cpi;
        gn_choice band;
        gn_choice cssn;
+       gn_choice ctzr;
+       int csq;
 } gn_data;
 
 /* 
@@ -271,6 +281,8 @@
        GN_OP_GetFileDetailsById,
        GN_OP_GetFileById,
        GN_OP_DeleteFileById,
+       GN_OP_NetworkRegister,
+       GN_OP_NetworkUnregister,
        GN_OP_Max,      /* don't append anything after this entry */
 } gn_operation;
 

Modified: trunk/src/host/qemu-neo1973/gnokiigsm/statemachine.h
===================================================================
--- trunk/src/host/qemu-neo1973/gnokiigsm/statemachine.h        2007-06-23 
00:58:06 UTC (rev 2335)
+++ trunk/src/host/qemu-neo1973/gnokiigsm/statemachine.h        2007-06-23 
01:01:43 UTC (rev 2336)
@@ -103,6 +103,7 @@
                        struct gn_statemachine *sm);
        void (*write)(void *opaque, const char *fmt, ...);
        void *opaque;
+       int non_at_ok;
 };
 
 GNOKII_API gn_state gn_sm_loop(int timeout, struct gn_statemachine *state);

Modified: trunk/src/host/qemu-neo1973/hw/modem.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/modem.c      2007-06-23 00:58:06 UTC (rev 
2335)
+++ trunk/src/host/qemu-neo1973/hw/modem.c      2007-06-23 01:01:43 UTC (rev 
2336)
@@ -26,6 +26,9 @@
 
     struct gn_statemachine state;
     struct gsmmodem_info_s info;
+    QEMUTimer *csq_tm;
+    QEMUTimer *reg_tm;
+    gn_data *reg_data;
 };
 
 #define TICALYPSOv3_MANF       "<manufacturer>"
@@ -41,10 +44,17 @@
 static gn_error modem_ops(gn_operation op, gn_data *data,
                 struct gn_statemachine *sm)
 {
+    struct modem_s *s = (struct modem_s *) sm->info->opaque;
+    int len;
+
     switch (op) {
     case GN_OP_MakeCall:
-        fprintf(stderr, "%s: calling %s: busy.\n", __FUNCTION__,
-                        data->call_info->number);
+        len = strlen(data->call_info->number);
+        if (data->call_info->number[len - 1] == ';')
+            len --;
+        fprintf(stderr, "%s: calling %.*s: busy.\n", __FUNCTION__,
+                        len, data->call_info->number);
+        /* FIXME: this is not the right way to signal busy line.  */
         return GN_ERR_LINEBUSY;
 
     case GN_OP_CancelCall:
@@ -67,7 +77,7 @@
         return GN_ERR_NOTSUPPORTED;
 
     case GN_OP_GetRFLevel:
-        *data->rf_level = 32.0f;       /* Some -50 dBm */
+        *data->rf_level = 30.0f;       /* Some -50 dBm */
         break;
 
     case GN_OP_GetImei:
@@ -89,6 +99,18 @@
         strcpy(data->manufacturer, TICALYPSOv4_MANF);
         break;
 
+    case GN_OP_NetworkRegister:
+        s->reg_data = data;
+        qemu_mod_timer(s->reg_tm, qemu_get_clock(vm_clock) + ticks_per_sec);
+        break;
+
+    case GN_OP_NetworkUnregister:
+        qemu_del_timer(s->reg_tm);
+        qemu_del_timer(s->csq_tm);
+        if (data->network_change_notification)
+            data->network_change_notification(0, &s->state);
+        break;
+
     default:
         return GN_ERR_NOTSUPPORTED;
     }
@@ -99,8 +121,26 @@
 {
     s->out_len = 0;
     s->baud_delay = ticks_per_sec;
+    qemu_del_timer(s->reg_tm);
+    qemu_del_timer(s->csq_tm);
 }
 
+static void modem_csq_report(void *opaque)
+{
+    struct modem_s *s = (struct modem_s *) opaque;
+    if (s->reg_data && s->reg_data->signal_quality_notification)
+        s->reg_data->signal_quality_notification(&s->state);
+    qemu_mod_timer(s->csq_tm, qemu_get_clock(vm_clock) + ticks_per_sec * 30);
+}
+
+static void modem_network_register(void *opaque)
+{
+    struct modem_s *s = (struct modem_s *) opaque;
+    if (s->reg_data && s->reg_data->network_change_notification)
+        s->reg_data->network_change_notification(1, &s->state);
+    modem_csq_report(opaque);
+}
+
 static inline void modem_fifo_wake(struct modem_s *s)
 {
     if (!s->enable || !s->out_len)
@@ -205,6 +245,9 @@
     s->info.write = modem_resp;
     s->info.gn_sm_functions = modem_ops;
     s->info.opaque = s;
+    s->info.non_at_ok = 1;     /* Return OK on non-AT commands.  */
+    s->reg_tm = qemu_new_timer(vm_clock, modem_network_register, s);
+    s->csq_tm = qemu_new_timer(vm_clock, modem_csq_report, s);
 
     if (!gn_atem_initialise(&s->state))
         goto fail;




--- End Message ---
_______________________________________________
commitlog mailing list
[email protected]
http://lists.openmoko.org/mailman/listinfo/commitlog

Reply via email to