diff options
author | Aleksander Morgado <aleksander@aleksander.es> | 2016-08-15 12:35:57 +0200 |
---|---|---|
committer | Aleksander Morgado <aleksander@aleksander.es> | 2016-10-12 13:24:09 +0200 |
commit | e64b964e8e2eb43b5555088a53890640865edbe8 (patch) | |
tree | 8f248232aabe70231155d6c2851ce81245083e8e | |
parent | e6e53467ee738b493cc89c750818ccb688fb5d5f (diff) |
ublox: implement connection statistics loading
The implementation uses +UGCNTRD=? to query whether the per-PDP context
statistics are supported by the device, and if they are, +UGCNTRD is used to
query them.
We only process the statistics for the specific CID we're using.
-rw-r--r-- | plugins/ublox/mm-broadband-bearer-ublox.c | 163 | ||||
-rw-r--r-- | plugins/ublox/mm-modem-helpers-ublox.c | 6 |
2 files changed, 166 insertions, 3 deletions
diff --git a/plugins/ublox/mm-broadband-bearer-ublox.c b/plugins/ublox/mm-broadband-bearer-ublox.c index 82ebdd4c..e3ba90d0 100644 --- a/plugins/ublox/mm-broadband-bearer-ublox.c +++ b/plugins/ublox/mm-broadband-bearer-ublox.c @@ -44,9 +44,16 @@ enum { static GParamSpec *properties[PROP_LAST]; +typedef enum { + FEATURE_SUPPORT_UNKNOWN, + FEATURE_SUPPORTED, + FEATURE_UNSUPPORTED, +} FeatureSupport; + struct _MMBroadbandBearerUbloxPrivate { MMUbloxUsbProfile profile; MMUbloxNetworkingMode mode; + FeatureSupport statistics; }; /*****************************************************************************/ @@ -527,6 +534,152 @@ disconnect_3gpp (MMBroadbandBearer *self, } /*****************************************************************************/ +/* Reload statistics */ + +typedef struct { + guint64 bytes_rx; + guint64 bytes_tx; +} StatsResult; + +static gboolean +reload_stats_finish (MMBaseBearer *self, + guint64 *bytes_rx, + guint64 *bytes_tx, + GAsyncResult *res, + GError **error) +{ + StatsResult *result; + + result = g_task_propagate_pointer (G_TASK (res), error); + if (!result) + return FALSE; + + if (bytes_rx) + *bytes_rx = result->bytes_rx; + if (bytes_tx) + *bytes_tx = result->bytes_tx; + g_free (result); + return TRUE; +} + +static void +ugcntrd_ready (MMBaseModem *modem, + GAsyncResult *res, + GTask *task) +{ + MMBroadbandBearerUblox *self; + const gchar *response; + GError *error = NULL; + guint tx_bytes = 0; + guint rx_bytes = 0; + guint cid; + + self = MM_BROADBAND_BEARER_UBLOX (g_task_get_source_object (task)); + + cid = mm_broadband_bearer_get_3gpp_cid (MM_BROADBAND_BEARER (self)); + + response = mm_base_modem_at_command_finish (modem, res, &error); + if (response) + mm_ublox_parse_ugcntrd_response_for_cid (response, + cid, + &tx_bytes, &rx_bytes, + NULL, NULL, + &error); + + if (error) { + g_prefix_error (&error, "Couldn't load PDP context %u statistics: ", cid); + g_task_return_error (task, error); + } else { + StatsResult *result; + + result = g_new (StatsResult, 1); + result->bytes_rx = rx_bytes; + result->bytes_tx = tx_bytes; + g_task_return_pointer (task, result, (GDestroyNotify) g_free); + } + + g_object_unref (task); +} + +static void +run_reload_stats (MMBroadbandBearerUblox *self, + GTask *task) +{ + /* Unsupported? */ + if (self->priv->statistics == FEATURE_UNSUPPORTED) { + g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED, + "Loading statistics isn't supported by this device"); + g_object_unref (task); + return; + } + + /* Supported */ + if (self->priv->statistics == FEATURE_SUPPORTED) { + MMBaseModem *modem = NULL; + + g_object_get (MM_BASE_BEARER (self), + MM_BASE_BEARER_MODEM, &modem, + NULL); + mm_base_modem_at_command (MM_BASE_MODEM (modem), + "+UGCNTRD", + 3, + FALSE, + (GAsyncReadyCallback) ugcntrd_ready, + task); + g_object_unref (modem); + return; + } + + g_assert_not_reached (); +} + +static void +ugcntrd_test_ready (MMBaseModem *modem, + GAsyncResult *res, + GTask *task) +{ + MMBroadbandBearerUblox *self; + + self = MM_BROADBAND_BEARER_UBLOX (g_task_get_source_object (task)); + + if (!mm_base_modem_at_command_finish (modem, res, NULL)) + self->priv->statistics = FEATURE_UNSUPPORTED; + else + self->priv->statistics = FEATURE_SUPPORTED; + + run_reload_stats (self, task); +} + +static void +reload_stats (MMBaseBearer *self, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GTask *task; + + task = g_task_new (self, NULL, callback, user_data); + + if (MM_BROADBAND_BEARER_UBLOX (self)->priv->statistics == FEATURE_SUPPORT_UNKNOWN) { + MMBaseModem *modem = NULL; + + g_object_get (MM_BASE_BEARER (self), + MM_BASE_BEARER_MODEM, &modem, + NULL); + + mm_base_modem_at_command (MM_BASE_MODEM (modem), + "+UGCNTRD=?", + 3, + FALSE, + (GAsyncReadyCallback) ugcntrd_test_ready, + task); + g_object_unref (modem); + return; + } + + run_reload_stats (MM_BROADBAND_BEARER_UBLOX (self), task); +} + +/*****************************************************************************/ MMBaseBearer * mm_broadband_bearer_ublox_new_finish (GAsyncResult *res, @@ -624,14 +777,16 @@ mm_broadband_bearer_ublox_init (MMBroadbandBearerUblox *self) MMBroadbandBearerUbloxPrivate); /* Defaults */ - self->priv->profile = MM_UBLOX_USB_PROFILE_UNKNOWN; - self->priv->mode = MM_UBLOX_NETWORKING_MODE_UNKNOWN; + self->priv->profile = MM_UBLOX_USB_PROFILE_UNKNOWN; + self->priv->mode = MM_UBLOX_NETWORKING_MODE_UNKNOWN; + self->priv->statistics = FEATURE_SUPPORT_UNKNOWN; } static void mm_broadband_bearer_ublox_class_init (MMBroadbandBearerUbloxClass *klass) { - GObjectClass *object_class = G_OBJECT_CLASS (klass); + GObjectClass *object_class = G_OBJECT_CLASS (klass); + MMBaseBearerClass *base_bearer_class = MM_BASE_BEARER_CLASS (klass); MMBroadbandBearerClass *broadband_bearer_class = MM_BROADBAND_BEARER_CLASS (klass); g_type_class_add_private (object_class, sizeof (MMBroadbandBearerUbloxPrivate)); @@ -641,6 +796,8 @@ mm_broadband_bearer_ublox_class_init (MMBroadbandBearerUbloxClass *klass) /* Note: the ublox plugin uses the generic AT+CGACT? based check to monitor * the connection status (i.e. default load_connection_status()) */ + base_bearer_class->reload_stats = reload_stats; + base_bearer_class->reload_stats_finish = reload_stats_finish; broadband_bearer_class->disconnect_3gpp = disconnect_3gpp; broadband_bearer_class->disconnect_3gpp_finish = disconnect_3gpp_finish; diff --git a/plugins/ublox/mm-modem-helpers-ublox.c b/plugins/ublox/mm-modem-helpers-ublox.c index 2e314675..eaaed550 100644 --- a/plugins/ublox/mm-modem-helpers-ublox.c +++ b/plugins/ublox/mm-modem-helpers-ublox.c @@ -986,6 +986,12 @@ mm_ublox_parse_ugcntrd_response_for_cid (const gchar *response, G_REGEX_DOLLAR_ENDONLY | G_REGEX_RAW, 0, NULL); g_assert (r != NULL); + /* Report invalid CID given */ + if (!in_cid) { + inner_error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Invalid CID given"); + goto out; + } + g_regex_match_full (r, response, strlen (response), 0, 0, &match_info, &inner_error); while (!inner_error && g_match_info_matches (match_info)) { guint cid = 0; |