[PATCH] altair-lte: add SIMREFRESH support

Aleksander Morgado aleksander at lanedo.com
Tue Nov 19 00:57:00 PST 2013


Hey Thieu,

See some comments below.


On 14/11/13 23:09, Thieu Le wrote:
> Register for SIMREFRESH event and reload own numbers and reregister
> modem with network when this happens.
> 
> ---
>  plugins/altair/mm-broadband-modem-altair-lte.c | 208 +++++++++++++++++++++++--
>  1 file changed, 191 insertions(+), 17 deletions(-)
> 
> diff --git a/plugins/altair/mm-broadband-modem-altair-lte.c b/plugins/altair/mm-broadband-modem-altair-lte.c
> index 64d4c51..d9cc56b 100644
> --- a/plugins/altair/mm-broadband-modem-altair-lte.c
> +++ b/plugins/altair/mm-broadband-modem-altair-lte.c
> @@ -53,6 +53,12 @@ G_DEFINE_TYPE_EXTENDED (MMBroadbandModemAltairLte, mm_broadband_modem_altair_lte
>                          G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_MESSAGING, iface_modem_messaging_init));
>  
>  struct _MMBroadbandModemAltairLtePrivate {
> +    /* Regex for SIM refresh notifications */
> +    GRegex *sim_refresh_regex;
> +    /* Timer that goes off 10s after the last SIM refresh notification.
> +     * This indicates that there are no more SIM refreshes and we should
> +     * reregister the device.*/
> +    guint sim_refresh_timer_id;
>      /* Regex for bearer related notifications */
>      GRegex *statcm_regex;
>  };
> @@ -634,7 +640,121 @@ modem_3gpp_register_in_network_finish (MMIfaceModem3gpp *self,
>  }
>  
>  /*****************************************************************************/
> -/* Setup/Cleanup unsolicited events (3GPP interface) */
> +/* SIMREFRESH unsolicited event handler */
> +
> +static void
> +altair_reregister_ready (MMBaseModem *self,
> +                         GAsyncResult *res,
> +                         gpointer user_data)
> +{
> +    GError *error = NULL;
> +
> +    mm_base_modem_at_command_full_finish (self, res, &error);
> +    if (error) {
> +        mm_dbg ("Failed to reregister modem");

'error' is being leaked in this case; you should g_error_free() it. If
you're not interested in the actual error, you can always do:

if (!mm_base_modem_at_command_full_finish (self, res, NULL)) {
  mm_dbg ("Failed to reregister modem");
}

> +    } else {
> +        mm_dbg ("Modem reregistered successfully");
> +    }
> +}
> +
> +static void
> +altair_deregister_ready (MMBaseModem *self,
> +                         GAsyncResult *res,
> +                         gpointer user_data)
> +{
> +    GError *error = NULL;
> +
> +    mm_base_modem_at_command_full_finish (self, res, &error);
> +    if (error) {
> +        mm_dbg ("Deregister modem failed");

Same here, 'error' leaked.

> +        return;
> +    }
> +
> +    mm_dbg ("Deregistered modem, now reregistering");
> +
> +    /* Register */
> +    mm_base_modem_at_command_full (
> +        MM_BASE_MODEM (self),
> +        mm_base_modem_peek_port_primary (MM_BASE_MODEM (self)),

Why use the _full() version? Can't you use the normal at_command(),
without specifying the exact port to use?

> +        "%CMATT=1",
> +        10,
> +        FALSE, /* allow_cached */
> +        FALSE, /* raw */
> +        NULL, /* cancellable */
> +        (GAsyncReadyCallback)altair_reregister_ready,
> +        NULL);
> +}
> +
> +static void
> +altair_load_own_numbers_ready (MMIfaceModem *iface_modem,
> +                               GAsyncResult *res,
> +                               MMBroadbandModemAltairLte *self)
> +{
> +    GError *error = NULL;
> +    GStrv str_list;
> +
> +    str_list = MM_IFACE_MODEM_GET_INTERFACE (self)->load_own_numbers_finish (MM_IFACE_MODEM (self), res, &error);
> +    if (error) {
> +        mm_warn ("Couldn't reload Own Numbers: '%s'", error->message);
> +        g_error_free (error);
> +    }
> +    if (str_list) {
> +        MmGdbusModem *skeleton = NULL;
> +        g_object_get (self,
> +                      MM_IFACE_MODEM_DBUS_SKELETON, &skeleton,
> +                      NULL);
> +        if (skeleton) {
> +            mm_dbg ("Reloaded Own Numbers");
> +            mm_gdbus_modem_set_own_numbers (skeleton, (const gchar *const *)str_list);
> +            g_object_unref (skeleton);
> +        }
> +        g_strfreev (str_list);

Plugins shouldn't access the skeleton object directly. If you want to
provide update of the own numbers property out of the normal loading
sequence, better write a new mm_iface_modem_update_own_numbers() method,
and let the iface code handle the skeleton content itself.

> +    }
> +
> +    /* Deregister */
> +    mm_dbg ("Reregistering modem");
> +    mm_base_modem_at_command_full (
> +        MM_BASE_MODEM (self),
> +        mm_base_modem_peek_port_primary (MM_BASE_MODEM (self)),

Same here, is it mandatory to use _command_full() instead of command()?

> +        "%CMATT=0",
> +        10,
> +        FALSE, /* allow_cached */
> +        FALSE, /* raw */
> +        NULL, /* cancellable */
> +        (GAsyncReadyCallback)altair_deregister_ready,
> +        NULL);
> +}
> +
> +static gboolean
> +altair_sim_refresh_timer_expired (MMBroadbandModemAltairLte *self)
> +{
> +    mm_dbg ("No more SIM refreshes, reloading Own Numbers and reregistering modem");
> +
> +    g_assert (MM_IFACE_MODEM_GET_INTERFACE (self)->load_own_numbers);
> +    g_assert (MM_IFACE_MODEM_GET_INTERFACE (self)->load_own_numbers_finish);
> +    MM_IFACE_MODEM_GET_INTERFACE (self)->load_own_numbers (
> +        MM_IFACE_MODEM (self),
> +        (GAsyncReadyCallback)altair_load_own_numbers_ready,
> +        self);
> +
> +    self->priv->sim_refresh_timer_id = 0;
> +    return FALSE;
> +}
> +
> +static void
> +altair_sim_refresh_changed (MMAtSerialPort *port,
> +                            GMatchInfo *match_info,
> +                            MMBroadbandModemAltairLte *self)
> +{
> +    mm_dbg ("Received SIM refresh notification");
> +    if (self->priv->sim_refresh_timer_id) {
> +        g_source_remove (self->priv->sim_refresh_timer_id);
> +    }
> +    self->priv->sim_refresh_timer_id =
> +        g_timeout_add_seconds(10,
> +                              (GSourceFunc)altair_sim_refresh_timer_expired,
> +                              self);
> +}
>  
>  typedef enum {
>      MM_STATCM_ALTAIR_LTE_DEREGISTERED = 0,
> @@ -651,6 +771,9 @@ bearer_list_report_disconnect_status_foreach (MMBearer *bearer,
>                                          MM_BEARER_CONNECTION_STATUS_DISCONNECTED);
>  }
>  
> +/*****************************************************************************/
> +/* STATCM unsolicited event handler */
> +
>  static void
>  altair_statcm_changed (MMAtSerialPort *port,
>                         GMatchInfo *match_info,
> @@ -682,6 +805,9 @@ altair_statcm_changed (MMAtSerialPort *port,
>  
>  }
>  
> +/*****************************************************************************/
> +/* Setup/Cleanup unsolicited events (3GPP interface) */
> +
>  static void
>  set_3gpp_unsolicited_events_handlers (MMBroadbandModemAltairLte *self,
>                                        gboolean enable)
> @@ -697,6 +823,14 @@ set_3gpp_unsolicited_events_handlers (MMBroadbandModemAltairLte *self,
>          if (!ports[i])
>              continue;
>  
> +        /* SIM refresh handler */
> +        mm_at_serial_port_add_unsolicited_msg_handler (
> +            ports[i],
> +            self->priv->sim_refresh_regex,
> +            enable ? (MMAtSerialUnsolicitedMsgFn)altair_sim_refresh_changed : NULL,
> +            enable ? self : NULL,
> +            NULL);
> +
>          /* bearer mode related */
>          mm_at_serial_port_add_unsolicited_msg_handler (
>              ports[i],
> @@ -794,6 +928,31 @@ modem_3gpp_cleanup_unsolicited_events (MMIfaceModem3gpp *self,
>  /* Enabling unsolicited events (3GPP interface) */
>  
>  static gboolean
> +response_processor_no_result_stop_on_error (MMBaseModem *self,
> +                                            gpointer none,
> +                                            const gchar *command,
> +                                            const gchar *response,
> +                                            gboolean last_command,
> +                                            const GError *error,
> +                                            GVariant **result,
> +                                            GError **result_error)
> +{
> +    if (error) {
> +        *result_error = g_error_copy (error);
> +        return TRUE;
> +    }
> +
> +    *result = NULL;
> +    return FALSE;
> +}
> +
> +static const MMBaseModemAtCommand unsolicited_events_enable_sequence[] = {
> +  { "%STATCM=1", 10, FALSE, response_processor_no_result_stop_on_error },
> +  { "%NOTIFYEV=\"SIMREFRESH\",1", 10, FALSE, NULL },
> +  { NULL }
> +};

If it is not mandatory; I would avoid 'stopping on error' in the AT
sequence (i.e. just set a NULL callback). What do you think?

> +
> +static gboolean
>  modem_3gpp_enable_unsolicited_events_finish (MMIfaceModem3gpp *self,
>                                               GAsyncResult *res,
>                                               GError **error)
> @@ -808,7 +967,7 @@ own_enable_unsolicited_events_ready (MMBaseModem *self,
>  {
>      GError *error = NULL;
>  
> -    mm_base_modem_at_command_full_finish (self, res, &error);
> +    mm_base_modem_at_sequence_finish (self, res, NULL, &error);
>      if (error)
>          g_simple_async_result_take_error (simple, error);
>      else
> @@ -832,14 +991,11 @@ parent_enable_unsolicited_events_ready (MMIfaceModem3gpp *self,
>      }
>  
>      /* Our own enable now */
> -    mm_base_modem_at_command_full (
> +    mm_base_modem_at_sequence (
>          MM_BASE_MODEM (self),
> -        mm_base_modem_peek_port_primary (MM_BASE_MODEM (self)),
> -        "%STATCM=1",
> -        10,
> -        FALSE, /* allow_cached */
> -        FALSE, /* raw */
> -        NULL, /* cancellable */
> +        unsolicited_events_enable_sequence,
> +        NULL, /* response_processor_context */
> +        NULL, /* response_processor_context_free */
>          (GAsyncReadyCallback)own_enable_unsolicited_events_ready,
>          simple);
>  }
> @@ -866,6 +1022,12 @@ modem_3gpp_enable_unsolicited_events (MMIfaceModem3gpp *self,
>  /*****************************************************************************/
>  /* Disabling unsolicited events (3GPP interface) */
>  
> +static const MMBaseModemAtCommand unsolicited_events_disable_sequence[] = {
> +  { "%STATCM=0", 10, FALSE, NULL },
> +  { "%NOTIFYEV=\"SIMREFRESH\",0", 10, FALSE, NULL },
> +  { NULL }
> +};
> +
>  static gboolean
>  modem_3gpp_disable_unsolicited_events_finish (MMIfaceModem3gpp *self,
>                                                GAsyncResult *res,
> @@ -896,7 +1058,7 @@ own_disable_unsolicited_events_ready (MMBaseModem *self,
>  {
>      GError *error = NULL;
>  
> -    mm_base_modem_at_command_full_finish (self, res, &error);
> +    mm_base_modem_at_sequence_finish (self, res, NULL, &error);
>      if (error) {
>          g_simple_async_result_take_error (simple, error);
>          g_simple_async_result_complete (simple);
> @@ -924,14 +1086,11 @@ modem_3gpp_disable_unsolicited_events (MMIfaceModem3gpp *self,
>                                          modem_3gpp_disable_unsolicited_events);
>  
>      /* Our own disable first */
> -    mm_base_modem_at_command_full (
> +    mm_base_modem_at_sequence (
>          MM_BASE_MODEM (self),
> -        mm_base_modem_peek_port_primary (MM_BASE_MODEM (self)),
> -        "%STATCM=0",
> -        10,
> -        FALSE, /* allow_cached */
> -        FALSE, /* raw */
> -        NULL, /* cancellable */
> +        unsolicited_events_disable_sequence,
> +        NULL, /* response_processor_context */
> +        NULL, /* response_processor_context_free */
>          (GAsyncReadyCallback)own_disable_unsolicited_events_ready,
>          result);
>  }
> @@ -1086,11 +1245,25 @@ mm_broadband_modem_altair_lte_init (MMBroadbandModemAltairLte *self)
>                                                MM_TYPE_BROADBAND_MODEM_ALTAIR_LTE,
>                                                MMBroadbandModemAltairLtePrivate);
>  
> +    self->priv->sim_refresh_regex = g_regex_new ("\\r\\n\\%NOTIFYEV:\\s*SIMREFRESH,?(\\d*)\\r+\\n",
> +                                                 G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
> +    self->priv->sim_refresh_timer_id = 0;
>      self->priv->statcm_regex = g_regex_new ("\\r\\n\\%STATCM:\\s*(\\d*),?(\\d*)\\r+\\n",
>                                              G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
>  }
>  
>  static void
> +finalize (GObject *object)
> +{
> +    MMBroadbandModemAltairLte *self = MM_BROADBAND_MODEM_ALTAIR_LTE (object);

Add a whiteline here.

> +    if (self->priv->sim_refresh_timer_id)
> +        g_source_remove (self->priv->sim_refresh_timer_id);
> +    g_regex_unref (self->priv->sim_refresh_regex);
> +    g_regex_unref (self->priv->statcm_regex);
> +    G_OBJECT_CLASS (mm_broadband_modem_altair_lte_parent_class)->finalize (object);
> +}
> +
> +static void
>  iface_modem_init (MMIfaceModem *iface)
>  {
>      iface->modem_power_down = modem_power_down;
> @@ -1174,6 +1347,7 @@ mm_broadband_modem_altair_lte_class_init (MMBroadbandModemAltairLteClass *klass)
>  
>      g_type_class_add_private (object_class, sizeof (MMBroadbandModemAltairLtePrivate));
>  
> +    object_class->finalize = finalize;
>      broadband_modem_class->setup_ports = setup_ports;
>  
>      /* The Altair LTE modem reboots itself upon receiving an ATZ command. We
> 


-- 
Aleksander


More information about the ModemManager-devel mailing list