diff options
author | Dan Williams <dcbw@redhat.com> | 2010-03-10 14:50:41 -0800 |
---|---|---|
committer | Dan Williams <dcbw@redhat.com> | 2010-03-10 14:50:41 -0800 |
commit | 1979512d8dfb6428353e6bf358f908973a318095 (patch) | |
tree | 60f703f4a2c75c4e3a2d7d362969fd2c441ddb8c /src | |
parent | 8dde6bb8dd2c063f5740ae78b980343be8e5d669 (diff) | |
parent | b7858ba235c046a514fbc79e18ac9faa75982032 (diff) |
Merge remote branch 'origin/master' into qcdm
Diffstat (limited to 'src')
-rw-r--r-- | src/main.c | 8 | ||||
-rw-r--r-- | src/mm-generic-cdma.c | 3 | ||||
-rw-r--r-- | src/mm-generic-gsm.c | 358 | ||||
-rw-r--r-- | src/mm-generic-gsm.h | 5 | ||||
-rw-r--r-- | src/mm-modem-helpers.c | 67 | ||||
-rw-r--r-- | src/mm-modem-helpers.h | 2 | ||||
-rw-r--r-- | src/mm-serial-port.c | 10 | ||||
-rw-r--r-- | src/tests/test-modem-helpers.c | 22 |
8 files changed, 345 insertions, 130 deletions
@@ -17,6 +17,7 @@ #include <signal.h> #include <syslog.h> #include <string.h> +#include <unistd.h> #include <dbus/dbus-glib.h> #include <dbus/dbus-glib-lowlevel.h> #include "mm-manager.h" @@ -33,8 +34,11 @@ mm_signal_handler (int signo) mm_options_set_debug (!mm_options_debug ()); else if (signo == SIGINT || signo == SIGTERM) { g_message ("Caught signal %d, shutting down...", signo); - g_main_loop_quit (loop); - } + if (loop) + g_main_loop_quit (loop); + else + _exit (0); + } } static void diff --git a/src/mm-generic-cdma.c b/src/mm-generic-cdma.c index 8ec71a7a..4d558c3e 100644 --- a/src/mm-generic-cdma.c +++ b/src/mm-generic-cdma.c @@ -358,6 +358,9 @@ enable_all_done (MMModem *modem, GError *error, gpointer user_data) if (error) info->error = g_error_copy (error); else { + /* Try to enable XON/XOFF flow control */ + mm_at_serial_port_queue_command (priv->primary, "+IFC=1,1", 3, NULL, NULL); + /* Open up the second port, if one exists */ if (priv->secondary) { if (!mm_serial_port_open (MM_SERIAL_PORT (priv->secondary), &info->error)) { diff --git a/src/mm-generic-gsm.c b/src/mm-generic-gsm.c index fd4d8380..c6add593 100644 --- a/src/mm-generic-gsm.c +++ b/src/mm-generic-gsm.c @@ -79,6 +79,8 @@ typedef struct { guint pending_reg_id; MMCallbackInfo *pending_reg_info; + guint signal_quality_id; + time_t signal_quality_timestamp; guint32 signal_quality; guint32 cid; @@ -113,6 +115,17 @@ static gboolean handle_reg_status_response (MMGenericGsm *self, static MMModemGsmAccessTech etsi_act_to_mm_act (gint act); +static void _internal_update_access_technology (MMGenericGsm *modem, + MMModemGsmAccessTech act); + +static void reg_info_updated (MMGenericGsm *self, + gboolean update_rs, + MMModemGsmNetworkRegStatus status, + gboolean update_code, + const char *oper_code, + gboolean update_name, + const char *oper_name); + MMModem * mm_generic_gsm_new (const char *device, const char *driver, @@ -145,14 +158,6 @@ mm_generic_gsm_get_cid (MMGenericGsm *modem) return MM_GENERIC_GSM_GET_PRIVATE (modem)->cid; } -static void -got_signal_quality (MMModem *modem, - guint32 result, - GError *error, - gpointer user_data) -{ -} - typedef struct { const char *result; const char *normalized; @@ -699,6 +704,9 @@ mm_generic_gsm_enable_complete (MMGenericGsm *self, } } + /* Try to enable XON/XOFF flow control */ + mm_at_serial_port_queue_command (priv->primary, "+IFC=1,1", 3, NULL, NULL); + /* Get allowed mode */ if (MM_GENERIC_GSM_GET_CLASS (self)->get_allowed_mode) MM_GENERIC_GSM_GET_CLASS (self)->get_allowed_mode (self, get_allowed_mode_done, NULL); @@ -842,13 +850,18 @@ disable_done (MMAtSerialPort *port, info->error = mm_modem_check_removed (info->modem, error); if (!info->error) { - MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (info->modem); + MMGenericGsm *self = MM_GENERIC_GSM (info->modem); mm_serial_port_close (MM_SERIAL_PORT (port)); mm_modem_set_state (MM_MODEM (info->modem), MM_MODEM_STATE_DISABLED, MM_MODEM_STATE_REASON_NONE); - priv->reg_status = MM_MODEM_GSM_NETWORK_REG_STATUS_UNKNOWN; + + /* Clear out registration info */ + reg_info_updated (self, + TRUE, MM_MODEM_GSM_NETWORK_REG_STATUS_UNKNOWN, + TRUE, NULL, + TRUE, NULL); } mm_callback_info_schedule (info); } @@ -903,11 +916,16 @@ disable (MMModem *modem, priv->poll_id = 0; } + if (priv->signal_quality_id) { + g_source_remove (priv->signal_quality_id); + priv->signal_quality_id = 0; + } + priv->lac[0] = 0; priv->lac[1] = 0; priv->cell_id[0] = 0; priv->cell_id[1] = 0; - mm_generic_gsm_update_access_technology (self, MM_MODEM_GSM_ACCESS_TECH_UNKNOWN); + _internal_update_access_technology (self, MM_MODEM_GSM_ACCESS_TECH_UNKNOWN); /* Close the secondary port if its open */ if (priv->secondary && mm_serial_port_is_open (MM_SERIAL_PORT (priv->secondary))) @@ -1268,6 +1286,49 @@ change_pin (MMModemGsmCard *modem, g_free (command); } +static void +reg_info_updated (MMGenericGsm *self, + gboolean update_rs, + MMModemGsmNetworkRegStatus status, + gboolean update_code, + const char *oper_code, + gboolean update_name, + const char *oper_name) +{ + MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (self); + gboolean changed = FALSE; + + if (update_rs) { + if (status != priv->reg_status) { + priv->reg_status = status; + changed = TRUE; + } + } + + if (update_code) { + if (g_strcmp0 (oper_code, priv->oper_code) != 0) { + g_free (priv->oper_code); + priv->oper_code = g_strdup (oper_code); + changed = TRUE; + } + } + + if (update_name) { + if (g_strcmp0 (oper_name, priv->oper_name) != 0) { + g_free (priv->oper_name); + priv->oper_name = g_strdup (oper_name); + changed = TRUE; + } + } + + if (changed) { + mm_modem_gsm_network_registration_info (MM_MODEM_GSM_NETWORK (self), + priv->reg_status, + priv->oper_code, + priv->oper_name); + } +} + static char * parse_operator (const char *reply) { @@ -1300,18 +1361,14 @@ read_operator_code_done (MMAtSerialPort *port, GError *error, gpointer user_data) { - MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (user_data); + MMGenericGsm *self = MM_GENERIC_GSM (user_data); char *oper; - if (error) - return; - - oper = parse_operator (response->str); - if (!oper) - return; - - g_free (priv->oper_code); - priv->oper_code = oper; + if (!error) { + oper = parse_operator (response->str); + if (oper) + reg_info_updated (self, FALSE, 0, TRUE, oper, FALSE, NULL); + } } static void @@ -1320,23 +1377,14 @@ read_operator_name_done (MMAtSerialPort *port, GError *error, gpointer user_data) { - MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (user_data); + MMGenericGsm *self = MM_GENERIC_GSM (user_data); char *oper; - if (error) - return; - - oper = parse_operator (response->str); - if (!oper) - return; - - g_free (priv->oper_name); - priv->oper_name = oper; - - mm_modem_gsm_network_registration_info (MM_MODEM_GSM_NETWORK (user_data), - priv->reg_status, - priv->oper_code, - priv->oper_name); + if (!error) { + oper = parse_operator (response->str); + if (oper) + reg_info_updated (self, FALSE, 0, FALSE, NULL, TRUE, oper); + } } /* Registration */ @@ -1363,6 +1411,15 @@ mm_generic_gsm_pending_registration_stop (MMGenericGsm *modem) } } +static void +got_signal_quality (MMModem *modem, + guint32 quality, + GError *error, + gpointer user_data) +{ + mm_generic_gsm_update_signal_quality (MM_GENERIC_GSM (modem), quality); +} + void mm_generic_gsm_set_reg_status (MMGenericGsm *modem, MMModemGsmNetworkRegStatus status) @@ -1383,14 +1440,8 @@ mm_generic_gsm_set_reg_status (MMGenericGsm *modem, mm_at_serial_port_queue_command (priv->primary, "+COPS=3,2;+COPS?", 3, read_operator_code_done, modem); mm_at_serial_port_queue_command (priv->primary, "+COPS=3,0;+COPS?", 3, read_operator_name_done, modem); mm_modem_gsm_network_get_signal_quality (MM_MODEM_GSM_NETWORK (modem), got_signal_quality, NULL); - } else { - g_free (priv->oper_code); - g_free (priv->oper_name); - priv->oper_code = priv->oper_name = NULL; - - mm_modem_gsm_network_registration_info (MM_MODEM_GSM_NETWORK (modem), priv->reg_status, - priv->oper_code, priv->oper_name); - } + } else + reg_info_updated (MM_GENERIC_GSM (modem), FALSE, 0, TRUE, NULL, TRUE, NULL); mm_generic_gsm_update_enabled_state (modem, TRUE, MM_MODEM_STATE_REASON_NONE); } @@ -1480,14 +1531,21 @@ reg_state_changed (MMAtSerialPort *port, return; } - if (reg_status_updated (self, state, NULL)) { - /* If registration is finished (either registered or failed) but the - * registration query hasn't completed yet, just remove the timeout and - * let the registration query complete. - */ - if (priv->pending_reg_id) { - g_source_remove (priv->pending_reg_id); - priv->pending_reg_id = 0; + /* Don't update reg state on CGREG responses since for many devices it's + * unclear what that registration state that actually reflects. We'll + * take CGREG registration state into account later when we have a more + * consistent way of handling it. + */ + if (cgreg == FALSE) { + if (reg_status_updated (self, state, NULL)) { + /* If registration is finished (either registered or failed) but the + * registration query hasn't completed yet, just remove the timeout and + * let the registration query complete. + */ + if (priv->pending_reg_id) { + g_source_remove (priv->pending_reg_id); + priv->pending_reg_id = 0; + } } } @@ -1668,7 +1726,11 @@ registration_timed_out (gpointer data) g_warn_if_fail (info == priv->pending_reg_info); - priv->reg_status = MM_MODEM_GSM_NETWORK_REG_STATUS_IDLE; + /* Clear out registration info */ + reg_info_updated (MM_GENERIC_GSM (info->modem), + TRUE, MM_MODEM_GSM_NETWORK_REG_STATUS_IDLE, + TRUE, NULL, + TRUE, NULL); info->error = mm_mobile_error_for_code (MM_MOBILE_ERROR_NETWORK_TIMEOUT); mm_generic_gsm_pending_registration_stop (MM_GENERIC_GSM (info->modem)); @@ -2133,26 +2195,91 @@ set_apn (MMModemGsmNetwork *modem, /* GetSignalQuality */ +static gboolean +emit_signal_quality_change (gpointer user_data) +{ + MMGenericGsm *self = MM_GENERIC_GSM (user_data); + MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (self); + + priv->signal_quality_id = 0; + priv->signal_quality_timestamp = time (NULL); + mm_modem_gsm_network_signal_quality (MM_MODEM_GSM_NETWORK (self), priv->signal_quality); + return FALSE; +} + +void +mm_generic_gsm_update_signal_quality (MMGenericGsm *self, guint32 quality) +{ + MMGenericGsmPrivate *priv; + guint delay = 0; + + g_return_if_fail (self != NULL); + g_return_if_fail (MM_IS_GENERIC_GSM (self)); + g_return_if_fail (quality <= 100); + + priv = MM_GENERIC_GSM_GET_PRIVATE (self); + + if (priv->signal_quality == quality) + return; + + priv->signal_quality = quality; + + /* Some modems will send unsolcited signal quality changes quite often, + * so rate-limit them to every few seconds. Track the last time we + * emitted signal quality so that we send the signal immediately if there + * haven't been any updates in a while. + */ + if (!priv->signal_quality_id) { + if (priv->signal_quality_timestamp > 0) { + time_t curtime; + long int diff; + + curtime = time (NULL); + diff = curtime - priv->signal_quality_timestamp; + if (diff == 0) { + /* If the device is sending more than one update per second, + * make sure we don't spam clients with signals. + */ + delay = 3; + } else if ((diff > 0) && (diff <= 3)) { + /* Emitted an update less than 3 seconds ago; schedule an update + * 3 seconds after the previous one. + */ + delay = (guint) diff; + } else { + /* Otherwise, we haven't emitted an update in the last 3 seconds, + * or the user turned their clock back, or something like that. + */ + delay = 0; + } + } + + priv->signal_quality_id = g_timeout_add_seconds (delay, + emit_signal_quality_change, + self); + } +} + static void get_signal_quality_done (MMAtSerialPort *port, GString *response, GError *error, gpointer user_data) { - MMGenericGsmPrivate *priv; MMCallbackInfo *info = (MMCallbackInfo *) user_data; char *reply = response->str; + gboolean parsed = FALSE; - if (error) - info->error = g_error_copy (error); - else if (!strncmp (reply, "+CSQ: ", 6)) { + info->error = mm_modem_check_removed (info->modem, error); + if (info->error) + goto done; + + if (!strncmp (reply, "+CSQ: ", 6)) { /* Got valid reply */ int quality; int ber; - reply += 6; - - if (sscanf (reply, "%d, %d", &quality, &ber)) { + if (sscanf (reply + 6, "%d, %d", &quality, &ber)) { /* 99 means unknown */ if (quality == 99) { info->error = g_error_new_literal (MM_MOBILE_ERROR, @@ -2162,15 +2289,19 @@ get_signal_quality_done (MMAtSerialPort *port, /* Normalize the quality */ quality = CLAMP (quality, 0, 31) * 100 / 31; - priv = MM_GENERIC_GSM_GET_PRIVATE (info->modem); - priv->signal_quality = quality; + mm_generic_gsm_update_signal_quality (MM_GENERIC_GSM (info->modem), quality); mm_callback_info_set_result (info, GUINT_TO_POINTER (quality), NULL); } - } else - info->error = g_error_new_literal (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, - "Could not parse signal quality results"); + parsed = TRUE; + } } + if (!parsed && !info->error) { + info->error = g_error_new_literal (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, + "Could not parse signal quality results"); + } + +done: mm_callback_info_schedule (info); } @@ -2185,7 +2316,6 @@ get_signal_quality (MMModemGsmNetwork *modem, connected = mm_port_get_connected (MM_PORT (priv->primary)); if (connected && !priv->secondary) { - g_message ("Returning saved signal quality %d", priv->signal_quality); callback (MM_MODEM (modem), priv->signal_quality, NULL, user_data); return; } @@ -2221,19 +2351,19 @@ etsi_act_to_mm_act (gint act) while (iter->mm_act != MM_MODEM_GSM_ACCESS_TECH_UNKNOWN) { if (iter->etsi_act == act) return iter->mm_act; + iter++; } return MM_MODEM_GSM_ACCESS_TECH_UNKNOWN; } -void -mm_generic_gsm_update_access_technology (MMGenericGsm *modem, - MMModemGsmAccessTech act) +static void +_internal_update_access_technology (MMGenericGsm *modem, + MMModemGsmAccessTech act) { MMGenericGsmPrivate *priv; g_return_if_fail (modem != NULL); g_return_if_fail (MM_IS_GENERIC_GSM (modem)); - g_return_if_fail (act >= MM_MODEM_GSM_ACCESS_TECH_UNKNOWN && act <= MM_MODEM_GSM_ACCESS_TECH_LAST); priv = MM_GENERIC_GSM_GET_PRIVATE (modem); @@ -2251,6 +2381,18 @@ mm_generic_gsm_update_access_technology (MMGenericGsm *modem, } void +mm_generic_gsm_update_access_technology (MMGenericGsm *self, + MMModemGsmAccessTech act) +{ + g_return_if_fail (self != NULL); + g_return_if_fail (MM_IS_GENERIC_GSM (self)); + + /* For plugins, don't update the access tech when the modem isn't enabled */ + if (mm_modem_get_state (MM_MODEM (self)) >= MM_MODEM_STATE_ENABLED) + _internal_update_access_technology (self, act); +} + +void mm_generic_gsm_update_allowed_mode (MMGenericGsm *self, MMModemGsmAllowedMode mode) { @@ -2509,8 +2651,6 @@ simple_connect (MMModemSimple *simple, simple_state_machine (MM_MODEM (simple), NULL, info); } - - static void simple_free_gvalue (gpointer data) { @@ -2542,16 +2682,39 @@ simple_string_value (const char *str) return val; } +#define NOTDONE_TAG "not-done" +#define SS_HASH_TAG "simple-get-status" + +static void +simple_status_complete_item (MMCallbackInfo *info) +{ + guint32 completed = GPOINTER_TO_UINT (mm_callback_info_get_data (info, NOTDONE_TAG)); + + g_warn_if_fail (completed > 0); + + /* Decrement the number of outstanding calls and if there aren't any left, + * schedule the callback info completion. + */ + completed--; + mm_callback_info_set_data (info, NOTDONE_TAG, GUINT_TO_POINTER (completed), NULL); + if (completed == 0) + mm_callback_info_schedule (info); +} + static void simple_status_got_signal_quality (MMModem *modem, guint32 result, GError *error, gpointer user_data) { - if (error) - g_warning ("Error getting signal quality: %s", error->message); - else - g_hash_table_insert ((GHashTable *) user_data, "signal_quality", simple_uint_value (result)); + MMCallbackInfo *info = (MMCallbackInfo *) user_data; + GHashTable *properties; + + if (!error) { + properties = (GHashTable *) mm_callback_info_get_data (info, SS_HASH_TAG); + g_hash_table_insert (properties, "signal_quality", simple_uint_value (result)); + } + simple_status_complete_item (info); } static void @@ -2560,9 +2723,14 @@ simple_status_got_band (MMModem *modem, GError *error, gpointer user_data) { - /* Ignore band errors since there's no generic implementation for it */ - if (!error) - g_hash_table_insert ((GHashTable *) user_data, "band", simple_uint_value (result)); + MMCallbackInfo *info = (MMCallbackInfo *) user_data; + GHashTable *properties; + + if (!error) { + properties = (GHashTable *) mm_callback_info_get_data (info, SS_HASH_TAG); + g_hash_table_insert (properties, "band", simple_uint_value (result)); + } + simple_status_complete_item (info); } static void @@ -2576,17 +2744,15 @@ simple_status_got_reg_info (MMModemGsmNetwork *modem, MMCallbackInfo *info = (MMCallbackInfo *) user_data; GHashTable *properties; - if (error) - info->error = g_error_copy (error); - else { - properties = (GHashTable *) mm_callback_info_get_data (info, "simple-get-status"); - + info->error = mm_modem_check_removed ((MMModem *) modem, error); + if (!info->error) { + properties = (GHashTable *) mm_callback_info_get_data (info, SS_HASH_TAG); + g_hash_table_insert (properties, "registration_status", simple_uint_value (status)); g_hash_table_insert (properties, "operator_code", simple_string_value (oper_code)); g_hash_table_insert (properties, "operator_name", simple_string_value (oper_name)); } - - mm_callback_info_schedule (info); + simple_status_complete_item (info); } static void @@ -2595,7 +2761,7 @@ simple_get_status_invoke (MMCallbackInfo *info) MMModemSimpleGetStatusFn callback = (MMModemSimpleGetStatusFn) info->callback; callback (MM_MODEM_SIMPLE (info->modem), - (GHashTable *) mm_callback_info_get_data (info, "simple-get-status"), + (GHashTable *) mm_callback_info_get_data (info, SS_HASH_TAG), info->error, info->user_data); } @@ -2615,12 +2781,15 @@ simple_get_status (MMModemSimple *simple, G_CALLBACK (callback), user_data); - properties = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, simple_free_gvalue); - mm_callback_info_set_data (info, "simple-get-status", properties, (GDestroyNotify) g_hash_table_unref); + properties = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, simple_free_gvalue); + mm_callback_info_set_data (info, SS_HASH_TAG, properties, (GDestroyNotify) g_hash_table_unref); + + mm_modem_gsm_network_get_signal_quality (gsm, simple_status_got_signal_quality, info); + mm_modem_gsm_network_get_band (gsm, simple_status_got_band, info); + mm_modem_gsm_network_get_registration_info (gsm, simple_status_got_reg_info, info); - mm_modem_gsm_network_get_signal_quality (gsm, simple_status_got_signal_quality, properties); - mm_modem_gsm_network_get_band (gsm, simple_status_got_band, properties); - mm_modem_gsm_network_get_registration_info (gsm, simple_status_got_reg_info, properties); + /* 3 calls to complete before scheduling the callback: (signal, band, reginfo) */ + mm_callback_info_set_data (info, NOTDONE_TAG, GUINT_TO_POINTER (3), NULL); if (priv->act > -1) { /* Deprecated key */ @@ -2791,6 +2960,11 @@ finalize (GObject *object) priv->poll_id = 0; } + if (priv->signal_quality_id) { + g_source_remove (priv->signal_quality_id); + priv->signal_quality_id = 0; + } + mm_gsm_creg_regex_destroy (priv->reg_regex); g_free (priv->oper_code); diff --git a/src/mm-generic-gsm.h b/src/mm-generic-gsm.h index bf2b4576..bce04331 100644 --- a/src/mm-generic-gsm.h +++ b/src/mm-generic-gsm.h @@ -133,6 +133,11 @@ void mm_generic_gsm_update_allowed_mode (MMGenericGsm *modem, void mm_generic_gsm_update_access_technology (MMGenericGsm *modem, MMModemGsmAccessTech act); +/* Called to asynchronously update the current signal quality of the device; + * 'quality' is a 0 - 100% quality. + */ +void mm_generic_gsm_update_signal_quality (MMGenericGsm *modem, guint32 quality); + void mm_generic_gsm_check_pin (MMGenericGsm *modem, MMModemFn callback, gpointer user_data); diff --git a/src/mm-modem-helpers.c b/src/mm-modem-helpers.c index 56834d6d..e835eb9b 100644 --- a/src/mm-modem-helpers.c +++ b/src/mm-modem-helpers.c @@ -205,22 +205,22 @@ mm_gsm_destroy_scan_data (gpointer data) /*************************************************************************/ /* +CREG: <stat> (GSM 07.07 CREG=1 unsolicited) */ -#define CREG1 "\\+CG?REG:\\s*(\\d{1})" +#define CREG1 "\\+(CREG|CGREG):\\s*(\\d{1})" /* +CREG: <n>,<stat> (GSM 07.07 CREG=1 solicited) */ -#define CREG2 "\\+CG?REG:\\s*(\\d{1}),\\s*(\\d{1})" +#define CREG2 "\\+(CREG|CGREG):\\s*(\\d{1}),\\s*(\\d{1})" /* +CREG: <stat>,<lac>,<ci> (GSM 07.07 CREG=2 unsolicited) */ -#define CREG3 "\\+CG?REG:\\s*(\\d{1}),\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)" +#define CREG3 "\\+(CREG|CGREG):\\s*(\\d{1}),\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)" /* +CREG: <n>,<stat>,<lac>,<ci> (GSM 07.07 solicited and some CREG=2 unsolicited) */ -#define CREG4 "\\+CG?REG:\\s*(\\d{1}),\\s*(\\d{1})\\s*,\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)" +#define CREG4 "\\+(CREG|CGREG):\\s*(\\d{1}),\\s*(\\d{1})\\s*,\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)" /* +CREG: <stat>,<lac>,<ci>,<AcT> (ETSI 27.007 CREG=2 unsolicited) */ -#define CREG5 "\\+CG?REG:\\s*(\\d{1})\\s*,\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)\\s*,\\s*(\\d{1,2})" +#define CREG5 "\\+(CREG|CGREG):\\s*(\\d{1})\\s*,\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)\\s*,\\s*(\\d{1,2})" /* +CREG: <n>,<stat>,<lac>,<ci>,<AcT> (ETSI 27.007 solicited and some CREG=2 unsolicited) */ -#define CREG6 "\\+CG?REG:\\s*(\\d{1}),\\s*(\\d{1})\\s*,\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)\\s*,\\s*(\\d{1,2})" +#define CREG6 "\\+(CREG|CGREG):\\s*(\\d{1}),\\s*(\\d{1})\\s*,\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)\\s*,\\s*(\\d{1,2})" GPtrArray * mm_gsm_creg_regex_get (gboolean solicited) @@ -319,7 +319,7 @@ mm_gsm_parse_creg_response (GMatchInfo *info, gulong *out_lac, gulong *out_ci, gint *out_act, - gboolean *out_greg, + gboolean *out_cgreg, GError **error) { gboolean success = FALSE, foo; @@ -327,56 +327,60 @@ mm_gsm_parse_creg_response (GMatchInfo *info, gulong stat = 0, lac = 0, ci = 0; guint istat = 0, ilac = 0, ici = 0, iact = 0; char *str; - const char *orig_str; g_return_val_if_fail (info != NULL, FALSE); g_return_val_if_fail (out_reg_state != NULL, FALSE); g_return_val_if_fail (out_lac != NULL, FALSE); g_return_val_if_fail (out_ci != NULL, FALSE); g_return_val_if_fail (out_act != NULL, FALSE); - g_return_val_if_fail (out_greg != NULL, FALSE); + g_return_val_if_fail (out_cgreg != NULL, FALSE); + + str = g_match_info_fetch (info, 1); + if (str && strstr (str, "CGREG")) + *out_cgreg = TRUE; /* Normally the number of matches could be used to determine what each * item is, but we have overlap in one case. */ n_matches = g_match_info_get_match_count (info); - if (n_matches == 2) { + if (n_matches == 3) { /* CREG=1: +CREG: <stat> */ - istat = 1; - } else if (n_matches == 3) { - /* Solicited response: +CREG: <n>,<stat> */ istat = 2; } else if (n_matches == 4) { - /* CREG=2 (GSM 07.07): +CREG: <stat>,<lac>,<ci> */ - istat = 1; - ilac = 2; - ici = 3; + /* Solicited response: +CREG: <n>,<stat> */ + istat = 3; } else if (n_matches == 5) { + /* CREG=2 (GSM 07.07): +CREG: <stat>,<lac>,<ci> */ + istat = 2; + ilac = 3; + ici = 4; + } else if (n_matches == 6) { /* CREG=2 (ETSI 27.007): +CREG: <stat>,<lac>,<ci>,<AcT> * CREG=2 (non-standard): +CREG: <n>,<stat>,<lac>,<ci> */ - /* To distinguish, check length of the second match item. If it's - * more than one digit or has quotes in it, then we have the first format. + /* To distinguish, check length of the third match item. If it's + * more than one digit or has quotes in it then it's a LAC and we + * got the first format. */ - str = g_match_info_fetch (info, 2); + str = g_match_info_fetch (info, 3); if (str && (strchr (str, '"') || strlen (str) > 1)) { g_free (str); - istat = 1; - ilac = 2; - ici = 3; - iact = 4; - } else { istat = 2; ilac = 3; ici = 4; + iact = 5; + } else { + istat = 3; + ilac = 4; + ici = 5; } - } else if (n_matches == 6) { + } else if (n_matches == 7) { /* CREG=2 (non-standard): +CREG: <n>,<stat>,<lac>,<ci>,<AcT> */ - istat = 2; - ilac = 3; - ici = 4; - iact = 5; + istat = 3; + ilac = 4; + ici = 5; + iact = 6; } /* Status */ @@ -416,9 +420,6 @@ mm_gsm_parse_creg_response (GMatchInfo *info, act = -1; } - orig_str = g_match_info_get_string (info); - *out_greg = !!strstr (orig_str, "+CGREG"); - *out_reg_state = (guint32) stat; if (stat != 4) { /* Don't fill in lac/ci/act if the device's state is unknown */ diff --git a/src/mm-modem-helpers.h b/src/mm-modem-helpers.h index 57956766..d8c74d84 100644 --- a/src/mm-modem-helpers.h +++ b/src/mm-modem-helpers.h @@ -36,7 +36,7 @@ gboolean mm_gsm_parse_creg_response (GMatchInfo *info, gulong *out_lac, gulong *out_ci, gint *out_act, - gboolean *out_greg, + gboolean *out_cgreg, GError **error); #endif /* MM_MODEM_HELPERS_H */ diff --git a/src/mm-serial-port.c b/src/mm-serial-port.c index a31e4299..8de0cdd1 100644 --- a/src/mm-serial-port.c +++ b/src/mm-serial-port.c @@ -321,8 +321,14 @@ real_config_fd (MMSerialPort *self, int fd, GError **error) stbuf.c_cc[VTIME] = 0; stbuf.c_cc[VEOF] = 1; - stbuf.c_cflag &= ~(CBAUD | CSIZE | CSTOPB | CLOCAL | PARENB); - stbuf.c_cflag |= (speed | bits | CREAD | 0 | parity | stopbits); + /* Use software handshaking */ + stbuf.c_iflag |= (IXON | IXOFF | IXANY); + + /* Set up port speed and serial attributes; also ignore modem control + * lines since most drivers don't implement RTS/CTS anyway. + */ + stbuf.c_cflag &= ~(CBAUD | CSIZE | CSTOPB | PARENB | CRTSCTS); + stbuf.c_cflag |= (speed | bits | CREAD | 0 | parity | stopbits | CLOCAL); if (ioctl (fd, TCSETA, &stbuf) < 0) { g_set_error (error, diff --git a/src/tests/test-modem-helpers.c b/src/tests/test-modem-helpers.c index 980c4ae7..addeee3e 100644 --- a/src/tests/test-modem-helpers.c +++ b/src/tests/test-modem-helpers.c @@ -670,6 +670,25 @@ test_cgreg2_f3607gw_unsolicited (void *f, gpointer d) test_creg_match ("Ericsson F3607gw CGREG=2", FALSE, reply, data, &result); } +static void +test_creg_cgreg_multi_unsolicited (void *f, gpointer d) +{ + TestData *data = (TestData *) d; + const char *reply = "\r\n+CREG: 5\r\n\r\n+CGREG: 0\r\n"; + const CregResult result = { 5, 0, 0, -1, 1, FALSE}; + + test_creg_match ("Multi CREG/CGREG", FALSE, reply, data, &result); +} + +static void +test_creg_cgreg_multi2_unsolicited (void *f, gpointer d) +{ + TestData *data = (TestData *) d; + const char *reply = "\r\n+CGREG: 0\r\n\r\n+CREG: 5\r\n"; + const CregResult result = { 0, 0, 0, -1, 1, TRUE}; + + test_creg_match ("Multi CREG/CGREG #2", FALSE, reply, data, &result); +} static TestData * test_data_new (void) @@ -753,6 +772,9 @@ int main (int argc, char **argv) g_test_suite_add (suite, TESTCASE (test_cgreg2_f3607gw_solicited, data)); g_test_suite_add (suite, TESTCASE (test_cgreg2_f3607gw_unsolicited, data)); + g_test_suite_add (suite, TESTCASE (test_creg_cgreg_multi_unsolicited, data)); + g_test_suite_add (suite, TESTCASE (test_creg_cgreg_multi2_unsolicited, data)); + result = g_test_run (); test_data_free (data); |