r2337 - in trunk/src/host/qemu-neo1973: . gnokiigsm hw
andrew at sita.openmoko.org
andrew at sita.openmoko.org
Sat Jun 23 17:16:24 CEST 2007
Author: andrew
Date: 2007-06-23 17:16:21 +0200 (Sat, 23 Jun 2007)
New Revision: 2337
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/datapump.c
trunk/src/host/qemu-neo1973/hw/modem.c
trunk/src/host/qemu-neo1973/monitor.c
trunk/src/host/qemu-neo1973/vl.c
trunk/src/host/qemu-neo1973/vl.h
Log:
Simulate incoming calls.
Implement TI's undocumented %CPI and +CLIP based on gsmd code.
Report variable CSQ values.
Modified: trunk/src/host/qemu-neo1973/gnokiigsm/at-emulator.c
===================================================================
--- trunk/src/host/qemu-neo1973/gnokiigsm/at-emulator.c 2007-06-23 01:01:43 UTC (rev 2336)
+++ trunk/src/host/qemu-neo1973/gnokiigsm/at-emulator.c 2007-06-23 15:16:21 UTC (rev 2337)
@@ -227,6 +227,12 @@
break;
case GN_CALL_LocalHangup:
case GN_CALL_RemoteHangup:
+ if (IncomingCallNo > 0) {
+ gn_atem_cpi(GSMD_CALLPROG_DISCONNECT,
+ GSMD_CALL_DIR_MT, 0);
+ gn_atem_cpi(GSMD_CALLPROG_RELEASE,
+ GSMD_CALL_DIR_MT, 0);
+ }
IncomingCallNo = -1;
break;
default:
@@ -365,6 +371,10 @@
{
char buffer[MAX_LINE_LENGTH], **strval;
int len;
+
+ if (*val == 0)
+ strcpy(val, op->default_val);
+
if ((*buf)[0] == 0 || ((*buf)[0] == '?' && (*buf)[1] == 0)) {
*buf += strlen(*buf);
gsprintf(buffer, MAX_LINE_LENGTH, "%s: %s\r\n", op->op, val);
@@ -838,6 +848,22 @@
return (false);
}
+void gn_atem_cpi(enum gsmd_call_progress msg,
+ enum gsmd_call_direction dir, int inband)
+{
+ char *buffer;
+
+ if (data.cpi[0] < '1')
+ return;
+
+ /* Format: %CPI: <cId>,<msgType>,<ibt>,<tch>,<dir>,[<mode>],
+ * [<number>],[<type>],[<alpha>],[<cause>],<line> */
+ asprintf(&buffer, "%%CPI: %i,%i,0,%i,%i,0,,,,,0\r\n",
+ data.call_info->call_id, msg, inband, dir);
+ gn_atem_string_out(buffer);
+ free(buffer);
+}
+
static struct gn_atem_op gn_atem_op_cpi = {
.op = "%CPI",
.writable = 1,
@@ -919,6 +945,8 @@
if (gn_sm_functions(GN_OP_MakeCall, &data, sm) != GN_ERR_NONE) {
CommandMode = true;
dp_CallPassup(GN_CALL_RemoteHangup, NULL, NULL);
+ data.call_notification = gn_atem_call_passup;
+ gn_sm_functions(GN_OP_SetCallNotification, &data, sm);
} else {
IncomingCallNo = data.call_info->call_id;
gn_sm_loop(10, sm);
@@ -931,6 +959,12 @@
switch (gn_atem_num_get(&buf)) {
case -1:
case 0: /* hook off the phone */
+ if (IncomingCallNo > 0) {
+ gn_atem_cpi(GSMD_CALLPROG_DISCONNECT,
+ GSMD_CALL_DIR_MT, 0);
+ gn_atem_cpi(GSMD_CALLPROG_RELEASE,
+ GSMD_CALL_DIR_MT, 0);
+ }
gn_atem_hangup_phone();
break;
case 1: /* hook on the phone */
@@ -1890,14 +1924,21 @@
break;
case MR_RING:
+ gn_atem_cpi(GSMD_CALLPROG_SETUP,
+ GSMD_CALL_DIR_MT, 0);
+ gn_atem_cpi(GSMD_CALLPROG_SETUP,
+ GSMD_CALL_DIR_MT, 1);
if (!strcmp(data.crc, "1"))
gn_atem_string_out(
"+CRING: VOICE\r\n");
else
gn_atem_string_out("RING\r\n");
+ /* XXX: Standard format is "313373",145 */
if (!strcmp(data.clip, "1,1"))
- gn_atem_string_out("+CLIP: "
- "\"313373\",0\r\n");
+ gn_atem_string_out("+CLIP: \"313373\""
+ ",145,,,,1\r\n");
+ gn_atem_cpi(GSMD_CALLPROG_SYNC,
+ GSMD_CALL_DIR_MT, 1);
break;
default:
Modified: trunk/src/host/qemu-neo1973/gnokiigsm/at-emulator.h
===================================================================
--- trunk/src/host/qemu-neo1973/gnokiigsm/at-emulator.h 2007-06-23 01:01:43 UTC (rev 2336)
+++ trunk/src/host/qemu-neo1973/gnokiigsm/at-emulator.h 2007-06-23 15:16:21 UTC (rev 2337)
@@ -34,6 +34,28 @@
#include "compat.h"
#include "gnokii.h"
+/* XXX: The values >6 are TI-specific */
+enum gsmd_call_progress {
+ GSMD_CALLPROG_SETUP = 0,
+ GSMD_CALLPROG_DISCONNECT = 1,
+ GSMD_CALLPROG_ALERT = 2,
+ GSMD_CALLPROG_CALL_PROCEED = 3,
+ GSMD_CALLPROG_SYNC = 4,
+ GSMD_CALLPROG_PROGRESS = 5,
+ GSMD_CALLPROG_CONNECTED = 6,
+ GSMD_CALLPROG_RELEASE = 7,
+ GSMD_CALLPROG_REJECT = 8,
+ GSMD_CALLPROG_UNKNOWN = 9,
+ __NUM_GSMD_CALLPROG
+};
+
+enum gsmd_call_direction {
+ GSMD_CALL_DIR_MO = 0, /* Mobile Originated (Outgoing) */
+ GSMD_CALL_DIR_MT = 1, /* Mobile Terminated (Incoming) */
+ GSMD_CALL_DIR_CCBS = 2, /* network initiated MO */
+ GSMD_CALL_DIR_MO_REDIAL = 3, /* Mobile Originated Redial */
+};
+
/* Prototypes */
bool gn_atem_initialise(struct gn_statemachine *sm);
void gn_atem_incoming_data_handle(const char *buffer, int length);
@@ -47,9 +69,12 @@
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);
+void gn_atem_call_passup(gn_call_status call_status,
+ gn_call_info *call_info, struct gn_statemachine *state);
void gn_atem_cid_out(gn_call_info *callinfo);
bool gn_atem_command_diesis(char **buf);
+void gn_atem_cpi(enum gsmd_call_progress msg, enum gsmd_call_direction dir,
+ int inband);
/* Global variables */
extern bool gn_atem_initialised;
Modified: trunk/src/host/qemu-neo1973/gnokiigsm/datapump.c
===================================================================
--- trunk/src/host/qemu-neo1973/gnokiigsm/datapump.c 2007-06-23 01:01:43 UTC (rev 2336)
+++ trunk/src/host/qemu-neo1973/gnokiigsm/datapump.c 2007-06-23 15:16:21 UTC (rev 2337)
@@ -75,6 +75,8 @@
gn_sm_functions(GN_OP_SetRLPRXCallback, &data, sm);
CommandMode = true;
+ data.call_notification = gn_atem_call_passup;
+ gn_sm_functions(GN_OP_SetCallNotification, &data, sm);
return true;
}
Modified: trunk/src/host/qemu-neo1973/hw/modem.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/modem.c 2007-06-23 01:01:43 UTC (rev 2336)
+++ trunk/src/host/qemu-neo1973/hw/modem.c 2007-06-23 15:16:21 UTC (rev 2337)
@@ -29,6 +29,9 @@
QEMUTimer *csq_tm;
QEMUTimer *reg_tm;
gn_data *reg_data;
+ void (*call_notification)(gn_call_status call_status,
+ gn_call_info *call_info, struct gn_statemachine *state);
+ int next_call_id;
};
#define TICALYPSOv3_MANF "<manufacturer>"
@@ -41,7 +44,7 @@
#define TICALYPSOv4_REV "GTA01Bv4"
#define TICALYPSOv4_IMEI "354651010000000"
-static gn_error modem_ops(gn_operation op, gn_data *data,
+static gn_error modem_gsm_ops(gn_operation op, gn_data *data,
struct gn_statemachine *sm)
{
struct modem_s *s = (struct modem_s *) sm->info->opaque;
@@ -61,6 +64,14 @@
fprintf(stderr, "%s: hangup.\n", __FUNCTION__);
break;
+ case GN_OP_AnswerCall:
+ fprintf(stderr, "%s: call answered.\n", __FUNCTION__);
+ if (!s->enable || !s->reg_data || !s->call_notification)
+ break;
+
+ s->call_notification(GN_CALL_RemoteHangup, NULL, &s->state);
+ break;
+
case GN_OP_GetSMS:
fprintf(stderr, "%s: SMS number %i requested\n",
__FUNCTION__, data->sms->number);
@@ -77,7 +88,7 @@
return GN_ERR_NOTSUPPORTED;
case GN_OP_GetRFLevel:
- *data->rf_level = 30.0f; /* Some -50 dBm */
+ *data->rf_level = 15.0f + ((time(0) & 15) ^ 2); /* Around -70 dBm */
break;
case GN_OP_GetImei:
@@ -109,8 +120,13 @@
qemu_del_timer(s->csq_tm);
if (data->network_change_notification)
data->network_change_notification(0, &s->state);
+ s->reg_data = 0;
break;
+ case GN_OP_SetCallNotification:
+ s->call_notification = data->call_notification;
+ break;
+
default:
return GN_ERR_NOTSUPPORTED;
}
@@ -130,7 +146,7 @@
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);
+ qemu_mod_timer(s->csq_tm, qemu_get_clock(vm_clock) + ticks_per_sec * 50);
}
static void modem_network_register(void *opaque)
@@ -232,6 +248,23 @@
modem_fifo_wake((struct modem_s *) opaque);
}
+static void modem_ring(void *opaque)
+{
+ struct modem_s *s = (struct modem_s *) opaque;
+ gn_call_info call_info;
+
+ if (!s->enable || !s->reg_data || !s->call_notification)
+ return;
+
+ call_info.type = GN_CALL_Voice;
+ snprintf(call_info.number, sizeof(call_info.number), "6100918");
+ snprintf(call_info.name, sizeof(call_info.name), "Red Riding Hood");
+ call_info.send_number = GN_CALL_Always;
+ call_info.call_id = s->next_call_id ++;
+
+ s->call_notification(GN_CALL_Incoming, &call_info, &s->state);
+}
+
CharDriverState *modem_init()
{
struct modem_s *s = (struct modem_s *)
@@ -243,11 +276,12 @@
s->state.info = &s->info;
s->info.write = modem_resp;
- s->info.gn_sm_functions = modem_ops;
+ s->info.gn_sm_functions = modem_gsm_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);
+ s->next_call_id = 1;
if (!gn_atem_initialise(&s->state))
goto fail;
@@ -255,6 +289,11 @@
if (!dp_Initialise())
goto fail;
+ /* If this is the first modem, register it as the one to receive
+ * "modem .." commands. */
+ modem_ops.opaque = s;
+ modem_ops.ring = modem_ring;
+
return &s->chr;
fail:
fprintf(stderr, "%s: GSM modem initialisation failed\n", __FUNCTION__);
Modified: trunk/src/host/qemu-neo1973/monitor.c
===================================================================
--- trunk/src/host/qemu-neo1973/monitor.c 2007-06-23 01:01:43 UTC (rev 2336)
+++ trunk/src/host/qemu-neo1973/monitor.c 2007-06-23 15:16:21 UTC (rev 2337)
@@ -60,6 +60,7 @@
static term_cmd_t term_cmds[];
static term_cmd_t info_cmds[];
+static term_cmd_t modem_cmds[];
static char term_outbuf[1024];
static int term_outbuf_index;
@@ -181,6 +182,8 @@
{
if (name && !strcmp(name, "info")) {
help_cmd1(info_cmds, "info ", NULL);
+ } else if (name && !strcmp(name, "modem")) {
+ help_cmd1(modem_cmds, "modem ", NULL);
} else {
help_cmd1(term_cmds, "", name);
if (name && !strcmp(name, "log")) {
@@ -1198,6 +1201,29 @@
}
#endif
+static void do_modem(const char *item)
+{
+ term_cmd_t *cmd;
+
+ if (!item)
+ goto help;
+ for(cmd = modem_cmds; cmd->name != NULL; cmd++) {
+ if (compare_cmd(item, cmd->name))
+ goto found;
+ }
+ help:
+ help_cmd("modem");
+ return;
+ found:
+ cmd->handler();
+}
+
+static void do_modem_ring(const char *item)
+{
+ if (modem_ops.ring)
+ modem_ops.ring(modem_ops.opaque);
+}
+
static term_cmd_t term_cmds[] = {
{ "help|?", "s?", do_help,
"[cmd]", "show the help" },
@@ -1263,10 +1289,12 @@
"path [frequency bits channels]",
"capture audio to a wave file (default frequency=44100 bits=16 channels=2)" },
#endif
- { "stopcapture", "i", do_stop_capture,
- "capture index", "stop capture" },
+ { "stopcapture", "i", do_stop_capture,
+ "capture index", "stop capture" },
{ "memsave", "lis", do_memory_save,
"addr size file", "save to disk virtual memory dump starting at 'addr' of size 'size'", },
+ { "modem", "s?", do_modem,
+ "subcommand", "cause various actions in the virtual modem", },
{ NULL, NULL, },
};
@@ -1326,6 +1354,12 @@
{ NULL, NULL, },
};
+static term_cmd_t modem_cmds[] = {
+ { "ring", "", do_modem_ring,
+ "", "make the virtual modem output a RING notification" },
+ { NULL, NULL, },
+};
+
/*******************************************************************/
static const char *pch;
@@ -2430,6 +2464,11 @@
for(key = key_defs; key->name != NULL; key++) {
cmd_completion(str, key->name);
}
+ } else if (!strcmp(cmd->name, "modem")) {
+ completion_index = strlen(str);
+ for(cmd = modem_cmds; cmd->name != NULL; cmd++) {
+ cmd_completion(str, cmd->name);
+ }
}
break;
default:
Modified: trunk/src/host/qemu-neo1973/vl.c
===================================================================
--- trunk/src/host/qemu-neo1973/vl.c 2007-06-23 01:01:43 UTC (rev 2336)
+++ trunk/src/host/qemu-neo1973/vl.c 2007-06-23 15:16:21 UTC (rev 2337)
@@ -201,6 +201,7 @@
const char *prom_envs[MAX_PROM_ENVS];
#endif
struct bt_piconet_s *local_piconet;
+struct modem_ops_s modem_ops;
/***********************************************************/
/* x86 ISA bus support */
Modified: trunk/src/host/qemu-neo1973/vl.h
===================================================================
--- trunk/src/host/qemu-neo1973/vl.h 2007-06-23 01:01:43 UTC (rev 2336)
+++ trunk/src/host/qemu-neo1973/vl.h 2007-06-23 15:16:21 UTC (rev 2337)
@@ -1551,6 +1551,10 @@
/* modem.c */
CharDriverState *modem_init();
void modem_enable(CharDriverState *chr, int enable);
+extern struct modem_ops_s {
+ void *opaque;
+ void (*ring)(void *opaque);
+} modem_ops;
/* PCMCIA/Cardbus */
More information about the commitlog
mailing list