light test report for ofono v0.3
by Fu, Elva
Test Environment
-------------------------------
general PC (pre-installed FC11)
- ofono v0.3
- phonesim package
mobile phone (use it as modem)
-------------------------------
Test Scope
-------------------------------
- we mainly focus on checking basic functionality of ofono v0.3 (voice call, sms, phonebook etc.)
- voice call, multiparty call, phonebook, SIM and modem are tested in real network env. For others, we test them through simulator.
- bug verification: verify issues we found in v0.2
-------------------------------
Test Summary
-------------------------------
there are small changes between ofono v0.2 and v0.3. so good test result is expected. :-)
Total 63 test cases were executed during this round of testing.
Pass: 63
Fail: 0
issues we found in v0.2 were fixed already, many thanks!
-------------------------------
Details
-------------------------------
to make it readable, we summarized by feature list. :-)
features checkpoints test results comments
SMS Send/receive pass
Set service center address pass
More recipients pass
More segment pass
Voice call Dial pass
Accept pass
Reject pass
Hold pass
Receive pass
Release pass
Multiparty call Create pass
Hang up pass
Private chat pass
Hold pass
Sim Phonebook Read pass
SS CF pass
CB pass
CW pass
CLIR/CLIP pass
Setting AOC pass
CF/CB pass
GSM string pass
Modem pass
Networking pass
Sim Read IMSI pass
Read MSISDN pass
-------------------------------
Elva
11 years, 4 months
Write state of SMS assembly to disk and restore on startup.
by Andrzej Zaborowski
This way we can continue receiving segmented messages over a reset or
crash.
---
src/common.c | 29 +++++++
src/common.h | 10 +++
src/sim.c | 34 --------
src/sms.c | 14 +++-
src/smsutil.c | 237 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
src/smsutil.h | 3 +-
unit/Makefile.am | 6 +-
unit/test-sms.c | 4 +-
8 files changed, 293 insertions(+), 44 deletions(-)
diff --git a/src/common.c b/src/common.c
index 14bf7f9..e1d560e 100644
--- a/src/common.c
+++ b/src/common.c
@@ -26,6 +26,7 @@
#define _GNU_SOURCE
#include <string.h>
#include <ctype.h>
+#include <errno.h>
#include <glib.h>
@@ -593,3 +594,31 @@ gboolean is_valid_pin(const char *pin)
return TRUE;
}
+
+int create_dirs(const char *filename, const mode_t mode)
+{
+ struct stat st;
+ char *dir;
+ const char *prev, *next;
+ int err;
+
+ err = stat(filename, &st);
+ if (!err && S_ISREG(st.st_mode))
+ return 0;
+
+ dir = g_malloc(strlen(filename) + 1);
+ strcpy(dir, "/");
+
+ for (prev = filename; (next = strchr(prev + 1, '/')); prev = next)
+ if (next > prev + 1) {
+ strncat(dir, prev + 1, next - prev);
+
+ if (mkdir(dir, mode) && errno != EEXIST) {
+ g_free(dir);
+ return -1;
+ }
+ }
+
+ g_free(dir);
+ return 0;
+}
diff --git a/src/common.h b/src/common.h
index 3805e21..18fb0c5 100644
--- a/src/common.h
+++ b/src/common.h
@@ -135,3 +135,13 @@ const char *ss_control_type_to_string(enum ss_control_type type);
const char *bearer_class_to_string(enum bearer_class cls);
gboolean is_valid_pin(const char *pin);
+
+#ifdef TEMP_FAILURE_RETRY
+#define TFR TEMP_FAILURE_RETRY
+#else
+#define TFR
+#endif
+
+#include <fcntl.h>
+
+int create_dirs(const char *filename, const mode_t mode);
diff --git a/src/sim.c b/src/sim.c
index d4387c9..cd608f7 100644
--- a/src/sim.c
+++ b/src/sim.c
@@ -44,12 +44,6 @@
#include "sim.h"
#include "simutil.h"
-#ifdef TEMP_FAILURE_RETRY
-#define TFR TEMP_FAILURE_RETRY
-#else
-#define TFR
-#endif
-
#define SIM_MANAGER_INTERFACE "org.ofono.SimManager"
#define SIM_CACHE_MODE 0600
@@ -515,34 +509,6 @@ static void sim_retrieve_imsi(struct ofono_modem *modem)
sim->ops->read_imsi(modem, sim_imsi_cb, modem);
}
-static int create_dirs(const char *filename, const mode_t mode)
-{
- struct stat st;
- char *dir;
- const char *prev, *next;
- int err;
-
- err = stat(filename, &st);
- if (!err && S_ISREG(st.st_mode))
- return 0;
-
- dir = g_malloc(strlen(filename) + 1);
- strcpy(dir, "/");
-
- for (prev = filename; (next = strchr(prev + 1, '/')); prev = next)
- if (next > prev + 1) {
- strncat(dir, prev + 1, next - prev);
-
- if (mkdir(dir, mode) && errno != EEXIST) {
- g_free(dir);
- return -1;
- }
- }
-
- g_free(dir);
- return 0;
-}
-
static void sim_op_error(struct ofono_modem *modem)
{
struct sim_manager_data *sim = modem->sim_manager;
diff --git a/src/sms.c b/src/sms.c
index c7d83fa..0781f86 100644
--- a/src/sms.c
+++ b/src/sms.c
@@ -72,7 +72,6 @@ static struct sms_manager_data *sms_manager_create()
sms->sca.type = 129;
sms->ref = 1;
- sms->assembly = sms_assembly_new();
sms->txq = g_queue_new();
return sms;
@@ -792,6 +791,14 @@ void ofono_sms_status_notify(struct ofono_modem *modem, unsigned char *pdu,
ofono_error("SMS Status-Report not yet handled");
}
+static void sms_got_imsi(struct ofono_modem *modem)
+{
+ const char *imsi = ofono_sim_get_imsi(modem);
+ struct sms_manager_data *sms = modem->sms_manager;
+
+ sms->assembly = sms_assembly_new(imsi);
+}
+
int ofono_sms_manager_register(struct ofono_modem *modem,
struct ofono_sms_ops *ops)
{
@@ -830,6 +837,11 @@ int ofono_sms_manager_register(struct ofono_modem *modem,
ofono_modem_add_interface(modem, SMS_MANAGER_INTERFACE);
+ if (ofono_sim_get_ready(modem))
+ sms_got_imsi(modem);
+ else
+ ofono_sim_ready_notify_register(modem, sms_got_imsi);
+
return 0;
}
diff --git a/src/smsutil.c b/src/smsutil.c
index fcff9aa..2480d71 100644
--- a/src/smsutil.c
+++ b/src/smsutil.c
@@ -23,11 +23,20 @@
#include <config.h>
#endif
+#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <glib.h>
-
+#include <dirent.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include "driver.h"
+#include "common.h"
#include "util.h"
#include "smsutil.h"
@@ -2106,9 +2115,211 @@ char *sms_decode_text(GSList *sms_list)
return utf8;
}
-struct sms_assembly *sms_assembly_new()
+static int sms_serialize(unsigned char *buf, const struct sms *sms)
+{
+ int len, tpdu_len;
+
+ sms_encode(sms, &len, &tpdu_len, buf + 1);
+ buf[0] = tpdu_len;
+
+ return len;
+}
+
+static gboolean sms_deserialize(const unsigned char *buf,
+ struct sms *sms, int len)
+{
+ if (len < 1)
+ return FALSE;
+
+ return sms_decode(buf + 1, len - 1, FALSE, buf[0], sms);
+}
+
+static GSList *sms_assembly_add_fragment_backup(struct sms_assembly *assembly,
+ const struct sms *sms, time_t ts,
+ const struct sms_address *addr,
+ guint16 ref, guint8 max, guint8 seq,
+ gboolean backup);
+
+#define SMS_BACKUP_MODE 0600
+#define SMS_BACKUP_PATH STORAGEDIR "/%s/sms"
+#define SMS_BACKUP_PATH_DIR SMS_BACKUP_PATH "/%s-%i-%i"
+#define SMS_BACKUP_PATH_FILE SMS_BACKUP_PATH_DIR "/%03i"
+
+#define SMS_ADDR_FMT "%21[0-9+*#]"
+
+static void sms_assembly_load(struct sms_assembly *assembly,
+ const struct dirent *dir)
+{
+ struct sms_address addr;
+ char straddr[sizeof(addr.address) + 1];
+ guint16 ref;
+ guint8 max;
+ guint8 seq;
+ char *path;
+ int len;
+ struct stat segment_stat;
+ struct dirent **segments;
+ char *endp;
+ int fd;
+ int r;
+ unsigned char buf[177];
+ struct sms segment;
+
+ if (dir->d_type != DT_DIR)
+ return;
+
+ if (sscanf(dir->d_name, SMS_ADDR_FMT "-%hi-%hhi",
+ straddr, &ref, &max) < 3)
+ return;
+ sms_address_from_string(&addr, straddr);
+
+ path = g_strdup_printf(SMS_BACKUP_PATH "/%s",
+ assembly->imsi, dir->d_name);
+ len = scandir(path, &segments, NULL, versionsort);
+ g_free(path);
+
+ if (len < 0)
+ return;
+
+ for (; len--; free(segments[len])) {
+ if (segments[len]->d_type != DT_REG)
+ continue;
+
+ seq = strtol(segments[len]->d_name, &endp, 10);
+ if (*endp != '\0')
+ continue;
+
+ path = g_strdup_printf(SMS_BACKUP_PATH "/%s/%s",
+ assembly->imsi,
+ dir->d_name, segments[len]->d_name);
+ fd = TFR(open(path, O_RDONLY));
+ g_free(path);
+
+ if (fd == -1)
+ continue;
+
+ if (fstat(fd, &segment_stat) != 0) {
+ TFR(close(fd));
+ continue;
+ }
+
+ r = TFR(read(fd, buf, sizeof(buf)));
+
+ if (r > 0 && sms_deserialize(buf, &segment, r)) {
+ if (sms_assembly_add_fragment_backup(assembly,
+ &segment,
+ segment_stat.st_mtime,
+ &addr, ref, max, seq, FALSE)) {
+ /* This can't happen */
+ }
+ }
+
+ TFR(close(fd));
+ }
+
+ free(segments);
+}
+
+static gboolean sms_assembly_store(struct sms_assembly *assembly,
+ struct sms_assembly_node *node,
+ const struct sms *sms, guint8 seq)
+{
+ unsigned char buf[177];
+ char *path;
+ int fd;
+ int len;
+
+ if (!assembly->imsi)
+ return;
+
+ len = sms_serialize(buf, sms);
+
+ path = g_strdup_printf(SMS_BACKUP_PATH_FILE, assembly->imsi,
+ sms_address_to_string(&node->addr),
+ node->ref, node->max_fragments, seq);
+
+ if (create_dirs(path, SMS_BACKUP_MODE | S_IXUSR)) {
+ g_free(path);
+ return FALSE;
+ }
+
+ fd = TFR(open(path, O_WRONLY | O_CREAT, SMS_BACKUP_MODE));
+ if (fd == -1) {
+ g_free(path);
+ return FALSE;
+ }
+
+ if (TFR(write(fd, buf, len)) < len) {
+ TFR(close(fd));
+ unlink(path);
+ g_free(path);
+ return FALSE;
+ }
+
+ g_free(path);
+ TFR(close(fd));
+
+ return TRUE;
+}
+
+static void sms_assembly_backup_free(struct sms_assembly *assembly,
+ struct sms_assembly_node *node)
{
- return g_new0(struct sms_assembly, 1);
+ char *path;
+ int seq;
+
+ if (!assembly->imsi)
+ return;
+
+ for (seq = 0; seq < node->max_fragments; seq++) {
+ int offset = seq / 32;
+ int bit = 1 << (seq % 32);
+
+ if (node->bitmap[offset] & bit) {
+ path = g_strdup_printf(SMS_BACKUP_PATH_FILE,
+ assembly->imsi,
+ sms_address_to_string(&node->addr),
+ node->ref, node->max_fragments, seq);
+ unlink(path);
+ g_free(path);
+ }
+ }
+
+ path = g_strdup_printf(SMS_BACKUP_PATH_DIR, assembly->imsi,
+ sms_address_to_string(&node->addr),
+ node->ref, node->max_fragments);
+ unlink(path);
+ g_free(path);
+}
+
+struct sms_assembly *sms_assembly_new(const char *imsi)
+{
+ struct sms_assembly *ret = g_new0(struct sms_assembly, 1);
+ char *path;
+ struct dirent **entries;
+ int len;
+
+ if (imsi) {
+ ret->imsi = imsi;
+
+ /* Restore state from backup */
+
+ path = g_strdup_printf(SMS_BACKUP_PATH, imsi);
+ len = scandir(path, &entries, NULL, alphasort);
+ g_free(path);
+
+ if (len < 0)
+ return ret;
+
+ while (len--) {
+ sms_assembly_load(ret, entries[len]);
+ free(entries[len]);
+ }
+
+ free(entries);
+ }
+
+ return ret;
}
void sms_assembly_free(struct sms_assembly *assembly)
@@ -2132,6 +2343,16 @@ GSList *sms_assembly_add_fragment(struct sms_assembly *assembly,
const struct sms_address *addr,
guint16 ref, guint8 max, guint8 seq)
{
+ sms_assembly_add_fragment_backup(assembly, sms,
+ ts, addr, ref, max, seq, TRUE);
+}
+
+static GSList *sms_assembly_add_fragment_backup(struct sms_assembly *assembly,
+ const struct sms *sms, time_t ts,
+ const struct sms_address *addr,
+ guint16 ref, guint8 max, guint8 seq,
+ gboolean backup)
+{
int offset = seq / 32;
int bit = 1 << (seq % 32);
GSList *l;
@@ -2205,11 +2426,17 @@ out:
node->bitmap[offset] |= bit;
node->num_fragments += 1;
- if (node->num_fragments < node->max_fragments)
+ if (node->num_fragments < node->max_fragments) {
+ if (backup)
+ sms_assembly_store(assembly, node, sms, seq);
+
return NULL;
+ }
completed = node->fragment_list;
+ sms_assembly_backup_free(assembly, node);
+
if (prev)
prev->next = l->next;
else
@@ -2243,6 +2470,8 @@ void sms_assembly_expire(struct sms_assembly *assembly, time_t before)
continue;
}
+ sms_assembly_backup_free(assembly, node);
+
g_slist_foreach(node->fragment_list, (GFunc)g_free, 0);
g_slist_free(node->fragment_list);
g_free(node);
diff --git a/src/smsutil.h b/src/smsutil.h
index 95d0c78..f6541b6 100644
--- a/src/smsutil.h
+++ b/src/smsutil.h
@@ -360,6 +360,7 @@ struct sms_assembly_node {
};
struct sms_assembly {
+ const char *imsi;
GSList *assembly_list;
};
@@ -454,7 +455,7 @@ gboolean sms_extract_concatenation(const struct sms *sms, guint16 *ref_num,
unsigned char *sms_decode_datagram(GSList *sms_list, long *out_len);
char *sms_decode_text(GSList *sms_list);
-struct sms_assembly *sms_assembly_new();
+struct sms_assembly *sms_assembly_new(const char *imsi);
void sms_assembly_free(struct sms_assembly *assembly);
GSList *sms_assembly_add_fragment(struct sms_assembly *assembly,
const struct sms *sms, time_t ts,
diff --git a/unit/Makefile.am b/unit/Makefile.am
index 8a27267..74d0f40 100644
--- a/unit/Makefile.am
+++ b/unit/Makefile.am
@@ -6,11 +6,13 @@ test_common_SOURCES = test-common.c $(top_srcdir)/src/common.c
test_util_SOURCES = test-util.c $(top_srcdir)/src/util.c
test_sms_SOURCES = test-sms.c $(top_srcdir)/src/util.c \
- $(top_srcdir)/src/smsutil.c
+ $(top_srcdir)/src/smsutil.c \
+ $(top_srcdir)/src/common.c
test_simutil_SOURCES = test-simutil.c $(top_srcdir)/src/util.c \
$(top_srcdir)/src/simutil.c \
- $(top_srcdir)/src/smsutil.c
+ $(top_srcdir)/src/smsutil.c \
+ $(top_srcdir)/src/common.c
LDADD = @GLIB_LIBS@ @GTHREAD_LIBS@
diff --git a/unit/test-sms.c b/unit/test-sms.c
index 52d6859..a94cd4b 100644
--- a/unit/test-sms.c
+++ b/unit/test-sms.c
@@ -619,7 +619,7 @@ static void test_assembly()
unsigned char pdu[164];
long pdu_len;
struct sms sms;
- struct sms_assembly *assembly = sms_assembly_new();
+ struct sms_assembly *assembly = sms_assembly_new(NULL);
guint16 ref;
guint8 max;
guint8 seq;
@@ -776,7 +776,7 @@ static void test_prepare_concat()
struct sms *sms;
struct sms decoded;
int pdu_len, tpdu_len;
- struct sms_assembly *assembly = sms_assembly_new();
+ struct sms_assembly *assembly = sms_assembly_new(NULL);
guint16 ref;
guint8 max;
guint8 seq;
--
1.6.1
11 years, 5 months
Read messages left over in ME storage on startup.
by Andrzej Zaborowski
On modems that don't support +CMT (or for class 2 SMSes) the messages are
stored in the modem and then read and deleted from there in two separate
steps with no warranty that deletion succeeds or (more likely) power is
cut before the deletion happens. Over time the memory may become full
and if we don't want to deal with this condition we need to check on
startup if there are messages we haven't deleted.
We can't differentiate between those messages and those the user already
had on the SIM / modem before installing ofono or switching phones, so we
might want to deliver messages with REC READ status with some kind of
indication that these are potentially old so the UI doesn't emit spurious
alerts. We don't do this now and just deliver as usual.
---
drivers/atmodem/sms.c | 128 +++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 128 insertions(+), 0 deletions(-)
diff --git a/drivers/atmodem/sms.c b/drivers/atmodem/sms.c
index 39cc718..ce78e9a 100644
--- a/drivers/atmodem/sms.c
+++ b/drivers/atmodem/sms.c
@@ -47,10 +47,12 @@ static const char *cmgf_prefix[] = { "+CMGF:", NULL };
static const char *cpms_prefix[] = { "+CPMS:", NULL };
static const char *cnmi_prefix[] = { "+CNMI:", NULL };
static const char *cmgs_prefix[] = { "+CMGS:", NULL };
+static const char *cmgl_prefix[] = { "+CMGL:", NULL };
static const char *none_prefix[] = { NULL };
static gboolean set_cmgf(gpointer user_data);
static gboolean set_cpms(gpointer user_data);
+static void at_cmgl_set_cpms(struct ofono_modem *modem, int store);
#define MAX_CMGF_RETRIES 10
#define MAX_CPMS_RETRIES 10
@@ -515,6 +517,126 @@ err:
ofono_error("Unable to parse CMTI notification");
}
+static void at_cmgl_done(struct ofono_modem *modem)
+{
+ struct at_data *at = ofono_modem_get_userdata(modem);
+
+ if (at->sms->incoming == MT_STORE &&
+ at->sms->store == ME_STORE)
+ at_cmgl_set_cpms(modem, SM_STORE);
+}
+
+static void at_cmgl_cb(gboolean ok, GAtResult *result, gpointer user_data)
+{
+ struct ofono_modem *modem = user_data;
+ struct at_data *at = ofono_modem_get_userdata(modem);
+ GAtResultIter iter;
+ const char *hexpdu;
+ unsigned char pdu[164];
+ long pdu_len;
+ int tpdu_len;
+ int index;
+ int status;
+ char buf[16];
+
+ dump_response("at_cmgl_cb", ok, result);
+
+ if (!ok) {
+ ofono_error("Initial listing SMS storage failed!");
+ goto err;
+ }
+
+ g_at_result_iter_init(&iter, result);
+
+ while (g_at_result_iter_next(&iter, "+CMGL:")) {
+ if (!g_at_result_iter_next_number(&iter, &index)) {
+ ofono_error("Unable to parse CMGL response");
+ goto err;
+ }
+
+ if (!g_at_result_iter_next_number(&iter, &status)) {
+ ofono_error("Unable to parse CMGL response");
+ goto err;
+ }
+
+ if (!g_at_result_iter_skip_next(&iter)) {
+ ofono_error("Unable to parse CMGL response");
+ goto err;
+ }
+
+ if (!g_at_result_iter_next_number(&iter, &tpdu_len)) {
+ ofono_error("Unable to parse CMGL response");
+ goto err;
+ }
+
+ /* Only MT messages */
+ if (status != 0 && status != 1)
+ continue;
+
+ hexpdu = g_at_result_pdu(result);
+
+ ofono_debug("Found an old SMS PDU: %s, with len: %d",
+ hexpdu, tpdu_len);
+
+ decode_hex_own_buf(hexpdu, -1, &pdu_len, 0, pdu);
+ ofono_sms_deliver_notify(modem, pdu, pdu_len, tpdu_len);
+
+ /* We don't buffer SMS on the SIM/ME, send along a CMGD */
+ sprintf(buf, "AT+CMGD=%d", index);
+ g_at_chat_send(at->parser, buf, none_prefix,
+ at_cmgd_cb, NULL, NULL);
+ }
+
+err:
+ at_cmgl_done(modem);
+}
+
+static void at_cmgl_cpms_cb(gboolean ok, GAtResult *result, gpointer user_data)
+{
+ struct cpms_request *req = user_data;
+ struct ofono_modem *modem = req->modem;
+ struct at_data *at = ofono_modem_get_userdata(modem);
+
+ if (!ok) {
+ ofono_error("Initial CPMS request failed");
+ at_cmgl_done(modem);
+ return;
+ }
+
+ at->sms->store = req->store;
+
+ g_at_chat_send(at->parser, "AT+CMGL=4", cmgl_prefix,
+ at_cmgl_cb, modem, NULL);
+}
+
+static void at_cmgl_set_cpms(struct ofono_modem *modem, int store)
+{
+ struct at_data *at = ofono_modem_get_userdata(modem);
+
+ if (store == at->sms->store) {
+ struct cpms_request req;
+
+ req.modem = modem;
+ req.store = store;
+
+ at_cmgl_cpms_cb(TRUE, NULL, &req);
+ } else {
+ char buf[128];
+ const char *readwrite = storages[store];
+ const char *incoming = storages[at->sms->incoming];
+ struct cpms_request *req = g_new(struct cpms_request, 1);
+
+ req->modem = modem;
+ req->store = store;
+
+ sprintf(buf, "AT+CPMS=\"%s\",\"%s\",\"%s\"",
+ readwrite, readwrite, incoming);
+
+ g_at_chat_send(at->parser, buf, cpms_prefix, at_cmgl_cpms_cb,
+ req, g_free);
+ }
+}
+
static void at_sms_initialized(struct ofono_modem *modem)
{
struct at_data *at = ofono_modem_get_userdata(modem);
@@ -533,6 +655,12 @@ static void at_sms_initialized(struct ofono_modem *modem)
modem, NULL);
ofono_sms_manager_register(modem, &ops);
+
+ /* Inspect and free the incoming SMS storage */
+ if (at->sms->incoming == MT_STORE)
+ at_cmgl_set_cpms(modem, ME_STORE);
+ else
+ at_cmgl_set_cpms(modem, at->sms->incoming);
}
static void at_sms_not_supported(struct ofono_modem *modem)
--
1.6.1
11 years, 5 months
[PATCH 3/3] G1: Add G1-specific SMS support
by Andres Salomon
This is based on the atmodem SMS code, with lots of stuff dropped.
The G1's modem advertises support for CNMI mode 2, but attempting to
set that actually fails. Instead, we _need_ to use mode 1. Along
those lines, CNMA doesn't appear to work properly, so we disable it
and use CMTI rather than CMT for PDUs. CDS notifications (for status
notifications) are disabled completely.
---
Makefile.am | 3 +-
plugins/g1.c | 7 +-
plugins/g1sms.c | 554 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
plugins/g1sms.h | 29 +++
4 files changed, 591 insertions(+), 2 deletions(-)
create mode 100644 plugins/g1sms.c
create mode 100644 plugins/g1sms.h
diff --git a/Makefile.am b/Makefile.am
index a2d3569..72997c1 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -80,7 +80,8 @@ endif
if G1MODEM
builtin_modules += g1
-builtin_sources += plugins/g1.c
+builtin_sources += plugins/g1.c \
+ plugins/g1sms.c
endif
if MAINTAINER_MODE
diff --git a/plugins/g1.c b/plugins/g1.c
index b0208bc..5d7c279 100644
--- a/plugins/g1.c
+++ b/plugins/g1.c
@@ -33,6 +33,7 @@
#include <glib.h>
#include <gatchat.h>
+#include "g1sms.h"
#define OFONO_API_SUBJECT_TO_CHANGE
#include <ofono/plugin.h>
@@ -334,7 +335,7 @@ static int g1_populate(struct ofono_modem *modem)
ofono_call_meter_create(modem, "generic_at", chat);
ofono_call_barring_create(modem, "generic_at", chat);
ofono_ssn_create(modem, "generic_at", chat);
- ofono_sms_create(modem, "generic_at", chat);
+ ofono_sms_create(modem, "HTC G1", chat);
ofono_phonebook_create(modem, "generic_at", chat);
mw = ofono_message_waiting_create(modem);
@@ -357,6 +358,8 @@ static int g1_init(void)
{
int err;
+ g1_sms_init();
+
err = ofono_modem_driver_register(&g1_driver);
if (err)
goto done;
@@ -385,6 +388,8 @@ static void g1_exit(void)
{
ofono_modem_remove(g1_modem);
ofono_modem_driver_unregister(&g1_driver);
+
+ g1_sms_exit();
}
OFONO_PLUGIN_DEFINE(g1, "HTC G1 modem driver", VERSION,
diff --git a/plugins/g1sms.c b/plugins/g1sms.c
new file mode 100644
index 0000000..617bb6a
--- /dev/null
+++ b/plugins/g1sms.c
@@ -0,0 +1,554 @@
+/*
+ *
+ * oFono - Open Source Telephony
+ *
+ * Copyright (C) 2008-2009 Intel Corporation. All rights reserved.
+ * Copyright (C) 2009 Collabora Ltd. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define _GNU_SOURCE
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <glib.h>
+
+#include <ofono/log.h>
+#include <ofono/modem.h>
+#include <ofono/sms.h>
+#include "smsutil.h"
+#include "util.h"
+
+#include "gatchat.h"
+#include "gatresult.h"
+
+#include "drivers/atmodem/at.h"
+
+static const char *csca_prefix[] = { "+CSCA:", NULL };
+static const char *csms_prefix[] = { "+CSMS:", NULL };
+static const char *cmgf_prefix[] = { "+CMGF:", NULL };
+static const char *cpms_prefix[] = { "+CPMS:", NULL };
+static const char *cnmi_prefix[] = { "+CNMI:", NULL };
+static const char *cmgs_prefix[] = { "+CMGS:", NULL };
+static const char *none_prefix[] = { NULL };
+
+static const char *storages[] = {
+ "SM",
+ "ME",
+ "MT",
+};
+
+#define SM_STORE 0
+#define ME_STORE 1
+#define MT_STORE 2
+
+struct sms_data {
+ int store;
+ int incoming;
+ GAtChat *chat;
+};
+
+struct cpms_request {
+ struct ofono_sms *sms;
+ int store;
+ int index;
+};
+
+static void at_csca_set_cb(gboolean ok, GAtResult *result, gpointer user_data)
+{
+ struct cb_data *cbd = user_data;
+ ofono_sms_sca_set_cb_t cb = cbd->cb;
+ struct ofono_error error;
+
+ dump_response("csca_set_cb", ok, result);
+ decode_at_error(&error, g_at_result_final_response(result));
+
+ cb(&error, cbd->data);
+}
+
+static void at_csca_set(struct ofono_sms *sms,
+ const struct ofono_phone_number *sca,
+ ofono_sms_sca_set_cb_t cb, void *user_data)
+{
+ struct sms_data *data = ofono_sms_get_data(sms);
+ struct cb_data *cbd = cb_data_new(cb, user_data);
+ char buf[64];
+
+ if (!cbd)
+ goto error;
+
+ sprintf(buf, "AT+CSCA=\"%s\",%d", sca->number, sca->type);
+
+ if (g_at_chat_send(data->chat, buf, csca_prefix,
+ at_csca_set_cb, cbd, g_free) > 0)
+ return;
+
+error:
+ if (cbd)
+ g_free(cbd);
+
+ {
+ DECLARE_FAILURE(error);
+ cb(&error, user_data);
+ }
+}
+
+static void at_csca_query_cb(gboolean ok, GAtResult *result, gpointer user_data)
+{
+ struct cb_data *cbd = user_data;
+ GAtResultIter iter;
+ ofono_sms_sca_query_cb_t cb = cbd->cb;
+ struct ofono_error error;
+ struct ofono_phone_number sca;
+ const char *number;
+
+ dump_response("at_csca_cb", ok, result);
+ decode_at_error(&error, g_at_result_final_response(result));
+
+ if (!ok) {
+ cb(&error, NULL, cbd->data);
+ return;
+ }
+
+ g_at_result_iter_init(&iter, result);
+
+ if (!g_at_result_iter_next(&iter, "+CSCA:"))
+ goto err;
+
+ if (!g_at_result_iter_next_string(&iter, &number))
+ goto err;
+
+ if (number[0] == '+') {
+ number = number + 1;
+ sca.type = 145;
+ } else
+ sca.type = 129;
+
+ strncpy(sca.number, number, OFONO_MAX_PHONE_NUMBER_LENGTH);
+ sca.number[OFONO_MAX_PHONE_NUMBER_LENGTH] = '\0';
+
+ g_at_result_iter_next_number(&iter, &sca.type);
+
+ ofono_debug("csca_query_cb: %s, %d", sca.number, sca.type);
+
+ cb(&error, &sca, cbd->data);
+
+ return;
+
+err:
+ {
+ DECLARE_FAILURE(error);
+ cb(&error, NULL, cbd->data);
+ }
+}
+
+static void at_csca_query(struct ofono_sms *sms, ofono_sms_sca_query_cb_t cb,
+ void *user_data)
+{
+ struct sms_data *data = ofono_sms_get_data(sms);
+ struct cb_data *cbd = cb_data_new(cb, user_data);
+
+ if (!cbd)
+ goto error;
+
+ if (g_at_chat_send(data->chat, "AT+CSCA?", csca_prefix,
+ at_csca_query_cb, cbd, g_free) > 0)
+ return;
+
+error:
+ if (cbd)
+ g_free(cbd);
+
+ {
+ DECLARE_FAILURE(error);
+ cb(&error, NULL, user_data);
+ }
+}
+
+static void at_cmgs_cb(gboolean ok, GAtResult *result, gpointer user_data)
+{
+ struct cb_data *cbd = user_data;
+ GAtResultIter iter;
+ ofono_sms_submit_cb_t cb = cbd->cb;
+ struct ofono_error error;
+ int mr;
+
+ dump_response("at_cmgs_cb", ok, result);
+ decode_at_error(&error, g_at_result_final_response(result));
+
+ if (!ok) {
+ cb(&error, -1, cbd->data);
+ return;
+ }
+
+ g_at_result_iter_init(&iter, result);
+
+ if (!g_at_result_iter_next(&iter, "+CMGS:"))
+ goto err;
+
+ if (!g_at_result_iter_next_number(&iter, &mr))
+ goto err;
+
+ ofono_debug("Got MR: %d", mr);
+
+ cb(&error, mr, cbd->data);
+ return;
+
+err:
+ {
+ DECLARE_FAILURE(error);
+ cb(&error, -1, cbd->data);
+ }
+}
+
+static void at_cmgs(struct ofono_sms *sms, unsigned char *pdu, int pdu_len,
+ int tpdu_len, int mms, ofono_sms_submit_cb_t cb,
+ void *user_data)
+{
+ struct sms_data *data = ofono_sms_get_data(sms);
+ struct cb_data *cbd = cb_data_new(cb, user_data);
+ char buf[512];
+ int len;
+
+ if (!cbd)
+ goto error;
+
+ if (mms) {
+ sprintf(buf, "AT+CMMS=%d", mms);
+ g_at_chat_send(data->chat, buf, none_prefix,
+ NULL, NULL, NULL);
+ }
+
+ len = sprintf(buf, "AT+CMGS=%d\r", tpdu_len);
+ encode_hex_own_buf(pdu, pdu_len, 0, buf+len);
+
+ if (g_at_chat_send(data->chat, buf, cmgs_prefix,
+ at_cmgs_cb, cbd, g_free) > 0)
+ return;
+
+error:
+ if (cbd)
+ g_free(cbd);
+
+ {
+ DECLARE_FAILURE(error);
+ cb(&error, -1, user_data);
+ }
+}
+
+static gboolean at_parse_pdu_common(GAtResult *result, const char *prefix,
+ const char **pdu, int *pdulen)
+{
+ GAtResultIter iter;
+
+ g_at_result_iter_init(&iter, result);
+
+ if (!g_at_result_iter_next(&iter, prefix))
+ return FALSE;
+
+ if (!strcmp(prefix, "+CMT:") && !g_at_result_iter_skip_next(&iter))
+ return FALSE;
+
+ if (!g_at_result_iter_next_number(&iter, pdulen))
+ return FALSE;
+
+ *pdu = g_at_result_pdu(result);
+
+ return TRUE;
+}
+
+static void at_cbm_notify(GAtResult *result, gpointer user_data)
+{
+ int pdulen;
+ const char *pdu;
+
+ dump_response("at_cbm_notify", TRUE, result);
+
+ if (!at_parse_pdu_common(result, "+CBM:", &pdu, &pdulen)) {
+ ofono_error("Unable to parse CBM notification");
+ return;
+ }
+
+ ofono_debug("Got new Cell Broadcast via CBM: %s, %d", pdu, pdulen);
+}
+
+static void at_cmgr_notify(GAtResult *result, gpointer user_data)
+{
+ struct ofono_sms *sms = user_data;
+ GAtResultIter iter;
+ const char *hexpdu;
+ unsigned char pdu[164];
+ long pdu_len;
+ int tpdu_len;
+
+ dump_response("at_cmgr_notify", TRUE, result);
+
+ g_at_result_iter_init(&iter, result);
+
+ if (!g_at_result_iter_next(&iter, "+CMGR:"))
+ goto err;
+
+ if (!g_at_result_iter_skip_next(&iter))
+ goto err;
+
+ if (!g_at_result_iter_skip_next(&iter))
+ goto err;
+
+ if (!g_at_result_iter_next_number(&iter, &tpdu_len))
+ goto err;
+
+ hexpdu = g_at_result_pdu(result);
+
+ ofono_debug("Got PDU: %s, with len: %d", hexpdu, tpdu_len);
+
+ decode_hex_own_buf(hexpdu, -1, &pdu_len, 0, pdu);
+ ofono_sms_deliver_notify(sms, pdu, pdu_len, tpdu_len);
+ return;
+
+err:
+ ofono_error("Unable to parse CMGR response");
+}
+
+static void at_cmgr_cb(gboolean ok, GAtResult *result, gpointer user_data)
+{
+ if (!ok)
+ ofono_error("Received a CMTI indication but CMGR failed!");
+}
+
+static void at_cmgd_cb(gboolean ok, GAtResult *result, gpointer user_data)
+{
+ if (!ok)
+ ofono_error("Unable to delete received SMS");
+}
+
+static void at_cmti_cpms_cb(gboolean ok, GAtResult *result, gpointer user_data)
+{
+ struct cpms_request *req = user_data;
+ struct ofono_sms *sms = req->sms;
+ struct sms_data *data = ofono_sms_get_data(sms);
+ char buf[128];
+
+ if (!ok) {
+ ofono_error("Received CMTI, but CPMS request failed");
+ return;
+ }
+
+ data->store = req->store;
+
+ sprintf(buf, "AT+CMGR=%d", req->index);
+ g_at_chat_send(data->chat, buf, none_prefix, at_cmgr_cb, NULL, NULL);
+
+ /* We don't buffer SMS on the SIM/ME, send along a CMGD as well */
+ sprintf(buf, "AT+CMGD=%d", req->index);
+ g_at_chat_send(data->chat, buf, none_prefix, at_cmgd_cb, NULL, NULL);
+}
+
+static void at_cmti_notify(GAtResult *result, gpointer user_data)
+{
+ struct ofono_sms *sms = user_data;
+ struct sms_data *data = ofono_sms_get_data(sms);
+ const char *strstore;
+ int store;
+ GAtResultIter iter;
+ int index;
+
+ dump_response("at_cmti_notify", TRUE, result);
+
+ g_at_result_iter_init(&iter, result);
+
+ if (!g_at_result_iter_next(&iter, "+CMTI:"))
+ goto err;
+
+ if (!g_at_result_iter_next_string(&iter, &strstore))
+ goto err;
+
+ if (!strcmp(strstore, "ME"))
+ store = ME_STORE;
+ else if (!strcmp(strstore, "SM"))
+ store = SM_STORE;
+ else
+ goto err;
+
+ if (!g_at_result_iter_next_number(&iter, &index))
+ goto err;
+
+ ofono_debug("Got a CMTI indication at %s, index: %d", strstore, index);
+
+ if (store == data->store) {
+ struct cpms_request req;
+
+ req.sms = sms;
+ req.store = store;
+ req.index = index;
+
+ at_cmti_cpms_cb(TRUE, NULL, &req);
+ } else {
+ char buf[128];
+ const char *incoming = storages[data->incoming];
+ struct cpms_request *req = g_new(struct cpms_request, 1);
+
+ req->sms = sms;
+ req->store = store;
+ req->index = index;
+
+ sprintf(buf, "AT+CPMS=\"%s\",\"%s\",\"%s\"",
+ strstore, strstore, incoming);
+
+ g_at_chat_send(data->chat, buf, cpms_prefix, at_cmti_cpms_cb,
+ req, g_free);
+ }
+
+ return;
+
+err:
+ ofono_error("Unable to parse CMTI notification");
+}
+
+static void at_sms_initialized(struct ofono_sms *sms)
+{
+ struct sms_data *data = ofono_sms_get_data(sms);
+
+ g_at_chat_register(data->chat, "+CMTI:", at_cmti_notify, FALSE,
+ sms, NULL);
+ g_at_chat_register(data->chat, "+CBM:", at_cbm_notify, TRUE,
+ sms, NULL);
+
+ /* We treat CMGR just like a notification */
+ g_at_chat_register(data->chat, "+CMGR:", at_cmgr_notify, TRUE,
+ sms, NULL);
+
+ ofono_sms_register(sms);
+}
+
+static void at_sms_not_supported(struct ofono_sms *sms)
+{
+ ofono_error("SMS not supported by this modem. If this is in error"
+ " please submit patches to support this hardware");
+
+ ofono_sms_remove(sms);
+}
+
+static void at_cnmi_set_cb(gboolean ok, GAtResult *result, gpointer user_data)
+{
+ struct ofono_sms *sms = user_data;
+
+ if (!ok)
+ return at_sms_not_supported(sms);
+
+ at_sms_initialized(sms);
+}
+
+static void at_cpms_set_cb(gboolean ok, GAtResult *result, gpointer user_data)
+{
+ struct ofono_sms *sms = user_data;
+ struct sms_data *data = ofono_sms_get_data(sms);
+
+ dump_response("at_cpms_set_cb", ok, result);
+ if (!ok) {
+ at_sms_not_supported(sms);
+ return;
+ }
+
+ /* the G1 is very particular about CNMI; mode 1 is required */
+ g_at_chat_send(data->chat, "AT+CNMI=1,1,2,0,1", cnmi_prefix,
+ at_cnmi_set_cb, sms, NULL);
+}
+
+static void at_cmgf_set_cb(gboolean ok, GAtResult *result, gpointer user_data)
+{
+ struct ofono_sms *sms = user_data;
+ struct sms_data *data = ofono_sms_get_data(sms);
+
+ dump_response("at_cmgf_set_cb", ok, result);
+
+ if (!ok) {
+ at_sms_not_supported(sms);
+ return;
+ }
+
+ g_at_chat_send(data->chat, "AT+CPMS=\"ME\",\"ME\",\"ME\"", cpms_prefix,
+ at_cpms_set_cb, sms, NULL);
+}
+
+static void at_csms_set_cb(gboolean ok, GAtResult *result,
+ gpointer user_data)
+{
+ struct ofono_sms *sms = user_data;
+ struct sms_data *data = ofono_sms_get_data(sms);
+
+ dump_response("at_csms_set_cb", ok, result);
+
+ if (!ok) {
+ at_sms_not_supported(sms);
+ return;
+ }
+
+ /* use ME for everything */
+ data->store = ME_STORE;
+ data->incoming = ME_STORE;
+
+ g_at_chat_send(data->chat, "AT+CMGF=0", cmgf_prefix,
+ at_cmgf_set_cb, sms, NULL);
+}
+
+static int at_sms_probe(struct ofono_sms *sms)
+{
+ GAtChat *chat = ofono_sms_get_data(sms);
+ struct sms_data *data;
+
+ data = g_new0(struct sms_data, 1);
+ data->chat = chat;
+
+ ofono_sms_set_data(sms, data);
+
+ g_at_chat_send(data->chat, "AT+CSMS=0", csms_prefix,
+ at_csms_set_cb, sms, NULL);
+
+ return 0;
+}
+
+static int at_sms_remove(struct ofono_sms *sms)
+{
+ struct sms_data *data = ofono_sms_get_data(sms);
+
+ g_free(data);
+
+ return 0;
+}
+
+static struct ofono_sms_driver g1_driver = {
+ .name = "HTC G1",
+ .probe = at_sms_probe,
+ .remove = at_sms_remove,
+ .sca_query = at_csca_query,
+ .sca_set = at_csca_set,
+ .submit = at_cmgs,
+};
+
+void g1_sms_init()
+{
+ ofono_sms_driver_register(&g1_driver);
+}
+
+void g1_sms_exit()
+{
+ ofono_sms_driver_unregister(&g1_driver);
+}
diff --git a/plugins/g1sms.h b/plugins/g1sms.h
new file mode 100644
index 0000000..482ce61
--- /dev/null
+++ b/plugins/g1sms.h
@@ -0,0 +1,29 @@
+/*
+ *
+ * oFono - Open Source Telephony
+ *
+ * Copyright (C) 2008-2009 Intel Corporation. All rights reserved.
+ * Copyright (C) 2009 Collabora Ltd. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef __G1SMS_H
+#define __G1SMS_H
+
+extern void g1_sms_init(void);
+extern void g1_sms_exit(void);
+
+#endif
--
1.6.3.3
11 years, 5 months
[PATCH 2/3] G1: Add a G1 syntax for parsing
by Andres Salomon
This is based on the generic_at parser, with unnecessary stuff removed.
The G1 routinely screws up CRLFs, so the parser needs to account for
that. This parser ignores leading CRLFs (which is what reference-ril
does as well), as well as trailing LFs (which are sometimes left out).
CRs are used as end-of-message indicators. Since we're not bothering
tracking CRLFs, there's also no need for a GARBAGE state, or MULTILINE
stuff.
---
plugins/g1.c | 87 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 85 insertions(+), 2 deletions(-)
diff --git a/plugins/g1.c b/plugins/g1.c
index 70e4914..b0208bc 100644
--- a/plugins/g1.c
+++ b/plugins/g1.c
@@ -33,7 +33,6 @@
#include <glib.h>
#include <gatchat.h>
-#include <gatsyntax.h>
#define OFONO_API_SUBJECT_TO_CHANGE
#include <ofono/plugin.h>
@@ -62,6 +61,90 @@ struct g1_data {
GIOChannel *io;
};
+/* Supply our own syntax parser */
+
+enum G1_STATE_ {
+ G1_STATE_IDLE = 0,
+ G1_STATE_RESPONSE,
+ G1_STATE_GUESS_PDU,
+ G1_STATE_PDU,
+ G1_STATE_PROMPT,
+};
+
+static void g1_hint(GAtSyntax *syntax, GAtSyntaxExpectHint hint)
+{
+ if (hint == G_AT_SYNTAX_EXPECT_PDU)
+ syntax->state = G1_STATE_GUESS_PDU;
+}
+
+static GAtSyntaxResult g1_feed(GAtSyntax *syntax,
+ const char *bytes, gsize *len)
+{
+ gsize i = 0;
+ GAtSyntaxResult res = G_AT_SYNTAX_RESULT_UNSURE;
+
+ while (i < *len) {
+ char byte = bytes[i];
+
+ switch (syntax->state) {
+ case G1_STATE_IDLE:
+ if (byte == '\r' || byte == '\n')
+ /* ignore */;
+ else if (byte == '>')
+ syntax->state = G1_STATE_PROMPT;
+ else
+ syntax->state = G1_STATE_RESPONSE;
+ break;
+
+ case G1_STATE_RESPONSE:
+ if (byte == '\r') {
+ syntax->state = G1_STATE_IDLE;
+
+ i += 1;
+ res = G_AT_SYNTAX_RESULT_LINE;
+ goto out;
+ }
+ break;
+
+ case G1_STATE_GUESS_PDU:
+ /* keep going until we find a LF that leads the PDU */
+ if (byte == '\n')
+ syntax->state = G1_STATE_PDU;
+ break;
+
+ case G1_STATE_PDU:
+ if (byte == '\r') {
+ syntax->state = G1_STATE_IDLE;
+
+ i += 1;
+ res = G_AT_SYNTAX_RESULT_PDU;
+ goto out;
+ }
+ break;
+
+ case G1_STATE_PROMPT:
+ if (byte == ' ') {
+ syntax->state = G1_STATE_IDLE;
+ i += 1;
+ res = G_AT_SYNTAX_RESULT_PROMPT;
+ goto out;
+ }
+
+ syntax->state = G1_STATE_RESPONSE;
+ return G_AT_SYNTAX_RESULT_UNSURE;
+
+ default:
+ break;
+ };
+
+ i += 1;
+ }
+
+out:
+ *len = i;
+ return res;
+}
+
static void connect_destroy(gpointer user)
{
struct ofono_modem *modem = user;
@@ -102,7 +185,7 @@ static gboolean connect_cb(GIOChannel *io, GIOCondition cond, gpointer user)
if (success == FALSE)
goto error;
- syntax = g_at_syntax_new_gsmv1();
+ syntax = g_at_syntax_new_full(g1_feed, g1_hint, G1_STATE_IDLE);
d->chat = g_at_chat_new(io, syntax);
g_at_syntax_unref(syntax);
--
1.6.3.3
11 years, 5 months
[PATCH 1/3] G1: Add initial HTC G1 modem support
by Andres Salomon
This series adds support for the HTC G1 phone (that is, the Google
phone).
G1 plugin is based on generic_at, with a bunch of stuff dropped
and simplified. We use AT+CFUN=1 for powering on rather than having
a configurable init string. We also manually set the default state
during init (the G1 appears to start in mode V0 by default). The
device (/dev/smd0) is hardcoded.
---
Makefile.am | 5 +
configure.ac | 8 ++-
plugins/g1.c | 309 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 321 insertions(+), 1 deletions(-)
create mode 100644 plugins/g1.c
diff --git a/Makefile.am b/Makefile.am
index 7ee6536..a2d3569 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -78,6 +78,11 @@ builtin_modules += generic_at
builtin_sources += plugins/generic_at.c
endif
+if G1MODEM
+builtin_modules += g1
+builtin_sources += plugins/g1.c
+endif
+
if MAINTAINER_MODE
builtin_modules += example_history
builtin_sources += plugins/example_history.c
diff --git a/configure.ac b/configure.ac
index a299a13..5deabb8 100644
--- a/configure.ac
+++ b/configure.ac
@@ -65,10 +65,16 @@ AC_ARG_ENABLE(isimodem, AC_HELP_STRING([--disable-isimodem],
[enable_isimodem=${enableval}])
AM_CONDITIONAL(ISIMODEM, test "${enable_isimodem}" != "no")
+AC_ARG_ENABLE(g1, AC_HELP_STRING([--disable-g1],
+ [disable HTC G1 modem support]),
+ [enable_g1=${enableval}])
+AM_CONDITIONAL(G1MODEM, test "${enable_g1}" != "no")
+
AC_ARG_ENABLE(atmodem, AC_HELP_STRING([--disable-atmodem],
[disable ETSI AT modem support]),
[enable_atmodem=${enableval}])
-AM_CONDITIONAL(ATMODEM, test "${enable_atmodem}" != "no")
+AM_CONDITIONAL(ATMODEM, [test "${enable_atmodem}" != "no" ||
+ test "${enable_g1}" != "no"])
AC_CHECK_LIB(dl, dlopen, dummy=yes,
AC_MSG_ERROR(dynamic linking loader is required))
diff --git a/plugins/g1.c b/plugins/g1.c
new file mode 100644
index 0000000..70e4914
--- /dev/null
+++ b/plugins/g1.c
@@ -0,0 +1,309 @@
+/*
+ * oFono - Open Source Telephony
+ *
+ * Copyright (C) 2008-2009 Intel Corporation. All rights reserved.
+ * Copyright (C) 2009 Collabora Ltd. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <sys/socket.h>
+#include <termios.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include <glib.h>
+#include <gatchat.h>
+#include <gatsyntax.h>
+
+#define OFONO_API_SUBJECT_TO_CHANGE
+#include <ofono/plugin.h>
+#include <ofono/log.h>
+#include <ofono/modem.h>
+#include <ofono/call-barring.h>
+#include <ofono/call-forwarding.h>
+#include <ofono/call-meter.h>
+#include <ofono/call-settings.h>
+#include <ofono/devinfo.h>
+#include <ofono/message-waiting.h>
+#include <ofono/netreg.h>
+#include <ofono/phonebook.h>
+#include <ofono/sim.h>
+#include <ofono/sms.h>
+#include <ofono/ssn.h>
+#include <ofono/ussd.h>
+#include <ofono/voicecall.h>
+
+#define MODEM_DEVICE "/dev/smd0"
+
+static struct ofono_modem *g1_modem = NULL;
+
+struct g1_data {
+ GAtChat *chat;
+ GIOChannel *io;
+};
+
+static void connect_destroy(gpointer user)
+{
+ struct ofono_modem *modem = user;
+ struct g1_data *d = ofono_modem_get_data(modem);
+
+ d->io = NULL;
+}
+
+static void g1_debug(const char *str, void *data)
+{
+ DBG("%s", str);
+}
+
+static gboolean connect_cb(GIOChannel *io, GIOCondition cond, gpointer user)
+{
+ struct ofono_modem *modem = user;
+ struct g1_data *d = ofono_modem_get_data(modem);
+ int err = 0;
+ gboolean success;
+ GAtSyntax *syntax;
+
+ if (cond & G_IO_NVAL)
+ return FALSE;
+
+ if (cond & G_IO_OUT) {
+ int sock = g_io_channel_unix_get_fd(io);
+ socklen_t len = sizeof(err);
+
+ if (getsockopt(sock, SOL_SOCKET, SO_ERROR, &err, &len) < 0)
+ err = errno == ENOTSOCK ? 0 : errno;
+ } else if (cond & (G_IO_HUP | G_IO_ERR))
+ err = ECONNRESET;
+
+ success = !err;
+
+ DBG("io ref: %d", io->ref_count);
+
+ if (success == FALSE)
+ goto error;
+
+ syntax = g_at_syntax_new_gsmv1();
+ d->chat = g_at_chat_new(io, syntax);
+ g_at_syntax_unref(syntax);
+
+ DBG("io ref: %d", io->ref_count);
+
+ if (!d->chat)
+ goto error;
+
+ if (getenv("OFONO_AT_DEBUG") != NULL)
+ g_at_chat_set_debug(d->chat, g1_debug, NULL);
+
+ /* ensure modem is in a known state; verbose on, echo/quiet off */
+ g_at_chat_send(d->chat, "ATE0Q0V1", NULL, NULL, NULL, NULL);
+
+ /* power up modem */
+ g_at_chat_send(d->chat, "AT+CFUN=1", NULL, NULL, NULL, NULL);
+
+ ofono_modem_set_powered(modem, TRUE);
+
+ return FALSE;
+
+error:
+ ofono_modem_set_powered(modem, FALSE);
+ return FALSE;
+}
+
+static GIOChannel *tty_connect(const char *tty)
+{
+ GIOChannel *io;
+ int sk;
+ struct termios newtio;
+
+ sk = open(tty, O_RDWR | O_NOCTTY);
+
+ if (sk < 0) {
+ ofono_error("Can't open TTY %s: %s(%d)",
+ tty, strerror(errno), errno);
+ return NULL;
+ }
+
+ newtio.c_cflag = B115200 | CRTSCTS | CLOCAL | CREAD;
+ newtio.c_iflag = IGNPAR;
+ newtio.c_oflag = 0;
+ newtio.c_lflag = 0;
+
+ newtio.c_cc[VTIME] = 1;
+ newtio.c_cc[VMIN] = 5;
+
+ tcflush(sk, TCIFLUSH);
+ if (tcsetattr(sk, TCSANOW, &newtio) < 0) {
+ ofono_error("Can't change serial settings: %s(%d)",
+ strerror(errno), errno);
+ close(sk);
+ return NULL;
+ }
+
+ io = g_io_channel_unix_new(sk);
+ g_io_channel_set_close_on_unref(io, TRUE);
+
+ if (g_io_channel_set_flags(io, G_IO_FLAG_NONBLOCK,
+ NULL) != G_IO_STATUS_NORMAL) {
+ g_io_channel_unref(io);
+ return NULL;
+ }
+
+ return io;
+}
+
+static int g1_probe(struct ofono_modem *modem)
+{
+ struct g1_data *d;
+
+ d = g_new0(struct g1_data, 1);
+ if (!d)
+ return -ENOMEM;
+ ofono_modem_set_data(modem, d);
+
+ return 0;
+}
+
+static int g1_remove(struct ofono_modem *modem)
+{
+ g_free(ofono_modem_get_data(modem));
+
+ return 0;
+}
+
+static int g1_enable(struct ofono_modem *modem)
+{
+ struct g1_data *d = ofono_modem_get_data(modem);
+ GIOChannel *io;
+ GIOCondition cond;
+
+ DBG("");
+
+ io = tty_connect(MODEM_DEVICE);
+ if (io == NULL)
+ return -EINVAL;
+
+ DBG("io ref: %d", io->ref_count);
+
+ cond = G_IO_OUT | G_IO_ERR | G_IO_HUP | G_IO_NVAL;
+ g_io_add_watch_full(io, G_PRIORITY_DEFAULT, cond, connect_cb,
+ modem, connect_destroy);
+
+ DBG("io ref: %d", io->ref_count);
+
+ g_io_channel_unref(io);
+
+ DBG("io ref: %d", io->ref_count);
+ d->io = io;
+
+ return -EINPROGRESS;
+}
+
+static int g1_disable(struct ofono_modem *modem)
+{
+ struct g1_data *d = ofono_modem_get_data(modem);
+
+ if (d->io) {
+ g_io_channel_close(d->io);
+ d->io = NULL;
+ }
+
+ if (d->chat) {
+ g_at_chat_unref(d->chat);
+ d->chat = NULL;
+ }
+
+ return 0;
+}
+
+static int g1_populate(struct ofono_modem *modem)
+{
+ struct g1_data *d = ofono_modem_get_data(modem);
+ GAtChat *chat = d->chat;
+ struct ofono_message_waiting *mw;
+
+ ofono_devinfo_create(modem, "generic_at", chat);
+ ofono_ussd_create(modem, "generic_at", chat);
+ ofono_sim_create(modem, "generic_at", chat);
+ ofono_call_forwarding_create(modem, "generic_at", chat);
+ ofono_call_settings_create(modem, "generic_at", chat);
+ ofono_netreg_create(modem, "generic_at", chat);
+ ofono_voicecall_create(modem, "generic_at", chat);
+ ofono_call_meter_create(modem, "generic_at", chat);
+ ofono_call_barring_create(modem, "generic_at", chat);
+ ofono_ssn_create(modem, "generic_at", chat);
+ ofono_sms_create(modem, "generic_at", chat);
+ ofono_phonebook_create(modem, "generic_at", chat);
+
+ mw = ofono_message_waiting_create(modem);
+ if (mw)
+ ofono_message_waiting_register(mw);
+
+ return 0;
+}
+
+static struct ofono_modem_driver g1_driver = {
+ .name = "HTC G1",
+ .probe = g1_probe,
+ .remove = g1_remove,
+ .enable = g1_enable,
+ .disable = g1_disable,
+ .populate = g1_populate,
+};
+
+static int g1_init(void)
+{
+ int err;
+
+ err = ofono_modem_driver_register(&g1_driver);
+ if (err)
+ goto done;
+
+ g1_modem = ofono_modem_create("G1", "HTC G1");
+ if (!g1_modem) {
+ err = -EIO;
+ goto unreg;
+ }
+
+ err = ofono_modem_register(g1_modem);
+ if (err)
+ goto remove;
+
+ return 0;
+
+remove:
+ ofono_modem_remove(g1_modem);
+unreg:
+ ofono_modem_driver_unregister(&g1_driver);
+done:
+ return err;
+}
+
+static void g1_exit(void)
+{
+ ofono_modem_remove(g1_modem);
+ ofono_modem_driver_unregister(&g1_driver);
+}
+
+OFONO_PLUGIN_DEFINE(g1, "HTC G1 modem driver", VERSION,
+ OFONO_PLUGIN_PRIORITY_DEFAULT,
+ g1_init, g1_exit)
--
1.6.3.3
11 years, 5 months
Expose service dialling numbers stored on SIM through SimManager.
by Andrzej Zaborowski
---
The ServiceDiallingNumbers property now returns a list of strings (alpha
identifiers interleaved with dialling numbers) and this is a little hacky
but returning a dictionary would make the interface more hassle to use so
I'm not sure what's better.
---
src/sim.c | 117 +++++++++++++++++++++++++++++++++++++++++++++++++++++---
src/simutil.h | 1 +
2 files changed, 111 insertions(+), 7 deletions(-)
diff --git a/src/sim.c b/src/sim.c
index 2298cbf..2287458 100644
--- a/src/sim.c
+++ b/src/sim.c
@@ -80,6 +80,7 @@ struct sim_manager_data {
int mnc_length;
GSList *own_numbers;
GSList *new_numbers;
+ GSList *service_numbers;
GSList *ready_notify;
gboolean ready;
GQueue *simop_q;
@@ -89,6 +90,11 @@ struct sim_manager_data {
unsigned char efmsisdn_records;
};
+struct service_number {
+ char *id;
+ struct ofono_phone_number ph;
+};
+
struct msisdn_set_request {
struct ofono_modem *modem;
int pending;
@@ -118,11 +124,39 @@ static char **get_own_numbers(GSList *own_numbers)
return ret;
}
+static char **get_service_numbers(GSList *service_numbers)
+{
+ int nelem;
+ GSList *l;
+ struct service_number *num;
+ char **ret;
+
+ nelem = g_slist_length(service_numbers) * 2;
+
+ ret = g_new0(char *, nelem + 1);
+
+ nelem = 0;
+ for (l = service_numbers; l; l = l->next) {
+ num = l->data;
+
+ ret[nelem++] = g_strdup(num->id);
+ ret[nelem++] = g_strdup(phone_number_to_string(&num->ph));
+ }
+
+ return ret;
+}
+
static void sim_file_op_free(struct sim_file_op *node)
{
g_free(node);
}
+static void service_number_free(struct service_number *num)
+{
+ g_free(num->id);
+ g_free(num);
+}
+
static struct sim_manager_data *sim_manager_create()
{
return g_try_new0(struct sim_manager_data, 1);
@@ -144,6 +178,13 @@ static void sim_manager_destroy(gpointer userdata)
data->own_numbers = NULL;
}
+ if (data->service_numbers) {
+ g_slist_foreach(data->service_numbers,
+ (GFunc)service_number_free, NULL);
+ g_slist_free(data->service_numbers);
+ data->service_numbers = NULL;
+ }
+
if (data->simop_source) {
g_source_remove(data->simop_source);
data->simop_source = 0;
@@ -165,6 +206,7 @@ static DBusMessage *sim_get_properties(DBusConnection *conn,
DBusMessageIter iter;
DBusMessageIter dict;
char **own_numbers;
+ char **service_numbers;
unsigned char mnc_len;
reply = dbus_message_new_method_return(msg);
@@ -194,6 +236,15 @@ static DBusMessage *sim_get_properties(DBusConnection *conn,
DBUS_TYPE_STRING, &own_numbers);
g_strfreev(own_numbers);
+ if (sim->service_numbers) {
+ service_numbers = get_service_numbers(sim->service_numbers);
+
+ ofono_dbus_dict_append_array(&dict, "ServiceDiallingNumbers",
+ DBUS_TYPE_STRING,
+ &service_numbers);
+ g_strfreev(service_numbers);
+ }
+
dbus_message_iter_close_container(&iter, &dict);
return reply;
@@ -476,22 +527,74 @@ static void sim_ad_read_cb(struct ofono_modem *modem, int ok,
}
}
-static void sim_own_numbers_update(struct ofono_modem *modem)
+static void sim_sdn_read_cb(struct ofono_modem *modem, int ok,
+ enum ofono_sim_file_structure structure,
+ int length, int record,
+ const unsigned char *data,
+ int record_length, void *userdata)
{
- ofono_sim_read(modem, SIM_EFMSISDN_FILEID,
- sim_msisdn_read_cb, modem->sim_manager);
+ struct sim_manager_data *sim = userdata;
+ int total;
+ struct ofono_phone_number ph;
+ char *alpha;
+ char **service_numbers;
+ DBusConnection *conn = ofono_dbus_get_connection();
+
+ if (!ok)
+ goto check;
+
+ if (structure != OFONO_SIM_FILE_STRUCTURE_FIXED)
+ return;
+
+ if (record_length < 14 || length < record_length)
+ return;
+
+ total = length / record_length;
+
+ if (sim_adn_parse(data, record_length, &ph, &alpha) == TRUE && alpha) {
+ struct service_number *sdn;
+
+ sdn = g_new(struct service_number, 1);
+ sdn->id = alpha;
+ memcpy(&sdn->ph, &ph, sizeof(struct ofono_phone_number));
+
+ sim->service_numbers =
+ g_slist_prepend(sim->service_numbers, sdn);
+ }
+
+ if (record != total)
+ return;
+
+check:
+ /* All records retrieved */
+ if (sim->service_numbers) {
+ sim->service_numbers = g_slist_reverse(sim->service_numbers);
+
+ service_numbers = get_service_numbers(sim->service_numbers);
+
+ ofono_dbus_signal_array_property_changed(conn, modem->path,
+ SIM_MANAGER_INTERFACE,
+ "ServiceDiallingNumbers",
+ DBUS_TYPE_STRING,
+ &service_numbers);
+ g_strfreev(service_numbers);
+ }
}
-static void sim_mnc_length_update(struct ofono_modem *modem)
+static void sim_own_numbers_update(struct ofono_modem *modem)
{
- ofono_sim_read(modem, SIM_EFAD_FILEID,
- sim_ad_read_cb, modem->sim_manager);
+ ofono_sim_read(modem, SIM_EFMSISDN_FILEID,
+ sim_msisdn_read_cb, modem->sim_manager);
}
static void sim_ready(struct ofono_modem *modem)
{
sim_own_numbers_update(modem);
- sim_mnc_length_update(modem);
+
+ ofono_sim_read(modem, SIM_EFAD_FILEID,
+ sim_ad_read_cb, modem->sim_manager);
+ ofono_sim_read(modem, SIM_EFSDN_FILEID,
+ sim_sdn_read_cb, modem->sim_manager);
}
static void sim_imsi_cb(const struct ofono_error *error, const char *imsi,
diff --git a/src/simutil.h b/src/simutil.h
index dccbe7b..de3e55e 100644
--- a/src/simutil.h
+++ b/src/simutil.h
@@ -22,6 +22,7 @@
enum sim_fileid {
SIM_EFMSISDN_FILEID = 0x6f40,
SIM_EFSPN_FILEID = 0x6f46,
+ SIM_EFSDN_FILEID = 0x6f49,
SIM_EFAD_FILEID = 0x6fad,
SIM_EFPNN_FILEID = 0x6fc5,
SIM_EFOPL_FILEID = 0x6fc6,
--
1.6.1
11 years, 5 months
Read EFad and expose MNC length in IMSI as a SimManager property.
by Andrzej Zaborowski
Alternatively we could expose the MNC as a separate property.
---
src/sim.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++
src/simutil.h | 1 +
2 files changed, 51 insertions(+), 0 deletions(-)
diff --git a/src/sim.c b/src/sim.c
index 39976b3..0af02cd 100644
--- a/src/sim.c
+++ b/src/sim.c
@@ -77,6 +77,7 @@ struct sim_file_op {
struct sim_manager_data {
struct ofono_sim_ops *ops;
char *imsi;
+ int mnc_length;
GSList *own_numbers;
GSList *new_numbers;
GSList *ready_notify;
@@ -164,6 +165,7 @@ static DBusMessage *sim_get_properties(DBusConnection *conn,
DBusMessageIter iter;
DBusMessageIter dict;
char **own_numbers;
+ unsigned char mnc_len;
reply = dbus_message_new_method_return(msg);
if (!reply)
@@ -179,6 +181,13 @@ static DBusMessage *sim_get_properties(DBusConnection *conn,
ofono_dbus_dict_append(&dict, "SubscriberIdentity",
DBUS_TYPE_STRING, &sim->imsi);
+ if (sim->mnc_length) {
+ mnc_len = sim->mnc_length;
+
+ ofono_dbus_dict_append(&dict, "MNCLength",
+ DBUS_TYPE_BYTE, &mnc_len);
+ }
+
own_numbers = get_own_numbers(sim->own_numbers);
ofono_dbus_dict_append_array(&dict, "SubscriberNumbers",
@@ -432,15 +441,56 @@ check:
sim->new_numbers = NULL;
}
+static void sim_ad_read_cb(struct ofono_modem *modem, int ok,
+ enum ofono_sim_file_structure structure,
+ int length, int record,
+ const unsigned char *data,
+ int record_length, void *userdata)
+{
+ struct sim_manager_data *sim = userdata;
+ DBusConnection *conn = ofono_dbus_get_connection();
+ int new_mnc_length;
+ unsigned char value;
+ struct ofono_phone_number ph;
+
+ if (!ok)
+ return;
+
+ if (structure != OFONO_SIM_FILE_STRUCTURE_TRANSPARENT)
+ return;
+
+ if (length < 4)
+ return;
+
+ new_mnc_length = data[3] & 0xf;
+
+ if (sim->mnc_length != new_mnc_length) {
+ sim->mnc_length = new_mnc_length;
+
+ value = new_mnc_length;
+ ofono_dbus_signal_property_changed(conn, modem->path,
+ SIM_MANAGER_INTERFACE,
+ "MNCLength", DBUS_TYPE_BYTE,
+ &value);
+ }
+}
+
static void sim_own_numbers_update(struct ofono_modem *modem)
{
ofono_sim_read(modem, SIM_EFMSISDN_FILEID,
sim_msisdn_read_cb, modem->sim_manager);
}
+static void sim_mnc_length_update(struct ofono_modem *modem)
+{
+ ofono_sim_read(modem, SIM_EFAD_FILEID,
+ sim_ad_read_cb, modem->sim_manager);
+}
+
static void sim_ready(struct ofono_modem *modem)
{
sim_own_numbers_update(modem);
+ sim_mnc_length_update(modem);
}
static void sim_imsi_cb(const struct ofono_error *error, const char *imsi,
diff --git a/src/simutil.h b/src/simutil.h
index c0d3d52..9bb5323 100644
--- a/src/simutil.h
+++ b/src/simutil.h
@@ -22,6 +22,7 @@
enum sim_fileid {
SIM_EFMSISDN_FILEID = 0x6f40,
SIM_EFSPN_FILEID = 0x6f46,
+ SIM_EFAD_FILEID = 0x6fad,
SIM_EFPNN_FILEID = 0x6fc5,
SIM_EFOPL_FILEID = 0x6fc6,
SIM_EFMBDN_FILEID = 0x6fc7,
--
1.6.1
11 years, 5 months
Decode and encode alpha-identifier fields in EFadn format utils.
by Andrzej Zaborowski
Also fix the number length passed to extract_bcd_number in sim_adn_parse.
---
src/message-waiting.c | 5 +++--
src/sim.c | 5 +++--
src/simutil.c | 42 +++++++++++++++++++++++++++++++++++++-----
src/simutil.h | 5 +++--
4 files changed, 46 insertions(+), 11 deletions(-)
diff --git a/src/message-waiting.c b/src/message-waiting.c
index ccb137e..abca027 100644
--- a/src/message-waiting.c
+++ b/src/message-waiting.c
@@ -230,7 +230,7 @@ static DBusMessage *set_mbdn(struct ofono_modem *modem, int mailbox,
efmbdn_length = req->mw->efmbdn_length > 0 ?
req->mw->efmbdn_length : 14;
- sim_adn_build(efmbdn, efmbdn_length, &req->number);
+ sim_adn_build(efmbdn, efmbdn_length, &req->number, NULL);
if (req->mw->efmbdn_length > 0)
r = ofono_sim_write(modem, SIM_EFMBDN_FILEID, mbdn_set_cb,
@@ -404,7 +404,8 @@ static void mw_mbdn_read_cb(struct ofono_modem *modem, int ok,
if (i == 5)
return;
- if (sim_adn_parse(data, record_length, &mw->mailbox_number[i]) == FALSE)
+ if (sim_adn_parse(data, record_length, &mw->mailbox_number[i], NULL) ==
+ FALSE)
mw->mailbox_number[i].number[0] = '\0';
if (mw_mailbox_property_name[i]) {
diff --git a/src/sim.c b/src/sim.c
index 0af02cd..2298cbf 100644
--- a/src/sim.c
+++ b/src/sim.c
@@ -249,7 +249,8 @@ static gboolean set_own_numbers(struct ofono_modem *modem,
for (record = 1; record <= sim->efmsisdn_records; record++) {
if (new_numbers) {
number = new_numbers->data;
- sim_adn_build(efmsisdn, sim->efmsisdn_length, number);
+ sim_adn_build(efmsisdn, sim->efmsisdn_length,
+ number, NULL);
new_numbers = new_numbers->next;
} else
memset(efmsisdn, 0xff, sim->efmsisdn_length);
@@ -401,7 +402,7 @@ static void sim_msisdn_read_cb(struct ofono_modem *modem, int ok,
sim->efmsisdn_length = record_length;
sim->efmsisdn_records = total;
- if (sim_adn_parse(data, record_length, &ph) == TRUE) {
+ if (sim_adn_parse(data, record_length, &ph, NULL) == TRUE) {
struct ofono_phone_number *own;
own = g_new(struct ofono_phone_number, 1);
diff --git a/src/simutil.c b/src/simutil.c
index 1dc310b..41d5149 100644
--- a/src/simutil.c
+++ b/src/simutil.c
@@ -403,7 +403,7 @@ const struct sim_eons_operator_info *sim_eons_lookup_with_lac(
}
gboolean sim_adn_parse(const unsigned char *data, int length,
- struct ofono_phone_number *ph)
+ struct ofono_phone_number *ph, char **identifier)
{
int number_len;
int ton_npi;
@@ -411,19 +411,31 @@ gboolean sim_adn_parse(const unsigned char *data, int length,
if (length < 14)
return FALSE;
- /* Skip Alpha-Identifier field */
+ /* Alpha-Identifier field */
+ if (identifier) {
+ if (length > 14)
+ *identifier = sim_string_to_utf8(data, length - 14);
+ else
+ *identifier = NULL;
+ }
data += length - 14;
number_len = *data++;
ton_npi = *data++;
- if (number_len > 11 || ton_npi == 0xff)
+ if (number_len > 11 || ton_npi == 0xff) {
+ if (identifier && *identifier) {
+ g_free(*identifier);
+ *identifier = NULL;
+ }
+
return FALSE;
+ }
ph->type = ton_npi;
/* BCD coded, however the TON/NPI is given by the first byte */
- number_len = (number_len - 1) * 2;
+ number_len -= 1;
extract_bcd_number(data, number_len, ph->number);
@@ -431,13 +443,33 @@ gboolean sim_adn_parse(const unsigned char *data, int length,
}
void sim_adn_build(unsigned char *data, int length,
- const struct ofono_phone_number *ph)
+ const struct ofono_phone_number *ph,
+ const char *identifier)
{
int number_len = strlen(ph->number);
+ unsigned char *gsm_identifier;
+ long gsm_bytes;
/* Alpha-Identifier field */
if (length > 14) {
memset(data, 0xff, length - 14);
+
+ if (identifier) {
+ /* TODO: figure out when the identifier needs to
+ * be encoded in UCS2 and do this.
+ */
+ gsm_identifier = convert_utf8_to_gsm(identifier,
+ -1, NULL, &gsm_bytes, 0);
+
+ if (gsm_identifier) {
+ if (gsm_bytes > length - 14)
+ gsm_bytes = length - 14;
+
+ memcpy(data, gsm_identifier, gsm_bytes);
+ g_free(gsm_identifier);
+ }
+ }
+
data += length - 14;
}
diff --git a/src/simutil.h b/src/simutil.h
index 9bb5323..dccbe7b 100644
--- a/src/simutil.h
+++ b/src/simutil.h
@@ -83,6 +83,7 @@ static inline enum sim_file_access file_access_condition_decode(int bcd)
}
gboolean sim_adn_parse(const unsigned char *data, int length,
- struct ofono_phone_number *ph);
+ struct ofono_phone_number *ph, char **identifier);
void sim_adn_build(unsigned char *data, int length,
- const struct ofono_phone_number *ph);
+ const struct ofono_phone_number *ph,
+ const char *identifier);
--
1.6.1
11 years, 5 months
driver callback naming
by Andres Salomon
Hi,
Slightly bikesheddy, but.. The ofono_modem_driver callback naming is
pretty confusing. Currently, it's:
static struct ofono_modem_driver g1_driver = {
.name = "HTC G1",
.probe = g1_probe,
.enable = g1_enable,
.disable = g1_disable,
.remove = g1_remove,
.populate = g1_populate,
};
I'm used to probe/remove in the kernel being used for device detection
and allocating related resources (as well as powering up or down pci
devices and such), but the enable/disable names tell me nothing.
What's being enabled? Is 'probe' just a thin layer that detects
whether a device is present and then defers to 'enable' to set it
up (and if so, should we it called 'detect' or something that
doesn't imply a kernel-like 'probe' function)? Denkenz informs me that
it's for setting power to devices; if that's the case, a better name
might be powerup/powerdown.
Of course, I'm also wondering why there needs to be two separate layers
of calls in the first place. Why not have drivers register everything
from within probe, call ofono_set_powered(modem, TRUE) once the device
is ready, and be done with it?
This question comes up because sending SIGTERM to the
daemon ends up calling g1_exit, which (in my case) was freeing the
ofono_modem->private_data first, and then calling ofono_modem_remove.
This in turn was calling the 'disable' callback, which expected
ofono_modem->private_data to exist.
The only reason why this doesn't blow up in the generic_at plugin is
because the driver_data is leaked. If one were to free it from
generic_at_exit in the wrong place (since it's allocated from
generic_at_init, it would make sense to free it in generic_at_exit),
one would see the same SEGV/SIGBUS/SIGILL errors upon ctrl-c.
11 years, 5 months