aboutsummaryrefslogtreecommitdiff
path: root/plugins/ublox/mm-broadband-modem-ublox.c
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/ublox/mm-broadband-modem-ublox.c')
-rw-r--r--plugins/ublox/mm-broadband-modem-ublox.c285
1 files changed, 170 insertions, 115 deletions
diff --git a/plugins/ublox/mm-broadband-modem-ublox.c b/plugins/ublox/mm-broadband-modem-ublox.c
index 83352fa8..9c6c55e2 100644
--- a/plugins/ublox/mm-broadband-modem-ublox.c
+++ b/plugins/ublox/mm-broadband-modem-ublox.c
@@ -44,11 +44,6 @@ G_DEFINE_TYPE_EXTENDED (MMBroadbandModemUblox, mm_broadband_modem_ublox, MM_TYPE
G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM, iface_modem_init)
G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_VOICE, iface_modem_voice_init))
-typedef enum {
- FEATURE_SUPPORT_UNKNOWN,
- FEATURE_SUPPORTED,
- FEATURE_UNSUPPORTED,
-} FeatureSupport;
struct _MMBroadbandModemUbloxPrivate {
/* USB profile in use */
@@ -64,8 +59,11 @@ struct _MMBroadbandModemUbloxPrivate {
/* Mode combination to apply if "any" requested */
MMModemMode any_allowed;
- /* Band management */
- FeatureSupport uact;
+ /* AT command configuration */
+ UbloxSupportConfig support_config;
+
+ /* Operator ID for manual registration */
+ gchar *operator_id;
/* Regex to ignore */
GRegex *pbready_regex;
@@ -73,7 +71,6 @@ struct _MMBroadbandModemUbloxPrivate {
/*****************************************************************************/
-static gboolean
acquire_power_operation (MMBroadbandModemUblox *self,
GError **error)
{
@@ -105,59 +102,27 @@ load_supported_bands_finish (MMIfaceModem *self,
}
static void
-uact_test_ready (MMBaseModem *_self,
- GAsyncResult *res,
- GTask *task)
+load_supported_bands (MMIfaceModem *_self,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
{
- MMBroadbandModemUblox *self = MM_BROADBAND_MODEM_UBLOX (_self);
- const gchar *response;
- GError *error = NULL;
- GArray *bands = NULL;
- GArray *bands_2g = NULL;
- GArray *bands_3g = NULL;
- GArray *bands_4g = NULL;
-
- response = mm_base_modem_at_command_finish (_self, res, NULL);
- if (!response) {
- /* Flag as unsupported */
- self->priv->uact = FEATURE_UNSUPPORTED;
-
- /* The list of supported tasks we give here must include not only the bands
- * allowed in the current AcT, but the whole list of bands allowed in all
- * AcTs. This is because the list of supported bands is loaded only once
- * during modem initialization. Not ideal, but the current API is like that.
- *
- * So, we give a predefined list of supported bands and we filter them in the
- * same way we filter the allowed AcTs.
- */
- bands = mm_ublox_get_supported_bands (mm_iface_modem_get_model (MM_IFACE_MODEM (self)), &error);
- goto out;
- }
+ MMBroadbandModemUblox *self = MM_BROADBAND_MODEM_UBLOX (_self);
+ GTask *task;
+ GError *error = NULL;
+ GArray *bands = NULL;
+ const gchar *model;
- /* Flag as supported */
- self->priv->uact = FEATURE_SUPPORTED;
+ model = mm_iface_modem_get_model (_self);
- /* Parse UACT=? test response */
- if (!mm_ublox_parse_uact_test (response, &bands_2g, &bands_3g, &bands_4g, &error))
- goto out;
+ task = g_task_new (_self, NULL, callback, user_data);
+
+ bands = mm_ublox_get_supported_bands (model, &error);
- /* Build a combined array */
- bands = g_array_new (FALSE, FALSE, sizeof (MMModemBand));
- if (bands_2g) {
- bands = g_array_append_vals (bands, bands_2g->data, bands_2g->len);
- g_array_unref (bands_2g);
- }
- if (bands_3g) {
- bands = g_array_append_vals (bands, bands_3g->data, bands_3g->len);
- g_array_unref (bands_3g);
- }
- if (bands_4g) {
- bands = g_array_append_vals (bands, bands_4g->data, bands_4g->len);
- g_array_unref (bands_4g);
+ if (!mm_ublox_get_support_config (model, &self->priv->support_config, &error)) {
+ g_assert (error);
+ g_task_return_error (task, error);
}
- g_assert (bands->len > 0);
-
-out:
+
if (!bands) {
g_assert (error);
g_task_return_error (task, error);
@@ -166,25 +131,6 @@ out:
g_object_unref (task);
}
-static void
-load_supported_bands (MMIfaceModem *self,
- GAsyncReadyCallback callback,
- gpointer user_data)
-{
- GTask *task;
-
- task = g_task_new (self, NULL, callback, user_data);
-
- /* See if AT+UACT is supported to query bands */
- mm_base_modem_at_command (
- MM_BASE_MODEM (self),
- "+UACT=?",
- 3,
- TRUE, /* allow cached */
- (GAsyncReadyCallback) uact_test_ready,
- task);
-}
-
/*****************************************************************************/
/* Load current bands (Modem interface) */
@@ -195,15 +141,17 @@ load_current_bands_finish (MMIfaceModem *_self,
{
MMBroadbandModemUblox *self = MM_BROADBAND_MODEM_UBLOX (_self);
const gchar *response;
+ const gchar *model;
response = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, error);
+ model = mm_iface_modem_get_model (_self);
if (!response)
return NULL;
- if (self->priv->uact == FEATURE_SUPPORTED)
+ if (self->priv->support_config.uact == FEATURE_SUPPORTED)
return mm_ublox_parse_uact_response (response, error);
- return mm_ublox_parse_ubandsel_response (response, error);
+ return mm_ublox_parse_ubandsel_response (response, model, error);
}
static void
@@ -213,12 +161,13 @@ load_current_bands (MMIfaceModem *_self,
{
MMBroadbandModemUblox *self = MM_BROADBAND_MODEM_UBLOX (_self);
- g_assert (self->priv->uact != FEATURE_SUPPORT_UNKNOWN);
+ g_assert (self->priv->support_config.uact != FEATURE_SUPPORT_UNKNOWN &&
+ self->priv->support_config.ubandsel != FEATURE_SUPPORT_UNKNOWN);
- if (self->priv->uact == FEATURE_SUPPORTED) {
+ if (self->priv->support_config.ubandsel == FEATURE_SUPPORTED) {
mm_base_modem_at_command (
MM_BASE_MODEM (self),
- "+UACT?",
+ "+UBANDSEL?",
3,
FALSE,
(GAsyncReadyCallback)callback,
@@ -226,13 +175,16 @@ load_current_bands (MMIfaceModem *_self,
return;
}
- mm_base_modem_at_command (
- MM_BASE_MODEM (self),
- "+UBANDSEL?",
- 3,
- FALSE,
- (GAsyncReadyCallback)callback,
- user_data);
+ if (self->priv->support_config.uact == FEATURE_SUPPORTED) {
+ mm_base_modem_at_command (
+ MM_BASE_MODEM (self),
+ "+UACT?",
+ 3,
+ FALSE,
+ (GAsyncReadyCallback)callback,
+ user_data);
+ return;
+ }
}
/*****************************************************************************/
@@ -319,10 +271,11 @@ set_current_modes_bands_command_ready (MMBaseModem *self,
ctx = (SetCurrentModesBandsContext *) g_task_get_task_data (task);
g_assert (ctx);
- mm_base_modem_at_command_finish (self, res, &ctx->saved_error);
-
- /* Go to next step (recover current power) regardless of the result */
- ctx->step++;
+ if (!mm_base_modem_at_command_finish (self, res, &ctx->saved_error))
+ ctx->step = SET_CURRENT_MODES_BANDS_STEP_RELEASE;
+ else
+ ctx->step++;
+
set_current_modes_bands_step (task);
}
@@ -399,15 +352,28 @@ set_current_modes_bands_step (GTask *task)
case SET_CURRENT_MODES_BANDS_STEP_POWER_DOWN:
if (ctx->initial_state != MM_MODEM_POWER_STATE_LOW) {
- mm_dbg ("powering down before configuration change...");
- mm_base_modem_at_command (
- MM_BASE_MODEM (ctx->self),
- "+CFUN=4",
- 3,
- FALSE,
- (GAsyncReadyCallback) set_current_modes_bands_low_power_ready,
- task);
- return;
+ mm_dbg ("powering down and deregistering from the network for configuration change...");
+ if (ctx->self->priv->support_config.method == BAND_UPDATE_NEEDS_COPS) {
+ mm_base_modem_at_command (
+ MM_BASE_MODEM (ctx->self),
+ "+COPS=2",
+ 10,
+ FALSE,
+ (GAsyncReadyCallback) set_current_modes_bands_low_power_ready,
+ task);
+ return;
+ }
+
+ if (ctx->self->priv->support_config.method == BAND_UPDATE_NEEDS_CFUN) {
+ mm_base_modem_at_command (
+ MM_BASE_MODEM (ctx->self),
+ "+CFUN=4",
+ 3,
+ FALSE,
+ (GAsyncReadyCallback) set_current_modes_bands_low_power_ready,
+ task);
+ return;
+ }
}
ctx->step++;
/* fall down */
@@ -426,14 +392,37 @@ set_current_modes_bands_step (GTask *task)
case SET_CURRENT_MODES_BANDS_STEP_RECOVER_CURRENT_POWER:
if (ctx->initial_state != MM_MODEM_POWER_STATE_LOW) {
mm_dbg ("recovering power state after configuration change...");
- mm_base_modem_at_command (
- MM_BASE_MODEM (ctx->self),
- "+CFUN=1",
- 3,
- FALSE,
- (GAsyncReadyCallback) set_current_modes_bands_recover_power_ready,
- task);
- return;
+ if (ctx->self->priv->support_config.method == BAND_UPDATE_NEEDS_COPS) {
+ gchar *command;
+
+ /* If the user sent a specific network to use, lock it in. */
+ if (ctx->self->priv->operator_id)
+ command = g_strdup_printf ("+COPS=1,2,\"%s\"", ctx->self->priv->operator_id);
+ else
+ command = g_strdup ("+COPS=0");
+
+ mm_base_modem_at_command (
+ MM_BASE_MODEM (ctx->self),
+ command,
+ 10,
+ FALSE,
+ (GAsyncReadyCallback) set_current_modes_bands_recover_power_ready,
+ task);
+ g_free (command);
+ return;
+ }
+
+ /* Use this to register if CFUN is needed */
+ if (ctx->self->priv->support_config.method == BAND_UPDATE_NEEDS_CFUN) {
+ mm_base_modem_at_command (
+ MM_BASE_MODEM (ctx->self),
+ "+CFUN=1",
+ 3,
+ FALSE,
+ (GAsyncReadyCallback) set_current_modes_bands_recover_power_ready,
+ task);
+ return;
+ }
}
ctx->step++;
/* fall down */
@@ -490,18 +479,21 @@ set_current_bands (MMIfaceModem *_self,
GAsyncReadyCallback callback,
gpointer user_data)
{
- MMBroadbandModemUblox *self = MM_BROADBAND_MODEM_UBLOX (_self);
+ MMBroadbandModemUblox *self = MM_BROADBAND_MODEM_UBLOX (_self);
GTask *task;
- gchar *command;
GError *error = NULL;
+ gchar *command;
+ const gchar *model;
task = g_task_new (self, NULL, callback, user_data);
+ model = mm_iface_modem_get_model(_self);
+
/* Build command */
- if (self->priv->uact == FEATURE_SUPPORTED)
+ if (self->priv->support_config.uact == FEATURE_SUPPORTED)
command = mm_ublox_build_uact_set_command (bands_array, &error);
- else
- command = mm_ublox_build_ubandsel_set_command (bands_array, &error);
+ else if (self->priv->support_config.ubandsel == FEATURE_SUPPORTED)
+ command = mm_ublox_build_ubandsel_set_command (bands_array, model, &error);
if (!command) {
g_task_return_error (task, error);
@@ -674,6 +666,66 @@ common_modem_power_operation (MMBroadbandModemUblox *self,
task);
}
+/*****************************************************************************/
+/* Register in network (3GPP interface) */
+
+static gboolean
+register_in_network_finish (MMIfaceModem3gpp *self,
+ GAsyncResult *res,
+ GError **error)
+{
+ return g_task_propagate_boolean (G_TASK (res), error);
+}
+
+static void
+cops_write_ready (MMBaseModem *_self,
+ GAsyncResult *res,
+ GTask *task)
+{
+ MMBroadbandModemUblox *self = MM_BROADBAND_MODEM_UBLOX (_self);
+ GError *error = NULL;
+
+ if (!mm_base_modem_at_command_full_finish (_self, res, &error))
+ g_task_return_error (task, error);
+ else {
+ g_free (self->priv->operator_id);
+ self->priv->operator_id = g_strdup (g_task_get_task_data (task));
+ g_task_return_boolean (task, TRUE);
+ }
+ g_object_unref (task);
+}
+
+static void
+register_in_network (MMIfaceModem3gpp *self,
+ const gchar *operator_id,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GTask *task;
+ gchar *command;
+
+ task = g_task_new (self, cancellable, callback, user_data);
+ g_task_set_task_data (task, g_strdup (operator_id), g_free);
+
+ /* If the user sent a specific network to use, lock it in. */
+ if (operator_id)
+ command = g_strdup_printf ("+COPS=1,2,\"%s\"", operator_id);
+ else
+ command = g_strdup ("+COPS=0");
+
+ mm_base_modem_at_command_full (MM_BASE_MODEM (self),
+ mm_base_modem_peek_best_at_port (MM_BASE_MODEM (self), NULL),
+ command,
+ 120,
+ FALSE,
+ FALSE, /* raw */
+ cancellable,
+ (GAsyncReadyCallback)cops_write_ready,
+ task);
+ g_free (command);
+}
+
static void
modem_reset (MMIfaceModem *self,
GAsyncReadyCallback callback,
@@ -1217,8 +1269,9 @@ mm_broadband_modem_ublox_init (MMBroadbandModemUblox *self)
self->priv->profile = MM_UBLOX_USB_PROFILE_UNKNOWN;
self->priv->mode = MM_UBLOX_NETWORKING_MODE_UNKNOWN;
self->priv->any_allowed = MM_MODEM_MODE_NONE;
- self->priv->uact = FEATURE_SUPPORT_UNKNOWN;
-
+ self->priv->support_config.method = BAND_UPDATE_NEEDS_UNKNOWN;
+ self->priv->support_config.uact = FEATURE_SUPPORT_UNKNOWN;
+ self->priv->support_config.ubandsel = FEATURE_SUPPORT_UNKNOWN;
self->priv->pbready_regex = g_regex_new ("\\r\\n\\+PBREADY\\r\\n",
G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
}
@@ -1276,6 +1329,8 @@ finalize (GObject *object)
g_regex_unref (self->priv->pbready_regex);
+ g_free (self->priv->operator_id);
+
G_OBJECT_CLASS (mm_broadband_modem_ublox_parent_class)->finalize (object);
}