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.
This commit is contained in:
Aleksander Morgado
2016-10-12 13:24:09 +02:00
parent e6e53467ee
commit e64b964e8e
2 changed files with 166 additions and 3 deletions
+160 -3
View File
@@ -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;
};
/*****************************************************************************/
@@ -526,6 +533,152 @@ disconnect_3gpp (MMBroadbandBearer *self,
g_free (cmd);
}
/*****************************************************************************/
/* 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 *
@@ -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;
+6
View File
@@ -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;