diff options
author | Dan Williams <dcbw@redhat.com> | 2016-07-25 23:07:03 -0500 |
---|---|---|
committer | Dan Williams <dcbw@redhat.com> | 2016-07-27 10:44:43 -0500 |
commit | 5350b9f568dc4375c874a3e3912458d512a3cbe4 (patch) | |
tree | 4f4929183f2ba3d1a7360ccce7149ed2d0555081 /src/mm-port-serial-qcdm.c | |
parent | 30f60de7d3f4d61a100ce1e6a01a746bd2409b81 (diff) |
broadband-modem/libqcdm: add signal strength from QCDM EVDO Pilot Sets log messages
When a CDMA-only modem is registered with the EVDO network, its not possible to
read signal strength in the following cases:
1) while a data connection is active on single-AT-port modems, because the AT
port is used for PPP and not available for AT+CSQ, AT+CIND or vendor-specific
signal strength commands
2) when the modem reports only CDMA 1x signal strength with AT+CSQ
Now that we have a reasonable interpretation of RSSI from the QCDM
EVDO Pilot Sets V2 log messgae, use that when other means of getting
signal strength aren't available.
Diffstat (limited to 'src/mm-port-serial-qcdm.c')
-rw-r--r-- | src/mm-port-serial-qcdm.c | 160 |
1 files changed, 156 insertions, 4 deletions
diff --git a/src/mm-port-serial-qcdm.c b/src/mm-port-serial-qcdm.c index 7732851f..e997bb06 100644 --- a/src/mm-port-serial-qcdm.c +++ b/src/mm-port-serial-qcdm.c @@ -26,10 +26,15 @@ #include "libqcdm/src/com.h" #include "libqcdm/src/utils.h" #include "libqcdm/src/errors.h" +#include "libqcdm/src/dm-commands.h" #include "mm-log.h" G_DEFINE_TYPE (MMPortSerialQcdm, mm_port_serial_qcdm, MM_TYPE_PORT_SERIAL) +struct _MMPortSerialQcdmPrivate { + GSList *unsolicited_msg_handlers; +}; + /*****************************************************************************/ static gboolean @@ -60,10 +65,10 @@ find_qcdm_start (GByteArray *response, gsize *start) } static MMPortSerialResponseType -parse_response (MMPortSerial *port, - GByteArray *response, - GByteArray **parsed_response, - GError **error) +parse_qcdm (GByteArray *response, + gboolean want_log, + GByteArray **parsed_response, + GError **error) { gsize start = 0; gsize used = 0; @@ -111,6 +116,14 @@ parse_response (MMPortSerial *port, return MM_PORT_SERIAL_RESPONSE_NONE; } + if (want_log && unescaped_buffer[0] != DIAG_CMD_LOG) { + /* If we only want log items and this isn't one, don't remove this + * DM packet from the buffer. + */ + g_free (unescaped_buffer); + return MM_PORT_SERIAL_RESPONSE_NONE; + } + /* Successfully decapsulated the DM command. We'll build a new byte array * with the response, and leave the input buffer cleaned up. */ g_assert (unescaped_len <= 1024); @@ -124,6 +137,15 @@ parse_response (MMPortSerial *port, return MM_PORT_SERIAL_RESPONSE_BUFFER; } +static MMPortSerialResponseType +parse_response (MMPortSerial *port, + GByteArray *response, + GByteArray **parsed_response, + GError **error) +{ + return parse_qcdm (response, FALSE, parsed_response, error); +} + /*****************************************************************************/ GByteArray * @@ -202,6 +224,111 @@ debug_log (MMPortSerial *port, const char *prefix, const char *buf, gsize len) /*****************************************************************************/ +typedef struct { + guint log_code; + MMPortSerialQcdmUnsolicitedMsgFn callback; + gboolean enable; + gpointer user_data; + GDestroyNotify notify; +} MMQcdmUnsolicitedMsgHandler; + +static gint +unsolicited_msg_handler_cmp (MMQcdmUnsolicitedMsgHandler *handler, + gpointer log_code) +{ + return handler->log_code - GPOINTER_TO_UINT (log_code); +} + +void +mm_port_serial_qcdm_add_unsolicited_msg_handler (MMPortSerialQcdm *self, + guint log_code, + MMPortSerialQcdmUnsolicitedMsgFn callback, + gpointer user_data, + GDestroyNotify notify) +{ + GSList *existing; + MMQcdmUnsolicitedMsgHandler *handler; + + g_return_if_fail (MM_IS_PORT_SERIAL_QCDM (self)); + g_return_if_fail (log_code > 0 && log_code <= G_MAXUINT16); + + existing = g_slist_find_custom (self->priv->unsolicited_msg_handlers, + GUINT_TO_POINTER (log_code), + (GCompareFunc)unsolicited_msg_handler_cmp); + if (existing) { + handler = existing->data; + /* We OVERWRITE any existing one, so if any context data existing, free it */ + if (handler->notify) + handler->notify (handler->user_data); + } else { + handler = g_slice_new (MMQcdmUnsolicitedMsgHandler); + self->priv->unsolicited_msg_handlers = g_slist_append (self->priv->unsolicited_msg_handlers, handler); + handler->log_code = log_code; + } + + handler->callback = callback; + handler->enable = TRUE; + handler->user_data = user_data; + handler->notify = notify; +} + +void +mm_port_serial_qcdm_enable_unsolicited_msg_handler (MMPortSerialQcdm *self, + guint log_code, + gboolean enable) +{ + GSList *existing; + MMQcdmUnsolicitedMsgHandler *handler; + + g_return_if_fail (MM_IS_PORT_SERIAL_QCDM (self)); + g_return_if_fail (log_code > 0 && log_code <= G_MAXUINT16); + + existing = g_slist_find_custom (self->priv->unsolicited_msg_handlers, + GUINT_TO_POINTER (log_code), + (GCompareFunc)unsolicited_msg_handler_cmp); + if (existing) { + handler = existing->data; + handler->enable = enable; + } +} + +static void +parse_unsolicited (MMPortSerial *port, GByteArray *response) +{ + MMPortSerialQcdm *self = MM_PORT_SERIAL_QCDM (port); + GByteArray *log_buffer = NULL; + GSList *iter; + + if (parse_qcdm (response, + TRUE, + &log_buffer, + NULL) != MM_PORT_SERIAL_RESPONSE_BUFFER) { + return; + } + + /* These should be guaranteed by parse_qcdm() */ + g_return_if_fail (log_buffer); + g_return_if_fail (log_buffer->len > 0); + g_return_if_fail (log_buffer->data[0] == DIAG_CMD_LOG); + + if (log_buffer->len < sizeof (DMCmdLog)) + return; + + for (iter = self->priv->unsolicited_msg_handlers; iter; iter = iter->next) { + MMQcdmUnsolicitedMsgHandler *handler = (MMQcdmUnsolicitedMsgHandler *) iter->data; + DMCmdLog *log_cmd = (DMCmdLog *) log_buffer->data; + + if (!handler->enable) + continue; + if (handler->log_code != le16toh (log_cmd->log_code)) + continue; + if (handler->callback) + handler->callback (self, log_buffer, handler->user_data); + } +} + +/*****************************************************************************/ + static gboolean config_fd (MMPortSerial *port, int fd, GError **error) { @@ -250,14 +377,39 @@ mm_port_serial_qcdm_new_fd (int fd) static void mm_port_serial_qcdm_init (MMPortSerialQcdm *self) { + self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, MM_TYPE_PORT_SERIAL_QCDM, MMPortSerialQcdmPrivate); +} + +static void +finalize (GObject *object) +{ + MMPortSerialQcdm *self = MM_PORT_SERIAL_QCDM (object); + + while (self->priv->unsolicited_msg_handlers) { + MMQcdmUnsolicitedMsgHandler *handler = (MMQcdmUnsolicitedMsgHandler *) self->priv->unsolicited_msg_handlers->data; + + if (handler->notify) + handler->notify (handler->user_data); + + g_slice_free (MMQcdmUnsolicitedMsgHandler, handler); + self->priv->unsolicited_msg_handlers = g_slist_delete_link (self->priv->unsolicited_msg_handlers, + self->priv->unsolicited_msg_handlers); + } + + G_OBJECT_CLASS (mm_port_serial_qcdm_parent_class)->finalize (object); } static void mm_port_serial_qcdm_class_init (MMPortSerialQcdmClass *klass) { + GObjectClass *object_class = G_OBJECT_CLASS (klass); MMPortSerialClass *port_class = MM_PORT_SERIAL_CLASS (klass); + g_type_class_add_private (object_class, sizeof (MMPortSerialQcdmPrivate)); + /* Virtual methods */ + object_class->finalize = finalize; + port_class->parse_unsolicited = parse_unsolicited; port_class->parse_response = parse_response; port_class->config_fd = config_fd; port_class->debug_log = debug_log; |