commit 1e2cdf8374c354bbf8f571dc8d0784737eecdc17 Author: Alastair Pharo Date: Mon Jul 17 17:32:25 2017 +1200 huawei: reset the default SMSC on E220 The E220 has a bug which causes SMS messages that are sent without specifying an SMSC to fail with org.freedesktop.ModemManager1.Error.Message.SmscAddressUnknown (AKA error 330), even when the modem knows the default SMSC to use. As a workaround, when we detect an E220, we use AT+CSCA commands to query and reset the default SMSC. e.g., (ttyUSB1): --> 'AT+CSCA?' (ttyUSB1): <-- '+CSCA: "+55555555555",145OK' ... (ttyUSB1): --> 'AT+CSCA="+55555555555",145' (ttyUSB1): <-- 'OK' It appears that the above sequence only needs to run once when the modem starts, so it is executed as part of the "check_support" call on the messaging interface. squash! huawei: reset the default SMSC on E220 diff --git a/plugins/huawei/mm-broadband-modem-huawei.c b/plugins/huawei/mm-broadband-modem-huawei.c index cf22b0d5..ac3c1133 100644 --- a/plugins/huawei/mm-broadband-modem-huawei.c +++ b/plugins/huawei/mm-broadband-modem-huawei.c @@ -40,6 +40,7 @@ #include "mm-iface-modem-3gpp.h" #include "mm-iface-modem-3gpp-ussd.h" #include "mm-iface-modem-location.h" +#include "mm-iface-modem-messaging.h" #include "mm-iface-modem-time.h" #include "mm-iface-modem-cdma.h" #include "mm-iface-modem-signal.h" @@ -55,6 +56,7 @@ static void iface_modem_init (MMIfaceModem *iface); static void iface_modem_3gpp_init (MMIfaceModem3gpp *iface); static void iface_modem_3gpp_ussd_init (MMIfaceModem3gppUssd *iface); static void iface_modem_location_init (MMIfaceModemLocation *iface); +static void iface_modem_messaging_init (MMIfaceModemMessaging *iface); static void iface_modem_cdma_init (MMIfaceModemCdma *iface); static void iface_modem_time_init (MMIfaceModemTime *iface); static void iface_modem_voice_init (MMIfaceModemVoice *iface); @@ -63,6 +65,7 @@ static void iface_modem_signal_init (MMIfaceModemSignal *iface); static MMIfaceModem *iface_modem_parent; static MMIfaceModem3gpp *iface_modem_3gpp_parent; static MMIfaceModemLocation *iface_modem_location_parent; +static MMIfaceModemMessaging *iface_modem_messaging_parent; static MMIfaceModemCdma *iface_modem_cdma_parent; static MMIfaceModemVoice *iface_modem_voice_parent; @@ -72,6 +75,7 @@ G_DEFINE_TYPE_EXTENDED (MMBroadbandModemHuawei, mm_broadband_modem_huawei, MM_TY G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_3GPP_USSD, iface_modem_3gpp_ussd_init) G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_CDMA, iface_modem_cdma_init) G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_LOCATION, iface_modem_location_init) + G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_MESSAGING, iface_modem_messaging_init) G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_TIME, iface_modem_time_init) G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_VOICE, iface_modem_voice_init) G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_SIGNAL, iface_modem_signal_init)) @@ -3988,6 +3992,133 @@ enable_location_gathering (MMIfaceModemLocation *self, } /*****************************************************************************/ +/* Check if Messaging supported (Messaging interface) */ + +static gboolean +messaging_check_support_finish (MMIfaceModemMessaging *self, + GAsyncResult *res, + GError **error) +{ + return g_task_propagate_boolean (G_TASK (res), error); +} + +static void +csca_set_ready (MMBaseModem *self, + GAsyncResult *res, + GTask *task) +{ + GError *error = NULL; + const gchar *response; + + response = mm_base_modem_at_command_finish (self, res, &error); + if (error) + g_task_return_error (task, error); + else + g_task_return_boolean (task, TRUE); + + g_object_unref (task); +} + +static void +csca_check_ready (MMBaseModem *self, + GAsyncResult *res, + GTask *task) +{ + GError *error = NULL; + const gchar *response; + gchar *command; + + /* The modem sometimes responds with a hex (UCS-2?) representation of the + * SMSC. This appears to be some buggy behaviour which only occurs when + * the SMSC is correctly set. As such, whenever the response starts with + * '+CSCA: "', and the next character is a zero, we assume that the SMSC + * has already been set successfully. + */ + response = mm_base_modem_at_command_finish (self, res, &error); + if (response && strncmp (response, "+CSCA: \"", 7) == 0) { + + if (response[8] != '0') { + command = g_strdup_printf ("+CSCA=%s", response + 7); + mm_base_modem_at_command (self, + command, + 3, + FALSE, + (GAsyncReadyCallback)csca_set_ready, + task); + + g_free (command); + } + else { + g_task_return_boolean (task, TRUE); + g_object_unref (task); + } + + return; + } + else if (response) { + g_set_error (&error, + MM_CORE_ERROR, + MM_CORE_ERROR_FAILED, + "Unexpected +CSCA response: '%s'", + response); + } + + g_task_return_error (task, error); + g_object_unref (task); +} + +static void +parent_messaging_check_support_ready (MMIfaceModemMessaging *_self, + GAsyncResult *res, + GTask *task) +{ + MMBroadbandModemHuawei *self = MM_BROADBAND_MODEM_HUAWEI (_self); + GError *error = NULL; + gboolean support; + + support = iface_modem_messaging_parent->check_support_finish (_self, + res, + &error); + + if (!support) { + if (error) + g_task_return_error (task, error); + else + g_task_return_boolean (task, FALSE); + + g_object_unref (task); + return; + } + + /* If messaging is supported, and the device is a E220, we need to run some + * extra AT-commands due to a presumed bug. + */ + if (g_strcmp0 (mm_iface_modem_get_model (MM_IFACE_MODEM (self)), "E220") == 0) { + mm_base_modem_at_command (MM_BASE_MODEM (self), + "+CSCA?", + 3, + FALSE, + (GAsyncReadyCallback)csca_check_ready, + task); + } + else { + g_task_return_boolean (task, TRUE); + g_object_unref (task); + } +} + +static void +messaging_check_support (MMIfaceModemMessaging *self, + GAsyncReadyCallback callback, + gpointer user_data) +{ + /* Run parent's check */ + iface_modem_messaging_parent->check_support (self, + (GAsyncReadyCallback)parent_messaging_check_support_ready, + g_task_new (self, NULL, callback, user_data)); +} + +/*****************************************************************************/ /* Check support (Time interface) */ static gboolean @@ -4592,6 +4723,15 @@ iface_modem_location_init (MMIfaceModemLocation *iface) } static void +iface_modem_messaging_init (MMIfaceModemMessaging *iface) +{ + iface_modem_messaging_parent = g_type_interface_peek_parent (iface); + + iface->check_support = messaging_check_support; + iface->check_support_finish = messaging_check_support_finish; +} + +static void iface_modem_time_init (MMIfaceModemTime *iface) { iface->check_support = modem_time_check_support;