diff options
Diffstat (limited to 'libmm-glib/mm-modem-signal.c')
-rw-r--r-- | libmm-glib/mm-modem-signal.c | 490 |
1 files changed, 368 insertions, 122 deletions
diff --git a/libmm-glib/mm-modem-signal.c b/libmm-glib/mm-modem-signal.c index f930a923..e977f162 100644 --- a/libmm-glib/mm-modem-signal.c +++ b/libmm-glib/mm-modem-signal.c @@ -41,6 +41,25 @@ G_DEFINE_TYPE (MMModemSignal, mm_modem_signal, MM_GDBUS_TYPE_MODEM_SIGNAL_PROXY) +typedef struct { + GMutex mutex; + guint id; + MMSignal *info; +} UpdatedProperty; + +typedef enum { + UPDATED_PROPERTY_TYPE_CDMA = 0, + UPDATED_PROPERTY_TYPE_EVDO = 1, + UPDATED_PROPERTY_TYPE_GSM = 2, + UPDATED_PROPERTY_TYPE_UMTS = 3, + UPDATED_PROPERTY_TYPE_LTE = 4, + UPDATED_PROPERTY_TYPE_LAST +} UpdatedPropertyType; + +struct _MMModemSignalPrivate { + UpdatedProperty values [UPDATED_PROPERTY_TYPE_LAST]; +}; + /*****************************************************************************/ /** @@ -95,8 +114,8 @@ mm_modem_signal_dup_path (MMModemSignal *self) */ gboolean mm_modem_signal_setup_finish (MMModemSignal *self, - GAsyncResult *res, - GError **error) + GAsyncResult *res, + GError **error) { g_return_val_if_fail (MM_IS_MODEM_SIGNAL (self), FALSE); @@ -120,10 +139,10 @@ mm_modem_signal_setup_finish (MMModemSignal *self, */ void mm_modem_signal_setup (MMModemSignal *self, - guint rate, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) + guint rate, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) { g_return_if_fail (MM_IS_MODEM_SIGNAL (self)); @@ -146,9 +165,9 @@ mm_modem_signal_setup (MMModemSignal *self, */ gboolean mm_modem_signal_setup_sync (MMModemSignal *self, - guint rate, - GCancellable *cancellable, - GError **error) + guint rate, + GCancellable *cancellable, + GError **error) { g_return_val_if_fail (MM_IS_MODEM_SIGNAL (self), FALSE); @@ -175,182 +194,409 @@ mm_modem_signal_get_rate (MMModemSignal *self) /*****************************************************************************/ -#define GETTER(VALUE) \ - gboolean \ - mm_modem_signal_get_##VALUE (MMModemSignal *self, \ - gdouble *value) \ - { \ - GVariant *variant; \ - gboolean is_valid = FALSE; \ - double val = 0.0; \ - \ - g_return_val_if_fail (MM_IS_MODEM_SIGNAL (self), FALSE); \ - \ - variant = mm_gdbus_modem_signal_dup_##VALUE (MM_GDBUS_MODEM_SIGNAL (self)); \ - if (variant) { \ - g_variant_get (variant, \ - "(bd)", \ - &is_valid, \ - &val); \ - g_variant_unref (variant); \ - } \ - \ - if (is_valid) \ - *value = val; \ - return is_valid; \ +static void values_updated (MMModemSignal *self, GParamSpec *pspec, UpdatedPropertyType type); + +static void +cdma_updated (MMModemSignal *self, + GParamSpec *pspec) +{ + values_updated (self, pspec, UPDATED_PROPERTY_TYPE_CDMA); +} + +static void +evdo_updated (MMModemSignal *self, + GParamSpec *pspec) +{ + values_updated (self, pspec, UPDATED_PROPERTY_TYPE_EVDO); +} + +static void +gsm_updated (MMModemSignal *self, + GParamSpec *pspec) +{ + values_updated (self, pspec, UPDATED_PROPERTY_TYPE_GSM); +} + +static void +umts_updated (MMModemSignal *self, + GParamSpec *pspec) +{ + values_updated (self, pspec, UPDATED_PROPERTY_TYPE_UMTS); +} + +static void +lte_updated (MMModemSignal *self, + GParamSpec *pspec) +{ + values_updated (self, pspec, UPDATED_PROPERTY_TYPE_LTE); +} + +typedef GVariant * (* Getter) (MmGdbusModemSignal *self); +typedef GVariant * (* Dupper) (MmGdbusModemSignal *self); +typedef void (* UpdatedCallback) (MMModemSignal *self, GParamSpec *pspec); +typedef struct { + const gchar *signal_name; + Getter get; + Dupper dup; + UpdatedCallback updated_callback; +} SignalData; + +static const SignalData signal_data [UPDATED_PROPERTY_TYPE_LAST] = { + { "notify::cdma", mm_gdbus_modem_signal_get_cdma, mm_gdbus_modem_signal_dup_cdma, cdma_updated }, + { "notify::evdo", mm_gdbus_modem_signal_get_evdo, mm_gdbus_modem_signal_dup_evdo, evdo_updated }, + { "notify::gsm", mm_gdbus_modem_signal_get_gsm, mm_gdbus_modem_signal_dup_gsm, gsm_updated }, + { "notify::umts", mm_gdbus_modem_signal_get_umts, mm_gdbus_modem_signal_dup_umts, umts_updated }, + { "notify::lte", mm_gdbus_modem_signal_get_lte, mm_gdbus_modem_signal_dup_lte, lte_updated } +}; + +static void +values_updated (MMModemSignal *self, + GParamSpec *pspec, + UpdatedPropertyType type) +{ + g_mutex_lock (&self->priv->values[type].mutex); + { + GVariant *dictionary; + + g_clear_object (&self->priv->values[type].info); + dictionary = signal_data[type].get (MM_GDBUS_MODEM_SIGNAL (self)); + if (dictionary) { + GError *error = NULL; + + self->priv->values[type].info = mm_signal_new_from_dictionary (dictionary, &error); + if (error) { + g_warning ("Invalid signal info update received: %s", error->message); + g_error_free (error); + } + } } + g_mutex_unlock (&self->priv->values[type].mutex); +} -/** - * mm_modem_get_cdma_rssi: - * @self: A #MMModemSignal. - * @value: (out): Return location for the value. - * - * Gets the CDMA1x RSSI (Received Signal Strength Indication), in dBm. - * - * Returns: %TRUE if @value is valid, %FALSE otherwise. - */ -GETTER(cdma_rssi) +static void +ensure_internal (MMModemSignal *self, + MMSignal **dup, + UpdatedPropertyType type) +{ + g_mutex_lock (&self->priv->values[type].mutex); + { + /* If this is the first time ever asking for the object, setup the + * update listener and the initial object, if any. */ + if (!self->priv->values[type].id) { + GVariant *dictionary; + + dictionary = signal_data[type].dup (MM_GDBUS_MODEM_SIGNAL (self)); + if (dictionary) { + GError *error = NULL; + + self->priv->values[type].info = mm_signal_new_from_dictionary (dictionary, &error); + if (error) { + g_warning ("Invalid signal info: %s", error->message); + g_error_free (error); + } + g_variant_unref (dictionary); + } + + /* No need to clear this signal connection when freeing self */ + self->priv->values[type].id = + g_signal_connect (self, + signal_data[type].signal_name, + G_CALLBACK (signal_data[type].updated_callback), + NULL); + } + + if (dup && self->priv->values[type].info) + *dup = g_object_ref (self->priv->values[type].info); + } + g_mutex_unlock (&self->priv->values[type].mutex); +} -/** - * mm_modem_get_cdma_ecio: - * @self: A #MMModemSignal. - * @value: (out): Return location for the value. - * - * Gets the CDMA1x Ec/Io, in dBm. - * - * Returns: %TRUE if @value is valid, %FALSE otherwise. - */ -GETTER(cdma_ecio) +/*****************************************************************************/ /** - * mm_modem_get_evdo_rssi: - * @self: A #MMModemSignal. - * @value: (out): Return location for the value. + * mm_modem_get_cdma: + * @self: A #MMModem. * - * Gets the CDMA EV-DO RSSI (Received Signal Strength Indication), in dBm. + * Gets a #MMSignal object specifying the CDMA signal information. * - * Returns: %TRUE if @value is valid, %FALSE otherwise. - */ -GETTER(evdo_rssi) - -/** - * mm_modem_get_evdo_ecio: - * @self: A #MMModemSignal. - * @value: (out): Return location for the value. - * - * Gets the CDMA EV-DO Ec/Io, in dBm. + * <warning>The values reported by @self are not updated when the values in the + * interface change. Instead, the client is expected to call + * mm_modem_get_cdma() again to get a new #MMSignal with the + * new values.</warning> * - * Returns: %TRUE if @value is valid, %FALSE otherwise. + * Returns: (transfer full) A #MMSignal that must be freed with g_object_unref() or %NULL if unknown. */ -GETTER(evdo_ecio) +MMSignal * +mm_modem_signal_get_cdma (MMModemSignal *self) +{ + MMSignal *info = NULL; + + g_return_val_if_fail (MM_IS_MODEM_SIGNAL (self), NULL); + + ensure_internal (self, &info, UPDATED_PROPERTY_TYPE_CDMA); + return info; +} /** - * mm_modem_get_evdo_sinr: - * @self: A #MMModemSignal. - * @value: (out): Return location for the value. + * mm_modem_peek_cdma: + * @self: A #MMModem. * - * Gets the CDMA EV-DO SINR level, in dB. + * Gets a #MMSignal object specifying the CDMA signal information. * - * Returns: %TRUE if @value is valid, %FALSE otherwise. + * <warning>The returned value is only valid until the property changes so + * it is only safe to use this function on the thread where + * @self was constructed. Use mm_modem_get_cdma() if on another + * thread.</warning> + * + * Returns: (transfer none) A #MMSignal. Do not free the returned value, it belongs to @self. */ -GETTER(evdo_sinr) +MMSignal * +mm_modem_signal_peek_cdma (MMModemSignal *self) +{ + g_return_val_if_fail (MM_IS_MODEM_SIGNAL (self), NULL); + + ensure_internal (self, NULL, UPDATED_PROPERTY_TYPE_CDMA); + return self->priv->values[UPDATED_PROPERTY_TYPE_CDMA].info; +} + +/*****************************************************************************/ /** - * mm_modem_get_evdo_io: - * @self: A #MMModemSignal. - * @value: (out): Return location for the value. + * mm_modem_get_evdo: + * @self: A #MMModem. * - * Gets the CDMA EV-DO IO, in dBm. + * Gets a #MMSignal object specifying the EV-DO signal information. * - * Returns: %TRUE if @value is valid, %FALSE otherwise. + * <warning>The values reported by @self are not updated when the values in the + * interface change. Instead, the client is expected to call + * mm_modem_get_evdo() again to get a new #MMSignal with the + * new values.</warning> + * + * Returns: (transfer full) A #MMSignal that must be freed with g_object_unref() or %NULL if unknown. */ -GETTER(evdo_io) +MMSignal * +mm_modem_signal_get_evdo (MMModemSignal *self) +{ + MMSignal *info = NULL; + + g_return_val_if_fail (MM_IS_MODEM_SIGNAL (self), NULL); + + ensure_internal (self, &info, UPDATED_PROPERTY_TYPE_EVDO); + return info; +} /** - * mm_modem_get_gsm_rssi: - * @self: A #MMModemSignal. - * @value: (out): Return location for the value. + * mm_modem_peek_evdo: + * @self: A #MMModem. + * + * Gets a #MMSignal object specifying the EV-DO signal information. * - * Gets the GSM RSSI (Received Signal Strength Indication), in dBm. + * <warning>The returned value is only valid until the property changes so + * it is only safe to use this function on the thread where + * @self was constructed. Use mm_modem_get_evdo() if on another + * thread.</warning> * - * Returns: %TRUE if @value is valid, %FALSE otherwise. + * Returns: (transfer none) A #MMSignal. Do not free the returned value, it belongs to @self. */ -GETTER(gsm_rssi) +MMSignal * +mm_modem_signal_peek_evdo (MMModemSignal *self) +{ + g_return_val_if_fail (MM_IS_MODEM_SIGNAL (self), NULL); + + ensure_internal (self, NULL, UPDATED_PROPERTY_TYPE_EVDO); + return self->priv->values[UPDATED_PROPERTY_TYPE_EVDO].info; +} + +/*****************************************************************************/ /** - * mm_modem_get_umts_rssi: - * @self: A #MMModemSignal. - * @value: (out): Return location for the value. + * mm_modem_get_gsm: + * @self: A #MMModem. * - * Gets the UMTS (WCDMA) RSSI (Received Signal Strength Indication), in dBm. + * Gets a #MMSignal object specifying the GSM signal information. * - * Returns: %TRUE if @value is valid, %FALSE otherwise. + * <warning>The values reported by @self are not updated when the values in the + * interface change. Instead, the client is expected to call + * mm_modem_get_gsm() again to get a new #MMSignal with the + * new values.</warning> + * + * Returns: (transfer full) A #MMSignal that must be freed with g_object_unref() or %NULL if unknown. */ -GETTER(umts_rssi) +MMSignal * +mm_modem_signal_get_gsm (MMModemSignal *self) +{ + MMSignal *info = NULL; + + g_return_val_if_fail (MM_IS_MODEM_SIGNAL (self), NULL); + + ensure_internal (self, &info, UPDATED_PROPERTY_TYPE_GSM); + return info; +} /** - * mm_modem_get_umts_ecio: - * @self: A #MMModemSignal. - * @value: (out): Return location for the value. + * mm_modem_peek_gsm: + * @self: A #MMModem. + * + * Gets a #MMSignal object specifying the GSM signal information. * - * Gets the UMTS (WCDMA) Ec/Io, in dBm. + * <warning>The returned value is only valid until the property changes so + * it is only safe to use this function on the thread where + * @self was constructed. Use mm_modem_get_gsm() if on another + * thread.</warning> * - * Returns: %TRUE if @value is valid, %FALSE otherwise. + * Returns: (transfer none) A #MMSignal. Do not free the returned value, it belongs to @self. */ -GETTER(umts_ecio) +MMSignal * +mm_modem_signal_peek_gsm (MMModemSignal *self) +{ + g_return_val_if_fail (MM_IS_MODEM_SIGNAL (self), NULL); + + ensure_internal (self, NULL, UPDATED_PROPERTY_TYPE_GSM); + return self->priv->values[UPDATED_PROPERTY_TYPE_GSM].info; +} + +/*****************************************************************************/ /** - * mm_modem_get_lte_rssi: - * @self: A #MMModemSignal. - * @value: (out): Return location for the value. + * mm_modem_get_umts: + * @self: A #MMModem. * - * Gets the LTE RSSI (Received Signal Strength Indication), in dBm. + * Gets a #MMSignal object specifying the UMTS signal information. * - * Returns: %TRUE if @value is valid, %FALSE otherwise. + * <warning>The values reported by @self are not updated when the values in the + * interface change. Instead, the client is expected to call + * mm_modem_get_umts() again to get a new #MMSignal with the + * new values.</warning> + * + * Returns: (transfer full) A #MMSignal that must be freed with g_object_unref() or %NULL if unknown. */ -GETTER(lte_rssi) +MMSignal * +mm_modem_signal_get_umts (MMModemSignal *self) +{ + MMSignal *info = NULL; + + g_return_val_if_fail (MM_IS_MODEM_SIGNAL (self), NULL); + + ensure_internal (self, &info, UPDATED_PROPERTY_TYPE_UMTS); + return info; +} /** - * mm_modem_get_lte_rsrq: - * @self: A #MMModemSignal. - * @value: (out): Return location for the value. + * mm_modem_peek_umts: + * @self: A #MMModem. + * + * Gets a #MMSignal object specifying the UMTS signal information. * - * Gets the LTE RSRQ (Reference Signal Received Quality), in dB. + * <warning>The returned value is only valid until the property changes so + * it is only safe to use this function on the thread where + * @self was constructed. Use mm_modem_get_umts() if on another + * thread.</warning> * - * Returns: %TRUE if @value is valid, %FALSE otherwise. + * Returns: (transfer none) A #MMSignal. Do not free the returned value, it belongs to @self. */ -GETTER(lte_rsrq) +MMSignal * +mm_modem_signal_peek_umts (MMModemSignal *self) +{ + g_return_val_if_fail (MM_IS_MODEM_SIGNAL (self), NULL); + + ensure_internal (self, NULL, UPDATED_PROPERTY_TYPE_UMTS); + return self->priv->values[UPDATED_PROPERTY_TYPE_UMTS].info; +} + +/*****************************************************************************/ /** - * mm_modem_get_lte_rsrp: - * @self: A #MMModemSignal. - * @value: (out): Return location for the value. + * mm_modem_get_lte: + * @self: A #MMModem. * - * Gets the LTE RSRP (Reference Signal Received Power), in dBm. + * Gets a #MMSignal object specifying the LTE signal information. * - * Returns: %TRUE if @value is valid, %FALSE otherwise. + * <warning>The values reported by @self are not updated when the values in the + * interface change. Instead, the client is expected to call + * mm_modem_get_lte() again to get a new #MMSignal with the + * new values.</warning> + * + * Returns: (transfer full) A #MMSignal that must be freed with g_object_unref() or %NULL if unknown. */ -GETTER(lte_rsrp) +MMSignal * +mm_modem_signal_get_lte (MMModemSignal *self) +{ + MMSignal *info = NULL; + + g_return_val_if_fail (MM_IS_MODEM_SIGNAL (self), NULL); + + ensure_internal (self, &info, UPDATED_PROPERTY_TYPE_LTE); + return info; +} /** - * mm_modem_get_lte_snr: - * @self: A #MMModemSignal. - * @value: (out): Return location for the value. + * mm_modem_peek_lte: + * @self: A #MMModem. + * + * Gets a #MMSignal object specifying the LTE signal information. * - * Gets the LTE S/R ratio, in dB. + * <warning>The returned value is only valid until the property changes so + * it is only safe to use this function on the thread where + * @self was constructed. Use mm_modem_get_lte() if on another + * thread.</warning> * - * Returns: %TRUE if @value is valid, %FALSE otherwise. + * Returns: (transfer none) A #MMSignal. Do not free the returned value, it belongs to @self. */ -GETTER(lte_snr) +MMSignal * +mm_modem_signal_peek_lte (MMModemSignal *self) +{ + g_return_val_if_fail (MM_IS_MODEM_SIGNAL (self), NULL); + + ensure_internal (self, NULL, UPDATED_PROPERTY_TYPE_LTE); + return self->priv->values[UPDATED_PROPERTY_TYPE_LTE].info; +} /*****************************************************************************/ static void mm_modem_signal_init (MMModemSignal *self) { + guint i; + + /* Setup private data */ + self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, MM_TYPE_MODEM_SIGNAL, MMModemSignalPrivate); + + for (i = 0; i < UPDATED_PROPERTY_TYPE_LAST; i++) + g_mutex_init (&self->priv->values[i].mutex); +} + +static void +finalize (GObject *object) +{ + MMModemSignal *self = MM_MODEM_SIGNAL (object); + guint i; + + for (i = 0; i < UPDATED_PROPERTY_TYPE_LAST; i++) + g_mutex_clear (&self->priv->values[i].mutex); + + G_OBJECT_CLASS (mm_modem_signal_parent_class)->finalize (object); +} + +static void +dispose (GObject *object) +{ + MMModemSignal *self = MM_MODEM_SIGNAL (object); + guint i; + + for (i = 0; i < UPDATED_PROPERTY_TYPE_LAST; i++) + g_clear_object (&self->priv->values[i].info); + + G_OBJECT_CLASS (mm_modem_signal_parent_class)->dispose (object); } static void mm_modem_signal_class_init (MMModemSignalClass *modem_class) { + GObjectClass *object_class = G_OBJECT_CLASS (modem_class); + + g_type_class_add_private (object_class, sizeof (MMModemSignalPrivate)); + + /* Virtual methods */ + object_class->dispose = dispose; + object_class->finalize = finalize; } |