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.
This commit is contained in:
+238
-2
@@ -53,6 +53,8 @@
|
||||
#include "mm-port-serial-qcdm.h"
|
||||
#include "libqcdm/src/errors.h"
|
||||
#include "libqcdm/src/commands.h"
|
||||
#include "libqcdm/src/logs.h"
|
||||
#include "libqcdm/src/log-items.h"
|
||||
|
||||
static void iface_modem_init (MMIfaceModem *iface);
|
||||
static void iface_modem_3gpp_init (MMIfaceModem3gpp *iface);
|
||||
@@ -172,6 +174,7 @@ struct _MMBroadbandModemPrivate {
|
||||
gboolean checked_sprint_support;
|
||||
gboolean has_spservice;
|
||||
gboolean has_speri;
|
||||
gint evdo_pilot_rssi;
|
||||
|
||||
/*<--- Modem Simple interface --->*/
|
||||
/* Properties */
|
||||
@@ -1713,6 +1716,45 @@ modem_load_supported_ip_families (MMIfaceModem *self,
|
||||
/*****************************************************************************/
|
||||
/* Signal quality loading (Modem interface) */
|
||||
|
||||
static void
|
||||
qcdm_evdo_pilot_sets_log_handle (MMPortSerialQcdm *port,
|
||||
GByteArray *log_buffer,
|
||||
gpointer user_data)
|
||||
{
|
||||
MMBroadbandModem *self = MM_BROADBAND_MODEM (user_data);
|
||||
QcdmResult *result;
|
||||
u_int32_t num_active = 0;
|
||||
u_int32_t pilot_pn = 0;
|
||||
u_int32_t pilot_energy = 0;
|
||||
int32_t rssi_dbm = 0;
|
||||
|
||||
result = qcdm_log_item_evdo_pilot_sets_v2_new ((const char *) log_buffer->data,
|
||||
log_buffer->len,
|
||||
NULL);
|
||||
if (!result)
|
||||
return;
|
||||
|
||||
if (!qcdm_log_item_evdo_pilot_sets_v2_get_num (result,
|
||||
QCDM_LOG_ITEM_EVDO_PILOT_SETS_V2_TYPE_ACTIVE,
|
||||
&num_active)) {
|
||||
qcdm_result_unref (result);
|
||||
return;
|
||||
}
|
||||
|
||||
if (num_active > 0 &&
|
||||
qcdm_log_item_evdo_pilot_sets_v2_get_pilot (result,
|
||||
QCDM_LOG_ITEM_EVDO_PILOT_SETS_V2_TYPE_ACTIVE,
|
||||
0,
|
||||
&pilot_pn,
|
||||
&pilot_energy,
|
||||
&rssi_dbm)) {
|
||||
mm_dbg ("EVDO active pilot RSSI: %ddBm", rssi_dbm);
|
||||
self->priv->evdo_pilot_rssi = rssi_dbm;
|
||||
}
|
||||
|
||||
qcdm_result_unref (result);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
MMBroadbandModem *self;
|
||||
GSimpleAsyncResult *result;
|
||||
@@ -1742,6 +1784,21 @@ modem_load_signal_quality_finish (MMIfaceModem *self,
|
||||
G_SIMPLE_ASYNC_RESULT (res)));
|
||||
}
|
||||
|
||||
static guint
|
||||
signal_quality_evdo_pilot_sets (MMBroadbandModem *self)
|
||||
{
|
||||
gint dbm;
|
||||
|
||||
if (self->priv->modem_cdma_evdo_registration_state == MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN)
|
||||
return 0;
|
||||
|
||||
if (self->priv->evdo_pilot_rssi >= 0)
|
||||
return 0;
|
||||
|
||||
dbm = CLAMP (self->priv->evdo_pilot_rssi, -113, -51);
|
||||
return 100 - ((dbm + 51) * 100 / (-113 + 51));
|
||||
}
|
||||
|
||||
static void
|
||||
signal_quality_csq_ready (MMBroadbandModem *self,
|
||||
GAsyncResult *res,
|
||||
@@ -1767,8 +1824,11 @@ signal_quality_csq_ready (MMBroadbandModem *self,
|
||||
result_str = mm_strip_tag (result_str, "+CSQ:");
|
||||
if (sscanf (result_str, "%d, %d", &quality, &ber)) {
|
||||
if (quality == 99) {
|
||||
/* 99 means unknown, no service, etc */
|
||||
quality = 0;
|
||||
/* 99 can mean unknown, no service, etc. But the modem may
|
||||
* also only report CDMA 1x quality in CSQ, so try EVDO via
|
||||
* QCDM log messages too.
|
||||
*/
|
||||
quality = signal_quality_evdo_pilot_sets (self);
|
||||
} else {
|
||||
/* Normalize the quality */
|
||||
quality = CLAMP (quality, 0, 31) * 100 / 31;
|
||||
@@ -1977,6 +2037,17 @@ static void
|
||||
signal_quality_qcdm (SignalQualityContext *ctx)
|
||||
{
|
||||
GByteArray *pilot_sets;
|
||||
guint quality;
|
||||
|
||||
/* If EVDO is active try that signal strength first */
|
||||
quality = signal_quality_evdo_pilot_sets (ctx->self);
|
||||
if (quality > 0) {
|
||||
g_simple_async_result_set_op_res_gpointer (ctx->result,
|
||||
GUINT_TO_POINTER (quality),
|
||||
NULL);
|
||||
signal_quality_context_complete_and_free (ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Use CDMA1x pilot EC/IO if we can */
|
||||
pilot_sets = g_byte_array_sized_new (25);
|
||||
@@ -6712,6 +6783,167 @@ modem_cdma_load_meid (MMIfaceModemCdma *self,
|
||||
user_data);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Setup/Cleanup unsolicited events (CDMA interface) */
|
||||
|
||||
typedef struct {
|
||||
MMBroadbandModem *self;
|
||||
gboolean setup;
|
||||
GSimpleAsyncResult *result;
|
||||
MMPortSerialQcdm *qcdm;
|
||||
} CdmaUnsolicitedEventsContext;
|
||||
|
||||
static void
|
||||
cdma_unsolicited_events_context_complete_and_free (CdmaUnsolicitedEventsContext *ctx,
|
||||
gboolean close_port,
|
||||
GError *error)
|
||||
{
|
||||
if (error)
|
||||
g_simple_async_result_take_error (ctx->result, error);
|
||||
else
|
||||
g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE);
|
||||
g_simple_async_result_complete_in_idle (ctx->result);
|
||||
|
||||
g_clear_object (&ctx->result);
|
||||
g_clear_object (&ctx->self);
|
||||
|
||||
if (ctx->qcdm && close_port)
|
||||
mm_port_serial_close (MM_PORT_SERIAL (ctx->qcdm));
|
||||
g_clear_object (&ctx->qcdm);
|
||||
|
||||
g_free (ctx);
|
||||
}
|
||||
|
||||
static void
|
||||
logcmd_qcdm_ready (MMPortSerialQcdm *port,
|
||||
GAsyncResult *res,
|
||||
CdmaUnsolicitedEventsContext *ctx)
|
||||
{
|
||||
QcdmResult *result;
|
||||
gint err = QCDM_SUCCESS;
|
||||
GByteArray *response;
|
||||
GError *error = NULL;
|
||||
|
||||
response = mm_port_serial_qcdm_command_finish (port, res, &error);
|
||||
if (error) {
|
||||
cdma_unsolicited_events_context_complete_and_free (ctx, TRUE, error);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Parse the response */
|
||||
result = qcdm_cmd_log_config_set_mask_result ((const gchar *) response->data,
|
||||
response->len,
|
||||
&err);
|
||||
g_byte_array_unref (response);
|
||||
if (!result) {
|
||||
error = g_error_new (MM_CORE_ERROR,
|
||||
MM_CORE_ERROR_FAILED,
|
||||
"Failed to parse Log Config Set Mask command result: %d",
|
||||
err);
|
||||
cdma_unsolicited_events_context_complete_and_free (ctx, TRUE, error);
|
||||
return;
|
||||
}
|
||||
|
||||
mm_port_serial_qcdm_add_unsolicited_msg_handler (port,
|
||||
DM_LOG_ITEM_EVDO_PILOT_SETS_V2,
|
||||
ctx->setup ? qcdm_evdo_pilot_sets_log_handle : NULL,
|
||||
ctx->self,
|
||||
NULL);
|
||||
|
||||
qcdm_result_unref (result);
|
||||
|
||||
/* Balance the mm_port_seral_open() from modem_cdma_setup_cleanup_unsolicited_events().
|
||||
* We want to close it in either case:
|
||||
* (a) we're cleaning up and setup opened the port
|
||||
* (b) if it was unexpectedly closed before cleanup and thus cleanup opened it
|
||||
*
|
||||
* Setup should leave the port open to allow log messages to be received
|
||||
* and sent to handlers.
|
||||
*/
|
||||
cdma_unsolicited_events_context_complete_and_free (ctx, ctx->setup ? FALSE : TRUE, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
modem_cdma_setup_cleanup_unsolicited_events (MMBroadbandModem *self,
|
||||
gboolean setup,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
CdmaUnsolicitedEventsContext *ctx;
|
||||
GByteArray *logcmd;
|
||||
u_int16_t log_items[] = { DM_LOG_ITEM_EVDO_PILOT_SETS_V2, 0 };
|
||||
GError *error = NULL;
|
||||
|
||||
ctx = g_new0 (CdmaUnsolicitedEventsContext, 1);
|
||||
ctx->self = g_object_ref (self);
|
||||
ctx->setup = TRUE;
|
||||
ctx->result = g_simple_async_result_new (G_OBJECT (self),
|
||||
callback,
|
||||
user_data,
|
||||
modem_cdma_setup_cleanup_unsolicited_events);
|
||||
ctx->qcdm = mm_base_modem_get_port_qcdm (MM_BASE_MODEM (self));
|
||||
if (!ctx->qcdm) {
|
||||
cdma_unsolicited_events_context_complete_and_free (ctx, FALSE, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Setup must open the QCDM port and keep it open to receive unsolicited
|
||||
* events. Cleanup expects the port to already be opened from setup, but
|
||||
* if not we still want to open it and try to disable log messages.
|
||||
*/
|
||||
if (setup || !mm_port_serial_is_open (MM_PORT_SERIAL (ctx->qcdm))) {
|
||||
if (!mm_port_serial_open (MM_PORT_SERIAL (ctx->qcdm), &error)) {
|
||||
cdma_unsolicited_events_context_complete_and_free (ctx, FALSE, error);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
logcmd = g_byte_array_sized_new (512);
|
||||
logcmd->len = qcdm_cmd_log_config_set_mask_new ((char *) logcmd->data,
|
||||
512,
|
||||
0x01, /* Equipment ID */
|
||||
setup ? log_items : NULL);
|
||||
assert (logcmd->len);
|
||||
|
||||
mm_port_serial_qcdm_command (ctx->qcdm,
|
||||
logcmd,
|
||||
5,
|
||||
NULL,
|
||||
(GAsyncReadyCallback)logcmd_qcdm_ready,
|
||||
ctx);
|
||||
g_byte_array_unref (logcmd);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
modem_cdma_setup_cleanup_unsolicited_events_finish (MMIfaceModemCdma *self,
|
||||
GAsyncResult *res,
|
||||
GError **error)
|
||||
{
|
||||
return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error);
|
||||
}
|
||||
|
||||
static void
|
||||
modem_cdma_setup_unsolicited_events (MMIfaceModemCdma *self,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
modem_cdma_setup_cleanup_unsolicited_events (MM_BROADBAND_MODEM (self),
|
||||
TRUE,
|
||||
callback,
|
||||
user_data);
|
||||
}
|
||||
|
||||
static void
|
||||
modem_cdma_cleanup_unsolicited_events (MMIfaceModemCdma *self,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
modem_cdma_setup_cleanup_unsolicited_events (MM_BROADBAND_MODEM (self),
|
||||
FALSE,
|
||||
callback,
|
||||
user_data);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* HDR state check (CDMA interface) */
|
||||
|
||||
@@ -10429,6 +10661,10 @@ iface_modem_cdma_init (MMIfaceModemCdma *iface)
|
||||
iface->load_meid_finish = modem_cdma_load_meid_finish;
|
||||
|
||||
/* Registration check steps */
|
||||
iface->setup_unsolicited_events = modem_cdma_setup_unsolicited_events;
|
||||
iface->setup_unsolicited_events_finish = modem_cdma_setup_cleanup_unsolicited_events_finish;
|
||||
iface->cleanup_unsolicited_events = modem_cdma_cleanup_unsolicited_events;
|
||||
iface->cleanup_unsolicited_events_finish = modem_cdma_setup_cleanup_unsolicited_events_finish;
|
||||
iface->setup_registration_checks = modem_cdma_setup_registration_checks;
|
||||
iface->setup_registration_checks_finish = modem_cdma_setup_registration_checks_finish;
|
||||
iface->get_call_manager_state = modem_cdma_get_call_manager_state;
|
||||
|
||||
+156
-4
@@ -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;
|
||||
|
||||
@@ -31,9 +31,11 @@
|
||||
|
||||
typedef struct _MMPortSerialQcdm MMPortSerialQcdm;
|
||||
typedef struct _MMPortSerialQcdmClass MMPortSerialQcdmClass;
|
||||
typedef struct _MMPortSerialQcdmPrivate MMPortSerialQcdmPrivate;
|
||||
|
||||
struct _MMPortSerialQcdm {
|
||||
MMPortSerial parent;
|
||||
MMPortSerialQcdmPrivate *priv;
|
||||
};
|
||||
|
||||
struct _MMPortSerialQcdmClass {
|
||||
@@ -55,4 +57,18 @@ GByteArray *mm_port_serial_qcdm_command_finish (MMPortSerialQcdm *self,
|
||||
GAsyncResult *res,
|
||||
GError **error);
|
||||
|
||||
typedef void (*MMPortSerialQcdmUnsolicitedMsgFn) (MMPortSerialQcdm *port,
|
||||
GByteArray *log_buffer,
|
||||
gpointer user_data);
|
||||
|
||||
void mm_port_serial_qcdm_add_unsolicited_msg_handler (MMPortSerialQcdm *self,
|
||||
guint log_code,
|
||||
MMPortSerialQcdmUnsolicitedMsgFn callback,
|
||||
gpointer user_data,
|
||||
GDestroyNotify notify);
|
||||
|
||||
void mm_port_serial_qcdm_enable_unsolicited_msg_handler (MMPortSerialQcdm *self,
|
||||
guint log_code,
|
||||
gboolean enable);
|
||||
|
||||
#endif /* MM_PORT_SERIAL_QCDM_H */
|
||||
|
||||
Reference in New Issue
Block a user