[PATCH 1/1] ublox: detect and support LARA R2 series
by Jonas Bonn
---
Hi Krishna,
This patch isn't tested, but this is roughly what you'd need to get the
LARA R2 detected and running. After that, it's just a matter of going
through the details of where ofono has issues.
>From what I can see at a quick glance at the documentation, there's
nothing that particularly stands out here so I suspect things will
mostly just work. Give the patch a try and let me know how it goes.
Regards,
Jonas
drivers/ubloxmodem/ubloxmodem.c | 9 +++++++++
drivers/ubloxmodem/ubloxmodem.h | 1 +
plugins/udevng.c | 2 ++
3 files changed, 12 insertions(+)
diff --git a/drivers/ubloxmodem/ubloxmodem.c b/drivers/ubloxmodem/ubloxmodem.c
index a52a67ea..85d72684 100644
--- a/drivers/ubloxmodem/ubloxmodem.c
+++ b/drivers/ubloxmodem/ubloxmodem.c
@@ -77,6 +77,15 @@ const struct ublox_model ublox_models[] = {
.name = "TOBY-L4906",
.flags = UBLOX_F_TOBY_L4,
},
+ /* LARA L2 series */
+ {
+ .name = "LARA-R202",
+ .flags = UBLOX_F_LARA_R2,
+ },
+ {
+ .name = "LARA-R211",
+ .flags = UBLOX_F_LARA_R2,
+ },
{ /* sentinel */ },
};
diff --git a/drivers/ubloxmodem/ubloxmodem.h b/drivers/ubloxmodem/ubloxmodem.h
index 2c5b7433..7fe58df3 100644
--- a/drivers/ubloxmodem/ubloxmodem.h
+++ b/drivers/ubloxmodem/ubloxmodem.h
@@ -27,6 +27,7 @@ enum ublox_flags {
UBLOX_F_TOBY_L2 = (1 << 0),
UBLOX_F_TOBY_L4 = (1 << 1),
UBLOX_F_HAVE_USBCONF = (1 << 2),
+ UBLOX_F_LARA_R2 = (1 << 3),
};
struct ublox_model {
diff --git a/plugins/udevng.c b/plugins/udevng.c
index f689b756..397ac931 100644
--- a/plugins/udevng.c
+++ b/plugins/udevng.c
@@ -1700,6 +1700,8 @@ static struct {
{ "ublox", "cdc_acm", "1546", "1010" },
{ "ublox", "cdc_ncm", "1546", "1010" },
{ "ublox", "cdc_acm", "1546", "1102" },
+ { "ublox", "cdc_acm", "1546", "110a" },
+ { "ublox", "cdc_ncm", "1546", "110a" },
{ "ublox", "rndis_host", "1546", "1146" },
{ "ublox", "cdc_acm", "1546", "1146" },
{ "gemalto", "option", "1e2d", "0053" },
--
2.20.1
1 year, 6 months
[RFC at-export 0/2] Export AT-modem functions to other drivers
by Jonas Bonn
Hi Denis,
I'm writing a custom network-registration driver for uBlox modems and
I'd like to know if you will choke on the following approach:
i) export method implementations from atmodem driver
ii) set up uBlox netreg vtable with custom probe method and exported
atmodem implementations for rest
If you can't accept this approach, please let me know of an alternative
method that would be preferable that (hopefully) doesn't entail just
copying all the code from one driver to the other (1000+ lines to keep
in sync going forward).
Best regards,
Jonas
PS: This is an RFC... patches are not quite done. That said, feel free
to patch review if you've got a moment; the final result shouldn't
differ all that much from what's here.
Jonas Bonn (2):
atmodem: export generic netreg funcs
ublox: network-registration atom
drivers/atmodem/network-registration.c | 16 +-
drivers/atmodem/network-registration.h | 17 +
drivers/ubloxmodem/network-registration.c | 413 ++++++++++++++++++++++
drivers/ubloxmodem/ubloxmodem.c | 2 +
drivers/ubloxmodem/ubloxmodem.h | 3 +
5 files changed, 444 insertions(+), 7 deletions(-)
create mode 100644 drivers/atmodem/network-registration.h
create mode 100644 drivers/ubloxmodem/network-registration.c
--
2.20.1
1 year, 8 months
[PATCH] xmm7modem: handling of IPv6 address for activated context
by Antara Borwankar
Handled IPv6 address after activating PDP context.
Received IPv6 address is of format addr + netmask in the same string
in the form of "a1.a2.a3.a4.a5.a6.a7.a8.a9.a10.a11.a12.a13.a14.a15.a16.
m1.m2.m3.m4.m5.m6.m7.m8.m9.m10.m11.m12.m13.m14.m15.m16"
---
drivers/atmodem/atutil.c | 39 +++++++++++++++++++++++++++++++++
drivers/atmodem/atutil.h | 3 +++
drivers/ifxmodem/gprs-context.c | 48 +++++++++++++++++++++++++++++------------
3 files changed, 76 insertions(+), 14 deletions(-)
diff --git a/drivers/atmodem/atutil.c b/drivers/atmodem/atutil.c
index 98e3a2f..adcca85 100644
--- a/drivers/atmodem/atutil.c
+++ b/drivers/atmodem/atutil.c
@@ -656,6 +656,45 @@ int at_util_get_ipv4_address_and_netmask(const char *addrnetmask,
return ret;
}
+/*
+ * CGCONTRDP returns addr + netmask in the same string in the form
+ * of "a1.a2.a3.a4.a5.a6.a7.a8.a9.a10.a11.a12.a13.a14.a15.a16.m1.m2.
+ * m3.m4.m5.m6.m7.m8.m9.m10.m11.m12.m13.m14.m15.m16" for IPv6.
+ * address/netmask must be able to hold 64 characters.
+ */
+int at_util_get_ipv6_address_and_netmask(const char *addrnetmask,
+ char *address, char *netmask)
+{
+ const char *s = addrnetmask;
+ const char *net = NULL;
+
+ int ret = -EINVAL;
+ int i;
+
+ /* Count 31 dots for ipv6, less or more means error. */
+ for (i = 0; i < 33; i++, s++) {
+ s = strchr(s, '.');
+
+ if (!s)
+ break;
+
+ if (i == 15) {
+ /* set netmask ptr and break the string */
+ net = s + 1;
+ }
+ }
+
+ if (i == 31) {
+ memcpy(address, addrnetmask, net - addrnetmask);
+ address[net - addrnetmask - 1] = '\0';
+ strcpy(netmask, net);
+
+ ret = 0;
+ }
+
+ return ret;
+}
+
int at_util_gprs_auth_method_to_auth_prot(
enum ofono_gprs_auth_method auth_method)
{
diff --git a/drivers/atmodem/atutil.h b/drivers/atmodem/atutil.h
index 69e8b49..61800ff 100644
--- a/drivers/atmodem/atutil.h
+++ b/drivers/atmodem/atutil.h
@@ -86,6 +86,9 @@ void at_util_sim_state_query_free(struct at_util_sim_state_query *req);
int at_util_get_ipv4_address_and_netmask(const char *addrnetmask,
char *address, char *netmask);
+int at_util_get_ipv6_address_and_netmask(const char *addrnetmask,
+ char *address, char *netmask);
+
int at_util_gprs_auth_method_to_auth_prot(
enum ofono_gprs_auth_method auth_method);
diff --git a/drivers/ifxmodem/gprs-context.c b/drivers/ifxmodem/gprs-context.c
index 6042004..5336f71 100644
--- a/drivers/ifxmodem/gprs-context.c
+++ b/drivers/ifxmodem/gprs-context.c
@@ -44,6 +44,7 @@
#define TUN_DEV "/dev/net/tun"
#define STATIC_IP_NETMASK "255.255.255.255"
+#define IPV6_DEFAULT_PREFIX_LEN 8
static const char *none_prefix[] = { NULL };
static const char *xdns_prefix[] = { "+XDNS:", NULL };
@@ -352,10 +353,39 @@ static void cgcontrdp_cb(gboolean ok, GAtResult *result, gpointer user_data)
DBG("DNS: %s, %s\n", gcd->dns1, gcd->dns2);
- if (!laddrnetmask || at_util_get_ipv4_address_and_netmask(laddrnetmask,
- gcd->address, gcd->netmask) < 0) {
- failed_setup(gc, NULL, TRUE);
- return;
+ if (gcd->proto == OFONO_GPRS_PROTO_IP) {
+ if (!laddrnetmask || at_util_get_ipv4_address_and_netmask(laddrnetmask,
+ gcd->address, gcd->netmask) < 0) {
+ failed_setup(gc, NULL, TRUE);
+ return;
+ }
+
+ ofono_gprs_context_set_ipv4_address(gc, gcd->address, TRUE);
+
+ if (gcd->netmask[0])
+ ofono_gprs_context_set_ipv4_netmask(gc, gcd->netmask);
+
+ if (gcd->gateway[0])
+ ofono_gprs_context_set_ipv4_gateway(gc, gcd->gateway);
+
+ ofono_gprs_context_set_ipv4_dns_servers(gc, dns);
+ }
+
+ if (gcd->proto == OFONO_GPRS_PROTO_IPV6) {
+ if (!laddrnetmask || at_util_get_ipv6_address_and_netmask(laddrnetmask,
+ gcd->address, gcd->netmask) < 0) {
+ failed_setup(gc, NULL, TRUE);
+ return;
+ }
+
+ ofono_gprs_context_set_ipv6_address(gc, gcd->address);
+
+ if (gcd->gateway[0])
+ ofono_gprs_context_set_ipv6_gateway(gc, gcd->gateway);
+
+ ofono_gprs_context_set_ipv6_dns_servers(gc, dns);
+
+ ofono_gprs_context_set_ipv6_prefix_length(gc, IPV6_DEFAULT_PREFIX_LEN);
}
if (gw)
@@ -373,16 +403,6 @@ static void cgcontrdp_cb(gboolean ok, GAtResult *result, gpointer user_data)
interface = ofono_gprs_context_get_interface(gc);
datapath = get_datapath(modem, interface);
- ofono_gprs_context_set_ipv4_address(gc, gcd->address, TRUE);
-
- if (gcd->netmask[0])
- ofono_gprs_context_set_ipv4_netmask(gc, gcd->netmask);
-
- if (gcd->gateway[0])
- ofono_gprs_context_set_ipv4_gateway(gc, gcd->gateway);
-
- ofono_gprs_context_set_ipv4_dns_servers(gc, dns);
-
snprintf(buf, sizeof(buf), "AT+XDATACHANNEL=1,1,\"%s\",\"%s\",2,%u",
ctrlpath, datapath, gcd->active_context);
g_at_chat_send(gcd->chat, buf, none_prefix, NULL, NULL, NULL);
--
1.9.1
1 year, 8 months
[PATCH 1/2] gprs: netreg_status_changed: output the status as human readable string
by Alexander Couzens
---
src/gprs.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/gprs.c b/src/gprs.c
index 148cbc979dfb..5f66cad591c1 100644
--- a/src/gprs.c
+++ b/src/gprs.c
@@ -1700,7 +1700,7 @@ static void netreg_status_changed(int status, int lac, int ci, int tech,
{
struct ofono_gprs *gprs = data;
- DBG("%d", status);
+ DBG("%d (%s)", status, registration_status_to_string(status));
gprs->netreg_status = status;
--
2.21.0
1 year, 8 months
[PATCH 1/2] network/ofono_netreg_status_notify: debug log the lac and ci
by Alexander Couzens
---
src/network.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/network.c b/src/network.c
index ae3175d4a7e9..19e7e7824067 100644
--- a/src/network.c
+++ b/src/network.c
@@ -1351,8 +1351,8 @@ void ofono_netreg_status_notify(struct ofono_netreg *netreg, int status,
if (netreg == NULL)
return;
- DBG("%s status %d tech %d", __ofono_atom_get_path(netreg->atom),
- status, tech);
+ DBG("%s status %d tech %d lac %d ci %d",
+ __ofono_atom_get_path(netreg->atom), status, tech, lac, ci);
if (netreg->status != status) {
struct ofono_modem *modem;
--
2.21.0
1 year, 8 months
Re: [PATCH] qmimodem: support wake on SMS receive
by Denis Kenzior
Hi Tom,
On 04/23/2019 07:42 AM, Nguyen, Tom wrote:
> Hi Denis,
>
> Per question, "So doesn't this also cause us to bring the modem offline when we wake up from resume?"
> Yes, it does. While this modem is capable of waking the host CPU via GPIO upon SMS reception, it doesn't have a handshake mechanism for the host to signal that it's ready to communicate with the modem, which would allow the host to prevent the modem from sending the QMI indication too early. Frustratingly, this handshake does exist if the modem is used with the AT interface. I tried to convince the vendor that the handshake should be applied to the QMI interface too, but...
That sounds horrible.
>
> Per comment, "So any state data must be allocated as part of the driver data."
> Thanks for the insight. Are you referring to "struct sms_data"?
>
Yes, correct. Anything that contains state must be allocated on the
heap. For oFono drivers this is typically the driver specific data
structure setup in the .probe method.
> I've copied my other email, so hopefully my future responses won't break this chain.
> Also, thank you for helping with the IMEI patch.
>
No worries. Just FYI, when responding to the list, please refrain from
top-posting. The common open source mailing list etiquette is to
respond in-line.
Regards,
-Denis
1 year, 9 months
[PATCH] gprs: Always store RoamingAllowed as a boolean.
by richard.rojfors@gmail.com
From: Richard Röjfors <richard(a)puffinpack.se>
In one instance it was stored as boolean and another as int.
Since its always parsed as a boolean and it is a boolean,
always store it as boolean.
---
src/gprs.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/gprs.c b/src/gprs.c
index d432c9fd..148cbc97 100644
--- a/src/gprs.c
+++ b/src/gprs.c
@@ -1793,7 +1793,7 @@ static DBusMessage *gprs_set_property(DBusConnection *conn,
gprs->roaming_allowed = value;
if (gprs->settings) {
- g_key_file_set_integer(gprs->settings, SETTINGS_GROUP,
+ g_key_file_set_boolean(gprs->settings, SETTINGS_GROUP,
"RoamingAllowed",
gprs->roaming_allowed);
storage_sync(gprs->imsi, SETTINGS_STORE,
--
2.19.1
1 year, 9 months
RE: Ofono for ublox LARA-R211
by Krishna
Hi All,
Whether anyone tried ofono framework with u-blox LARA-R211 or LARA-202?
Regards,
Krishna
From: Krishna [mailto:krishnaks@iwavesystems.com]
Sent: Friday, March 22, 2019 08:09 PM
To: 'ofono(a)ofono.org' <ofono(a)ofono.org>
Subject: Ofono for ublox LARA-R211
Hi All,
Whether I can use ofono for LARA-R211 or LARA-202?
I have added ofono package to the yocto and enabled required configurations
in Linux kernel.
I have referred below link for the configuration.
https://embexus.com/2017/06/04/add-a-mobile-broadband-connectivity-to-embedd
ed-linux/
However ./list-modem is not returning anything.
Let me know if I am missing any configuration.
Regards,
Krishna
1 year, 9 months
[PATCH] qmimodem: support wake on SMS receive
by Joshua Watt
From: Tom Nguyen <tom.nguyen(a)garmin.com>
Some modems, like Quectel EC25, support waking the host platform from
a suspend state upon an SMS reception. Current SMS handling configures
the modem to not save incoming messages. On platforms where the modem's
interfaces (eg, cdc-wdm, wwan, etc) disconnect on suspend and reconnect
on resume, oFono will re-initialize. This can cause lost messages
upon resume because the QMI indication is sent before oFono is ready.
Changes to support suspend/resume with wake on SMS:
- On startup:
1. Configure modem to save messages to NV and notify for class NONE.
2. Delete all processed messages in modem memory to free space.
3. Get list of unread messages, then get and delete each.
- After startup:
1. Process message upon event indication and delete.
2. Then check for possibly more messages to process.
---
drivers/qmimodem/sms.c | 338 ++++++++++++++++++++++++++++++++++-------
drivers/qmimodem/wms.h | 77 +++++++---
2 files changed, 341 insertions(+), 74 deletions(-)
diff --git a/drivers/qmimodem/sms.c b/drivers/qmimodem/sms.c
index 1e930396..0a85138a 100644
--- a/drivers/qmimodem/sms.c
+++ b/drivers/qmimodem/sms.c
@@ -41,6 +41,14 @@ struct sms_data {
uint16_t minor;
};
+static struct qmi_wms_read_msg_id rd_msg_id = { 0 };
+static uint8_t msg_mode = QMI_WMS_MESSAGE_MODE_GSMWCDMA;
+static bool msg_chk_all;
+static bool msg_list_chk;
+
+static void get_msg_list(struct ofono_sms *sms);
+
+
static void get_smsc_addr_cb(struct qmi_result *result, void *user_data)
{
struct cb_data *cbd = user_data;
@@ -334,21 +342,80 @@ error:
g_free(cbd);
}
-static void raw_read_cb(struct qmi_result *result, void *user_data)
+static void delete_msg_cb(struct qmi_result *result, void *user_data)
{
struct ofono_sms *sms = user_data;
- const struct qmi_wms_raw_message* msg;
- uint16_t len;
- uint16_t error;
+ uint16_t err;
- if (qmi_result_set_error(result, &error)) {
- DBG("Raw read error: %d (%s)", error,
- qmi_result_get_error(result));
+ DBG("");
+
+ if (qmi_result_set_error(result, &err))
+ DBG("Err: delete %d - %s", err, qmi_result_get_error(result));
+ else {
+ DBG("msg deleted");
+
+ /* check for more messages */
+ get_msg_list(sms);
+ }
+}
+
+static void delete_msg(struct ofono_sms *sms, uint8_t tag)
+{
+ struct sms_data *data = ofono_sms_get_data(sms);
+ struct qmi_param *param;
+ qmi_result_func_t func = NULL;
+
+ DBG("");
+
+ param = qmi_param_new();
+ if (param == NULL)
+ goto done;
+
+ qmi_param_append_uint8(param, QMI_WMS_PARAM_DEL_STORE,
+ QMI_WMS_STORAGE_TYPE_NV);
+
+ if (tag == QMI_WMS_MT_UNDEFINE) {
+ DBG("delete read msg type %d ndx %d", rd_msg_id.type,
+ rd_msg_id.ndx);
+
+ /* delete 1 msg */
+ qmi_param_append_uint32(param, QMI_WMS_PARAM_DEL_NDX,
+ rd_msg_id.ndx);
+ func = delete_msg_cb;
+ } else {
+ DBG("delete msg tag %d mode %d", tag, msg_mode);
+
+ /* delete all msgs from 1 tag type */
+ qmi_param_append_uint8(param, QMI_WMS_PARAM_DEL_TYPE, tag);
+ }
+
+ qmi_param_append_uint8(param, QMI_WMS_PARAM_DEL_MODE, msg_mode);
+
+ if (qmi_service_send(data->wms, QMI_WMS_DELETE, param,
+ func, sms, NULL) > 0)
return;
+
+ qmi_param_free(param);
+
+done:
+ return;
+}
+
+static void raw_read_cb(struct qmi_result *result, void *user_data)
+{
+ struct ofono_sms *sms = user_data;
+ const struct qmi_wms_raw_message *msg;
+ uint16_t err;
+
+ DBG("");
+
+ if (qmi_result_set_error(result, &err)) {
+ DBG("Err: read %d - %s", err, qmi_result_get_error(result));
+ goto done;
}
/* Raw message data */
- msg = qmi_result_get(result, 0x01, &len);
+ msg = qmi_result_get(result, QMI_WMS_RESULT_READ_MSG, NULL);
if (msg) {
uint16_t plen;
uint16_t tpdu_len;
@@ -357,66 +424,204 @@ static void raw_read_cb(struct qmi_result *result, void *user_data)
tpdu_len = plen - msg->msg_data[0] - 1;
ofono_sms_deliver_notify(sms, msg->msg_data, plen, tpdu_len);
+ } else
+ DBG("Err: no data in type %d ndx %d", rd_msg_id.type,
+ rd_msg_id.ndx);
+
+ /* delete read msg */
+ delete_msg(sms, QMI_WMS_MT_UNDEFINE);
+
+done:
+ return;
+}
+
+static void raw_read(struct ofono_sms *sms, uint8_t type, uint32_t ndx)
+{
+ struct sms_data *data = ofono_sms_get_data(sms);
+ struct qmi_param *param;
+
+ DBG("");
+
+ param = qmi_param_new();
+ if (param == NULL)
+ goto done;
+
+ rd_msg_id.type = type;
+ rd_msg_id.ndx = ndx;
+
+ DBG("read type %d ndx %d", rd_msg_id.type, rd_msg_id.ndx);
+
+ qmi_param_append(param, QMI_WMS_PARAM_READ_MSG, sizeof(rd_msg_id),
+ &rd_msg_id);
+ qmi_param_append_uint8(param, QMI_WMS_PARAM_READ_MODE, msg_mode);
+
+ if (qmi_service_send(data->wms, QMI_WMS_RAW_READ, param,
+ raw_read_cb, sms, NULL) > 0)
+ return;
+
+ qmi_param_free(param);
+
+done:
+ return;
+}
+
+static void get_msg_list_cb(struct qmi_result *result, void *user_data)
+{
+ struct ofono_sms *sms = user_data;
+ struct sms_data *data = ofono_sms_get_data(sms);
+ struct qmi_param *param;
+ const struct qmi_wms_result_msg_list *list;
+ uint32_t cnt = 0;
+ uint16_t tmp;
+
+ DBG("");
+
+ if (qmi_result_set_error(result, &tmp)) {
+ DBG("Err: get msg list %d - %s", tmp,
+ qmi_result_get_error(result));
+ goto done;
+ }
+
+ list = qmi_result_get(result, QMI_WMS_RESULT_MSG_LIST, NULL);
+ if (list == NULL) {
+ DBG("Err: get msg list empty");
+ goto done;
+ }
+
+ cnt = GUINT32_FROM_LE(list->cnt);
+ DBG("msgs found %d", cnt);
+
+ for (tmp = 0; tmp < cnt; tmp++) {
+ DBG("unread type %d ndx %d", list->msg[tmp].type,
+ GUINT32_FROM_LE(list->msg[tmp].ndx));
+ }
+
+ /* get 1st msg in list */
+ if (cnt)
+ raw_read(sms, list->msg[0].type,
+ GUINT32_FROM_LE(list->msg[0].ndx));
+ else
+ msg_list_chk = false;
+
+done:
+ /* check other protocol if needed */
+ if (msg_chk_all && (cnt == 0)) {
+ msg_chk_all = false;
+ msg_mode = QMI_WMS_MESSAGE_MODE_GSMWCDMA;
+ get_msg_list(sms);
+ }
+}
+
+static void get_msg_list(struct ofono_sms *sms)
+{
+ struct sms_data *data = ofono_sms_get_data(sms);
+ struct qmi_param *param;
+
+ DBG("");
+
+ param = qmi_param_new();
+ if (param == NULL)
+ goto done;
+
+ msg_list_chk = true;
+
+ /* query NOT_READ msg list */
+ qmi_param_append_uint8(param, QMI_WMS_PARAM_STORAGE_TYPE,
+ QMI_WMS_STORAGE_TYPE_NV);
+ qmi_param_append_uint8(param, QMI_WMS_PARAM_TAG_TYPE,
+ QMI_WMS_MT_NOT_READ);
+ qmi_param_append_uint8(param, QMI_WMS_PARAM_MESSAGE_MODE, msg_mode);
+
+ if (qmi_service_send(data->wms, QMI_WMS_GET_MSG_LIST, param,
+ get_msg_list_cb, sms, NULL) > 0)
+ return;
+
+ qmi_param_free(param);
+
+done:
+ return;
+}
+
+static void get_msg_protocol_cb(struct qmi_result *result, void *user_data)
+{
+ struct ofono_sms *sms = user_data;
+ uint16_t err;
+
+ DBG("");
+
+ if (qmi_result_set_error(result, &err) &&
+ (err != QMI_ERR_OP_DEVICE_UNSUPPORTED)) {
+ DBG("Err: protocol %d - %s", err, qmi_result_get_error(result));
+ goto done;
+ }
+
+ if (err != QMI_ERR_OP_DEVICE_UNSUPPORTED) {
+ /* modem supports only 1 protocol */
+ qmi_result_get_uint8(result, QMI_WMS_PARAM_PROTOCOL, &msg_mode);
} else {
- DBG("No message data available at requested position");
+ /* check both, start with 1 then switch to other */
+ DBG("device supports CDMA and WCDMA msg protocol");
+ msg_chk_all = true;
+ msg_mode = QMI_WMS_MESSAGE_MODE_CDMA;
}
+
+ /* check for messages */
+ get_msg_list(sms);
+
+done:
+ return;
+}
+
+static void get_msg_protocol(struct ofono_sms *sms)
+{
+ struct sms_data *data = ofono_sms_get_data(sms);
+
+ DBG("");
+
+ qmi_service_send(data->wms, QMI_WMS_GET_MSG_PROTOCOL, NULL,
+ get_msg_protocol_cb, sms, NULL);
}
static void event_notify(struct qmi_result *result, void *user_data)
{
struct ofono_sms *sms = user_data;
- struct sms_data *data = ofono_sms_get_data(sms);
const struct qmi_wms_result_new_msg_notify *notify;
- const struct qmi_wms_result_message *message;
- uint16_t len;
DBG("");
- notify = qmi_result_get(result, QMI_WMS_RESULT_NEW_MSG_NOTIFY, &len);
+ notify = qmi_result_get(result, QMI_WMS_RESULT_NEW_MSG_NOTIFY, NULL);
if (notify) {
- DBG("storage type %d index %d", notify->storage_type,
- GUINT32_FROM_LE(notify->storage_index));
- }
+ /* route is store and notify */
+ if (!qmi_result_get_uint8(result, QMI_WMS_RESULT_MSG_MODE,
+ &msg_mode))
+ DBG("msg mode not found, use mode %d", msg_mode);
+
+ DBG("msg type %d ndx %d mode %d", notify->storage_type,
+ GUINT32_FROM_LE(notify->storage_index), msg_mode);
+
+ /* don't read if list is being processed, will find this msg */
+ if (!msg_list_chk)
+ raw_read(sms, notify->storage_type,
+ GUINT32_FROM_LE(notify->storage_index));
+ } else {
+ const struct qmi_wms_result_message *message;
- message = qmi_result_get(result, QMI_WMS_RESULT_MESSAGE, &len);
- if (message) {
- uint16_t plen;
+ message = qmi_result_get(result, QMI_WMS_RESULT_MESSAGE, NULL);
+ if (message) {
+ /* route is either transfer only or transfer and ACK */
+ uint16_t plen;
- plen = GUINT16_FROM_LE(message->msg_length);
+ plen = GUINT16_FROM_LE(message->msg_length);
- DBG("ack_required %d transaction id %u", message->ack_required,
+ DBG("ack_required %d transaction id %u",
+ message->ack_required,
GUINT32_FROM_LE(message->transaction_id));
- DBG("msg format %d PDU length %d", message->msg_format, plen);
+ DBG("msg format %d PDU length %d",
+ message->msg_format, plen);
- ofono_sms_deliver_notify(sms, message->msg_data, plen, plen);
- } else {
- /* The Quectel EC21, at least, does not provide the
- * message data in the event notification, so a 'raw read'
- * needs to be issued in order to query the message itself
- */
- struct qmi_param *param;
-
- param = qmi_param_new();
- if (!param)
- return;
-
- /* Message memory storage ID */
- qmi_param_append(param, 0x01, sizeof(*notify), notify);
- /* The 'message mode' parameter is documented as optional,
- * but the Quectel EC21 errors out with error 17 (missing
- * argument) if it is not provided... we default to 3GPP
- * here because that's what works for me and it's not clear
- * how to actually query what this should be otherwise...
- */
- /* Message mode */
- qmi_param_append_uint8(param, 0x10,
- QMI_WMS_MESSAGE_MODE_GSMWCDMA);
-
- if (qmi_service_send(data->wms, QMI_WMS_RAW_READ, param,
- raw_read_cb, sms, NULL) > 0)
- return;
-
- qmi_param_free(param);
+ ofono_sms_deliver_notify(sms, message->msg_data,
+ plen, plen);
+ }
}
}
@@ -427,6 +632,25 @@ static void set_routes_cb(struct qmi_result *result, void *user_data)
DBG("");
ofono_sms_register(sms);
+
+ /*
+ * Modem storage is limited. As a fail safe, delete processed messages
+ * to free device memory to prevent blockage of new messages.
+ */
+ msg_mode = QMI_WMS_MESSAGE_MODE_CDMA;
+ delete_msg(sms, QMI_WMS_MT_READ);
+ delete_msg(sms, QMI_WMS_MO_SENT);
+ msg_mode = QMI_WMS_MESSAGE_MODE_GSMWCDMA;
+ delete_msg(sms, QMI_WMS_MT_READ);
+ delete_msg(sms, QMI_WMS_MO_SENT);
+
+ /*
+ * Subsystem initialized, now start process to check for unread
+ * messages. First, query msg protocol/mode. If modem supports both
+ * modes, then check messages for both modes since there's no way to
+ * query which mode is active.
+ */
+ get_msg_protocol(sms);
}
static void get_routes_cb(struct qmi_result *result, void *user_data)
@@ -445,7 +669,7 @@ static void get_routes_cb(struct qmi_result *result, void *user_data)
goto done;
list = qmi_result_get(result, QMI_WMS_RESULT_ROUTE_LIST, &len);
- if (!list)
+ if (!list)
goto done;
num = GUINT16_FROM_LE(list->count);
@@ -468,8 +692,8 @@ static void get_routes_cb(struct qmi_result *result, void *user_data)
new_list->count = GUINT16_TO_LE(1);
new_list->route[0].msg_type = QMI_WMS_MSG_TYPE_P2P;
new_list->route[0].msg_class = QMI_WMS_MSG_CLASS_NONE;
- new_list->route[0].storage_type = QMI_WMS_STORAGE_TYPE_NONE;
- new_list->route[0].action = QMI_WMS_ACTION_TRANSFER_AND_ACK;
+ new_list->route[0].storage_type = QMI_WMS_STORAGE_TYPE_NV;
+ new_list->route[0].action = QMI_WMS_ACTION_STORE_AND_NOTIFY;
param = qmi_param_new();
if (!param)
@@ -478,9 +702,9 @@ static void get_routes_cb(struct qmi_result *result, void *user_data)
qmi_param_append(param, QMI_WMS_PARAM_ROUTE_LIST, len, new_list);
qmi_param_append_uint8(param, QMI_WMS_PARAM_STATUS_REPORT, 0x01);
- if (qmi_service_send(data->wms, QMI_WMS_SET_ROUTES, param,
- set_routes_cb, sms, NULL) > 0)
- return;
+ if (qmi_service_send(data->wms, QMI_WMS_SET_ROUTES, param,
+ set_routes_cb, sms, NULL) > 0)
+ return;
qmi_param_free(param);
diff --git a/drivers/qmimodem/wms.h b/drivers/qmimodem/wms.h
index 7e18ec9d..f53fc1bd 100644
--- a/drivers/qmimodem/wms.h
+++ b/drivers/qmimodem/wms.h
@@ -25,8 +25,9 @@
#define QMI_WMS_RAW_SEND 32 /* Send a raw message */
-#define QMI_WMS_RAW_READ 34 /* Read raw message from storage*/
-
+#define QMI_WMS_RAW_READ 34 /* Read raw message from storage */
+#define QMI_WMS_DELETE 36 /* Delete message */
+#define QMI_WMS_GET_MSG_PROTOCOL 48 /* Get message protocol */
#define QMI_WMS_GET_MSG_LIST 49 /* Get list of messages from the device */
#define QMI_WMS_SET_ROUTES 50 /* Set routes for message memory storage */
#define QMI_WMS_GET_ROUTES 51 /* Get routes for message memory storage */
@@ -45,6 +46,17 @@ struct qmi_wms_result_new_msg_notify {
uint32_t storage_index;
} __attribute__((__packed__));
+#define QMI_WMS_RESULT_MESSAGE 0x11
+struct qmi_wms_result_message {
+ uint8_t ack_required; /* bool */
+ uint32_t transaction_id;
+ uint8_t msg_format;
+ uint16_t msg_length;
+ uint8_t msg_data[0];
+} __attribute__((__packed__));
+
+#define QMI_WMS_RESULT_MSG_MODE 0x12
+
/* Set new message conditions */
#define QMI_WMS_PARAM_NEW_MSG_REPORT 0x10 /* bool */
@@ -57,23 +69,59 @@ struct qmi_wms_param_message {
} __attribute__((__packed__));
#define QMI_WMS_RESULT_MESSAGE_ID 0x01 /* uint16 */
+/* Read a raw message */
+#define QMI_WMS_PARAM_READ_MSG 0x01
+struct qmi_wms_read_msg_id {
+ uint8_t type;
+ uint32_t ndx;
+} __attribute__((__packed__));
+
+#define QMI_WMS_PARAM_READ_MODE 0x10
+
+#define QMI_WMS_RESULT_READ_MSG 0x01
+struct qmi_wms_raw_message {
+ uint8_t msg_tag;
+ uint8_t msg_format;
+ uint16_t msg_length;
+ uint8_t msg_data[0];
+} __attribute__((__packed__));
+
+/* Delete messages */
+#define QMI_WMS_PARAM_DEL_STORE 0x01
+#define QMI_WMS_PARAM_DEL_NDX 0x10
+#define QMI_WMS_PARAM_DEL_TYPE 0x11
+#define QMI_WMS_PARAM_DEL_MODE 0x12
+
+/* Get message protocol */
+#define QMI_WMS_PARAM_PROTOCOL 0x01
+
/* Get list of messages from the device */
#define QMI_WMS_PARAM_STORAGE_TYPE 0x01 /* uint8 */
+#define QMI_WMS_PARAM_TAG_TYPE 0x10
#define QMI_WMS_PARAM_MESSAGE_MODE 0x11 /* uint8 */
+#define QMI_WMS_RESULT_MSG_LIST 0x01
+struct qmi_wms_result_msg_list {
+ uint32_t cnt;
+ struct {
+ uint32_t ndx;
+ uint8_t type;
+ } __attribute__((__packed__)) msg[0];
+} __attribute__((__packed__));
+
#define QMI_WMS_STORAGE_TYPE_UIM 0
#define QMI_WMS_STORAGE_TYPE_NV 1
#define QMI_WMS_STORAGE_TYPE_UNKNOWN 2
#define QMI_WMS_STORAGE_TYPE_NONE 255
-#define QMI_WMS_MESSAGE_MODE_GSMWCDMA 1
+#define QMI_WMS_MT_READ 0x00
+#define QMI_WMS_MT_NOT_READ 0x01
+#define QMI_WMS_MO_SENT 0x02
+#define QMI_WMS_MO_NOT_SENT 0x03
+#define QMI_WMS_MT_UNDEFINE 0xff
-struct qmi_wms_raw_message {
- uint8_t msg_tag;
- uint8_t msg_format;
- uint16_t msg_length;
- uint8_t msg_data[0];
-} __attribute__((__packed__));
+#define QMI_WMS_MESSAGE_MODE_CDMA 0x00
+#define QMI_WMS_MESSAGE_MODE_GSMWCDMA 0x01
/* Get routes for message memory storage */
#define QMI_WMS_RESULT_ROUTE_LIST 0x01
@@ -89,14 +137,6 @@ struct qmi_wms_route_list {
} __attribute__((__packed__));
#define QMI_WMS_RESULT_STATUS_REPORT 0x10 /* bool */
#define QMI_WMS_PARAM_STATUS_REPORT 0x10 /* bool */
-#define QMI_WMS_RESULT_MESSAGE 0x11
-struct qmi_wms_result_message {
- uint8_t ack_required; /* bool */
- uint32_t transaction_id;
- uint8_t msg_format;
- uint16_t msg_length;
- uint8_t msg_data[0];
-} __attribute__((__packed__));
#define QMI_WMS_MSG_TYPE_P2P 0x00
#define QMI_WMS_MSG_TYPE_BROADCAST 0x01
@@ -134,3 +174,6 @@ struct qmi_wms_result_smsc_addr {
#define QMI_WMS_DOMAIN_PS_PREFERRED 0x01
#define QMI_WMS_DOMAIN_CS_ONLY 0x02
#define QMI_WMS_DOMAIN_PS_ONLY 0x03
+
+/* Error code */
+#define QMI_ERR_OP_DEVICE_UNSUPPORTED 0x19
--
2.20.1
1 year, 9 months