static void cnti_set_ready (MMBaseModem *self, GAsyncResult *res, GSimpleAsyncResult *simple) { GError *error = NULL; const gchar *response; response = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, &error); if (!response) g_simple_async_result_take_error (simple, error); else { MMModemAccessTechnology act = MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN; const gchar *p; p = mm_strip_tag (response, "*CNTI:"); p = strchr (p, ','); if (p) act = mm_string_to_access_tech (p + 1); if (act == MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN) g_simple_async_result_set_error ( simple, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Couldn't parse access technologies result: '%s'", response); else g_simple_async_result_set_op_res_gpointer (simple, GUINT_TO_POINTER (act), NULL); } g_simple_async_result_complete (simple); g_object_unref (simple); }
static gboolean load_access_technologies_finish (MMIfaceModem *self, GAsyncResult *res, MMModemAccessTechnology *access_technologies, guint *mask, GError **error) { const gchar *p; const gchar *response; response = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, error); if (!response) return FALSE; p = mm_strip_tag (response, "*CNTI:"); p = strchr (p, ','); if (p) { /* We are reporting ALL 3GPP access technologies here */ *access_technologies = mm_string_to_access_tech (p + 1); *mask = MM_IFACE_MODEM_3GPP_ALL_ACCESS_TECHNOLOGIES_MASK; return TRUE; } g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Couldn't parse access technologies result: '%s'", response); return FALSE; }
static void cnti_set_ready (MMBaseModem *self, GAsyncResult *res, GSimpleAsyncResult *simple) { GError *error = NULL; const gchar *response; const gchar *p; response = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, &error); if (!response) { g_simple_async_result_take_error (simple, error); g_simple_async_result_complete (simple); g_object_unref (simple); return; } p = mm_strip_tag (response, "$CNTI:"); p = strchr (p, ','); if (!p) { error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Couldn't parse $CNTI result '%s'", response); g_simple_async_result_take_error (simple, error); g_simple_async_result_complete (simple); g_object_unref (simple); return; } snapshot_result_complete_simple (simple, mm_string_to_access_tech (p), MM_IFACE_MODEM_3GPP_ALL_ACCESS_TECHNOLOGIES_MASK); g_object_unref (simple); }
static void get_act_request_done (MMAtSerialPort *port, GString *response, GError *error, gpointer user_data) { MMCallbackInfo *info = user_data; MMModemGsmAccessTech act = MM_MODEM_GSM_ACCESS_TECH_UNKNOWN; const char *p; /* If the modem has already been removed, return without * scheduling callback */ if (mm_callback_info_check_modem_removed (info)) return; if (error) info->error = g_error_copy (error); else { p = mm_strip_tag (response->str, "+PSRAT:"); act = mm_gsm_string_to_access_tech (p); } mm_callback_info_set_result (info, GUINT_TO_POINTER (act), NULL); mm_callback_info_schedule (info); }
static guint load_signal_quality_finish (MMIfaceModem *self, GAsyncResult *res, GError **error) { gint quality = 0; const gchar *result; result = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, error); if (!result) return 0; /* Skip possible whitespaces after '+CSQF:' and before the response */ result = mm_strip_tag (result, "+CSQF:"); while (*result == ' ') result++; if (sscanf (result, "%d", &quality)) /* Normalize the quality. <rssi> is NOT given in dBs, * given as a relative value between 0 and 5 */ quality = CLAMP (quality, 0, 5) * 100 / 5; else g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Could not parse signal quality results"); return quality; }
static gboolean parse_octi_response (const gchar *response, MMModemAccessTechnology *access_technology) { MMModemAccessTechnology current = MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN; const gchar *p; GRegex *r; GMatchInfo *match_info; gchar *str; gboolean success = FALSE; p = mm_strip_tag (response, "_OCTI:"); r = g_regex_new ("(\\d),(\\d)", G_REGEX_UNGREEDY, 0, NULL); g_assert (r != NULL); g_regex_match (r, p, 0, &match_info); if (g_match_info_matches (match_info)) { str = g_match_info_fetch (match_info, 2); if (str && octi_to_mm (str[0], ¤t)) { *access_technology = current; success = TRUE; } g_free (str); } g_match_info_free (match_info); g_regex_unref (r); return success; }
static gboolean parse_owcti_response (const gchar *response, MMModemAccessTechnology *access_technology) { response = mm_strip_tag (response, "_OWCTI:"); return owcti_to_mm (*response, access_technology); }
static gboolean load_access_technologies_finish (MMIfaceModem *self, GAsyncResult *res, MMModemAccessTechnology *access_technologies, guint *mask, GError **error) { MMModemAccessTechnology act; const gchar *p; const gchar *response; response = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, error); if (!response) return FALSE; act = MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN; p = mm_strip_tag (response, "+WGPRSIND:"); if (p) { switch (*p) { case '1': /* GPRS only */ act = MM_MODEM_ACCESS_TECHNOLOGY_GPRS; break; case '2': /* EGPRS/EDGE supported */ act = MM_MODEM_ACCESS_TECHNOLOGY_EDGE; break; case '3': /* 3G R99 supported */ act = MM_MODEM_ACCESS_TECHNOLOGY_UMTS; break; case '4': /* HSDPA supported */ act = MM_MODEM_ACCESS_TECHNOLOGY_HSDPA; break; case '5': /* HSUPA supported */ act = MM_MODEM_ACCESS_TECHNOLOGY_HSUPA; break; default: break; } } if (act == MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN) { g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Couldn't parse access technologies result: '%s'", response); return FALSE; } /* We are reporting ALL 3GPP access technologies here */ *access_technologies = act; *mask = MM_IFACE_MODEM_3GPP_ALL_ACCESS_TECHNOLOGIES_MASK; return TRUE; }
static gboolean load_current_modes_finish (MMIfaceModem *self, GAsyncResult *res, MMModemMode *allowed, MMModemMode *preferred, GError **error) { const gchar *response; const gchar *str; gint a, b; response = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, error); if (!response) return FALSE; str = mm_strip_tag (response, "_OPSYS:"); if (!sscanf (str, "%d,%d", &a, &b)) { g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Couldn't parse OPSYS response: '%s'", response); return FALSE; } switch (a) { case 0: *allowed = MM_MODEM_MODE_2G; *preferred = MM_MODEM_MODE_NONE; return TRUE; case 1: *allowed = MM_MODEM_MODE_3G; *preferred = MM_MODEM_MODE_NONE; return TRUE; case 2: *allowed = (MM_MODEM_MODE_2G | MM_MODEM_MODE_3G); *preferred = MM_MODEM_MODE_2G; return TRUE; case 3: *allowed = (MM_MODEM_MODE_2G | MM_MODEM_MODE_3G); *preferred = MM_MODEM_MODE_3G; return TRUE; case 5: /* any */ *allowed = (MM_MODEM_MODE_2G | MM_MODEM_MODE_3G); *preferred = MM_MODEM_MODE_NONE; return TRUE; default: break; } g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Couldn't parse unexpected OPSYS response: '%s'", response); return FALSE; }
static void get_3g_band_ready (MMBroadbandModemWavecom *self, GAsyncResult *res, GSimpleAsyncResult *operation_result) { const gchar *response; const gchar *p; GError *error = NULL; GArray *bands_array = NULL; guint32 wavecom_band; response = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, &error); if (!response) { /* Let the error be critical. */ g_simple_async_result_take_error (operation_result, error); g_simple_async_result_complete (operation_result); g_object_unref (operation_result); return; } /* Example reply: * AT+WUBS? --> * <-- +WUBS: "3",1 * <-- OK * The "3" meaning here Band I and II are selected. */ p = mm_strip_tag (response, "+WUBS:"); if (*p == '"') p++; wavecom_band = atoi (p); if (wavecom_band > 0) { guint i; for (i = 0; i < G_N_ELEMENTS (bands_3g); i++) { if (bands_3g[i].wavecom_band_flag & wavecom_band) { if (G_UNLIKELY (!bands_array)) bands_array = g_array_new (FALSE, FALSE, sizeof (MMModemBand)); g_array_append_val (bands_array, bands_3g[i].mm_band); } } } if (!bands_array) g_simple_async_result_set_error (operation_result, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Couldn't parse current bands reply: '%s'", response); else g_simple_async_result_set_op_res_gpointer (operation_result, bands_array, (GDestroyNotify)g_array_unref); g_simple_async_result_complete (operation_result); g_object_unref (operation_result); }
static gboolean load_current_modes_finish (MMIfaceModem *self, GAsyncResult *res, MMModemMode *allowed, MMModemMode *preferred, GError **error) { const gchar *response; const gchar *str; gint mododr = -1; response = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, error); if (!response) return FALSE; str = mm_strip_tag (response, "+MODODR:"); if (!str) { g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Couldn't parse MODODR response: '%s'", response); return FALSE; } mododr = atoi (str); switch (mododr) { case 1: /* UMTS only */ *allowed = MM_MODEM_MODE_3G; *preferred = MM_MODEM_MODE_NONE; return TRUE; case 2: /* UMTS preferred */ *allowed = (MM_MODEM_MODE_2G | MM_MODEM_MODE_3G); *preferred = MM_MODEM_MODE_3G; return TRUE; case 3: /* GSM only */ *allowed = MM_MODEM_MODE_2G; *preferred = MM_MODEM_MODE_NONE; return TRUE; case 4: /* GSM preferred */ *allowed = (MM_MODEM_MODE_2G | MM_MODEM_MODE_3G); *preferred = MM_MODEM_MODE_2G; return TRUE; default: break; } g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Couldn't parse unexpected MODODR response: '%s'", response); return FALSE; }
static void supported_ms_classes_query_ready (MMBaseModem *self, GAsyncResult *res, GSimpleAsyncResult *simple) { const gchar *response; GError *error = NULL; MMModemMode mode; response = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, &error); if (!response) { /* Let the error be critical. */ g_simple_async_result_take_error (simple, error); g_simple_async_result_complete (simple); g_object_unref (simple); return; } response = mm_strip_tag (response, "+CGCLASS:"); mode = MM_MODEM_MODE_NONE; if (strstr (response, WAVECOM_MS_CLASS_A_IDSTR)) { mm_dbg ("Modem supports Class A mobile station"); mode |= MM_MODEM_MODE_3G; } if (strstr (response, WAVECOM_MS_CLASS_B_IDSTR)) { mm_dbg ("Modem supports Class B mobile station"); mode |= (MM_MODEM_MODE_2G | MM_MODEM_MODE_CS); } if (strstr (response, WAVECOM_MS_CLASS_CG_IDSTR)) { mm_dbg ("Modem supports Class CG mobile station"); mode |= MM_MODEM_MODE_2G; } if (strstr (response, WAVECOM_MS_CLASS_CC_IDSTR)) { mm_dbg ("Modem supports Class CC mobile station"); mode |= MM_MODEM_MODE_CS; } /* If none received, error */ if (mode == MM_MODEM_MODE_NONE) g_simple_async_result_set_error (simple, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Couldn't get supported mobile station classes: '%s'", response); else g_simple_async_result_set_op_res_gpointer (simple, GUINT_TO_POINTER (mode), NULL); g_simple_async_result_complete (simple); g_object_unref (simple); }
GArray * mm_huawei_parse_syscfgex_test (const gchar *response, GError **error) { gchar **split; GError *inner_error = NULL; GArray *out; if (!response || !g_str_has_prefix (response, "^SYSCFGEX:")) { g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Missing ^SYSCFGEX prefix"); return NULL; } /* Examples: * * ^SYSCFGEX: ("00","03","02","01","99"), * ((2000004e80380,"GSM850/GSM900/GSM1800/GSM1900/WCDMA850/WCDMA900/WCDMA1900/WCDMA2100"), * (3fffffff,"All Bands")), * (0-3), * (0-4), * ((800c5,"LTE2100/LTE1800/LTE2600/LTE900/LTE800"), * (7fffffffffffffff,"All bands")) */ split = split_groups (mm_strip_tag (response, "^SYSCFGEX:"), error); if (!split) return NULL; /* We expect 5 string chunks */ if (g_strv_length (split) < 5) { g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Unexpected ^SYSCFGEX format"); g_strfreev (split); return NULL; } out = parse_mode_combination_string_list (split[0], &inner_error); g_strfreev (split); if (inner_error) { g_propagate_error (error, inner_error); return NULL; } return out; }
GArray * mm_huawei_parse_syscfg_test (const gchar *response, GError **error) { gchar **split; GError *inner_error = NULL; GArray *out; if (!response || !g_str_has_prefix (response, "^SYSCFG:")) { g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Missing ^SYSCFG prefix"); return NULL; } /* Examples: * * ^SYSCFG:(2,13,14,16), * (0-3), * ((400000,"WCDMA2100")), * (0-2), * (0-4) */ split = split_groups (mm_strip_tag (response, "^SYSCFG:"), error); if (!split) return NULL; /* We expect 5 string chunks */ if (g_strv_length (split) < 5) { g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Unexpected ^SYSCFG format"); g_strfreev (split); return FALSE; } /* Parse supported mode combinations */ out = parse_syscfg_modes (split[0], split[1], &inner_error); g_strfreev (split); if (inner_error) { g_propagate_error (error, inner_error); return NULL; } return out; }
static void get_2g_band_ready (MMBroadbandModemWavecom *self, GAsyncResult *res, GSimpleAsyncResult *operation_result) { const gchar *response; const gchar *p; GError *error = NULL; GArray *bands_array = NULL; response = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, &error); if (!response) { /* Let the error be critical. */ g_simple_async_result_take_error (operation_result, error); g_simple_async_result_complete (operation_result); g_object_unref (operation_result); return; } p = mm_strip_tag (response, "+WMBS:"); if (p) { guint i; for (i = 0; i < G_N_ELEMENTS (bands_2g); i++) { if (bands_2g[i].wavecom_band == *p) { guint j; if (G_UNLIKELY (!bands_array)) bands_array = g_array_new (FALSE, FALSE, sizeof (MMModemBand)); for (j = 0; j < bands_2g[i].n_mm_bands; j++) g_array_append_val (bands_array, bands_2g[i].mm_bands[j]); } } } if (!bands_array) g_simple_async_result_set_error (operation_result, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Couldn't parse current bands reply: '%s'", response); else g_simple_async_result_set_op_res_gpointer (operation_result, bands_array, (GDestroyNotify)g_array_unref); g_simple_async_result_complete (operation_result); g_object_unref (operation_result); }
static void get_allowed_mode_done (MMAtSerialPort *port, GString *response, GError *error, gpointer user_data) { MMCallbackInfo *info = (MMCallbackInfo *) user_data; const char *p; MMModemGsmAllowedMode mode = MM_MODEM_GSM_ALLOWED_MODE_ANY; gint mododr = -1; /* If the modem has already been removed, return without * scheduling callback */ if (mm_callback_info_check_modem_removed (info)) return; if (error) { info->error = g_error_copy (error); goto done; } p = mm_strip_tag (response->str, "+MODODR:"); if (!p) { info->error = g_error_new_literal (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "Failed to parse the allowed mode response"); goto done; } mododr = atoi (p); switch (mododr) { case 1: mode = MM_MODEM_GSM_ALLOWED_MODE_3G_ONLY; break; case 2: case 4: mode = MM_MODEM_GSM_ALLOWED_MODE_3G_PREFERRED; break; case 3: mode = MM_MODEM_GSM_ALLOWED_MODE_2G_ONLY; break; default: break; } mm_callback_info_set_result (info, GUINT_TO_POINTER (mode), NULL); done: mm_callback_info_schedule (info); }
static gboolean load_current_modes_finish (MMIfaceModem *_self, GAsyncResult *res, MMModemMode *allowed, MMModemMode *preferred, GError **error) { MMBroadbandModemMbm *self = MM_BROADBAND_MODEM_MBM (_self); const gchar *response; guint a; response = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, error); if (!response) return FALSE; if (mm_get_uint_from_str (mm_strip_tag (response, "+CFUN:"), &a)) { /* No settings to set preferred */ *preferred = MM_MODEM_MODE_NONE; switch (a) { case MBM_NETWORK_MODE_OFFLINE: case MBM_NETWORK_MODE_LOW_POWER: /* Do not update internal mbm_mode */ *allowed = MM_MODEM_MODE_NONE; break; case MBM_NETWORK_MODE_2G: self->priv->mbm_mode = MBM_NETWORK_MODE_2G; *allowed = MM_MODEM_MODE_2G; break; case MBM_NETWORK_MODE_3G: self->priv->mbm_mode = MBM_NETWORK_MODE_3G; *allowed = MM_MODEM_MODE_3G; break; default: /* Do not update internal mbm_mode */ *allowed = (MM_MODEM_MODE_2G | MM_MODEM_MODE_3G); break; } return TRUE; } g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Couldn't parse +CFUN response: '%s'", response); return FALSE; }
static gboolean response_processor_psnt_ignore_at_errors (MMBaseModem *self, gpointer none, const gchar *command, const gchar *response, gboolean last_command, const GError *error, GVariant **result, GError **result_error) { const gchar *psnt, *mode; if (error) { /* Ignore AT errors (ie, ERROR or CMx ERROR) */ if (error->domain != MM_MOBILE_EQUIPMENT_ERROR || last_command) *result_error = g_error_copy (error); return FALSE; } psnt = mm_strip_tag (response, "#PSNT:"); mode = strchr (psnt, ','); if (mode) { switch (atoi (++mode)) { case 0: *result = g_variant_new_uint32 (MM_MODEM_ACCESS_TECHNOLOGY_GPRS); return TRUE; case 1: *result = g_variant_new_uint32 (MM_MODEM_ACCESS_TECHNOLOGY_EDGE); return TRUE; case 2: *result = g_variant_new_uint32 (MM_MODEM_ACCESS_TECHNOLOGY_UMTS); return TRUE; case 3: *result = g_variant_new_uint32 (MM_MODEM_ACCESS_TECHNOLOGY_HSDPA); return TRUE; default: break; } } g_set_error (result_error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Failed to parse #PSNT response: '%s'", response); return FALSE; }
static gboolean load_access_technologies_finish (MMIfaceModem *self, GAsyncResult *res, MMModemAccessTechnology *access_technologies, guint *mask, GError **error) { const gchar *result; result = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, error); if (!result) return FALSE; result = mm_strip_tag (result, "+PSRAT:"); *access_technologies = mm_string_to_access_tech (result); *mask = MM_MODEM_ACCESS_TECHNOLOGY_ANY; return TRUE; }
const MMHuaweiPrefmodeCombination * mm_huawei_parse_prefmode_response (const gchar *response, const GArray *supported_mode_combinations, GError **error) { gint mode; guint i; /* Format: * * ^PREFMODE: <mode> */ response = mm_strip_tag (response, "^PREFMODE:"); if (!sscanf (response, "%d", &mode)) { /* Dump error to upper layer */ g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Unexpected PREFMODE response: '%s'", response); return NULL; } /* Look for current modes among the supported ones */ for (i = 0; i < supported_mode_combinations->len; i++) { const MMHuaweiPrefmodeCombination *combination; combination = &g_array_index (supported_mode_combinations, MMHuaweiPrefmodeCombination, i); if (mode == combination->prefmode) return combination; } g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "No PREFMODE combination found matching the current one (%d)", mode); return NULL; }
static gboolean load_access_technologies_finish (MMIfaceModem *self, GAsyncResult *res, MMModemAccessTechnology *access_technologies, guint *mask, GError **error) { const gchar *response; response = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, error); if (!response) return FALSE; /* Sample response from an MF626: * +ZPAS: "******","CS_ONLY" */ response = mm_strip_tag (response, "+ZPAS:"); *access_technologies = mm_string_to_access_tech (response); *mask = MM_IFACE_MODEM_3GPP_ALL_ACCESS_TECHNOLOGIES_MASK; return TRUE; }
static void iccid_read_ready (MMBaseModem *modem, GAsyncResult *res, GSimpleAsyncResult *simple) { GError *error = NULL; const gchar *response; const gchar *p; char *parsed; GError *local = NULL; response = mm_base_modem_at_command_finish (modem, res, &error); if (!response) { g_simple_async_result_take_error (simple, error); g_simple_async_result_complete (simple); g_object_unref (simple); return; } p = mm_strip_tag (response, "!ICCID:"); if (!p) { g_simple_async_result_set_error (simple, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Failed to parse !ICCID response: '%s'", response); g_simple_async_result_complete (simple); g_object_unref (simple); return; } parsed = mm_3gpp_parse_iccid (p, &local); if (parsed) g_simple_async_result_set_op_res_gpointer (simple, parsed, g_free); else g_simple_async_result_take_error (simple, local); g_simple_async_result_complete (simple); g_object_unref (simple); }
static void connect_3gpp_qmistatus_ready (MMBaseModem *modem, GAsyncResult *res, DetailedConnectContext *ctx) { const gchar *result; GError *error = NULL; result = mm_base_modem_at_command_finish (MM_BASE_MODEM (ctx->modem), res, &error); if (!result) { mm_warn ("QMI connection status failed: %s", error->message); g_simple_async_result_take_error (ctx->result, error); detailed_connect_context_complete_and_free (ctx); return; } result = mm_strip_tag (result, "$NWQMISTATUS:"); if (g_strrstr(result, "QMI State: CONNECTED")) { mm_dbg("Connected"); detailed_connect_context_complete_and_free_successful (ctx); return; } else { mm_dbg("Error: '%s'", result); if (ctx->retries > 0) { ctx->retries--; mm_dbg("Retrying status check in a second. %d retries left.", ctx->retries); g_timeout_add_seconds(1, (GSourceFunc)connect_3gpp_qmistatus, ctx); return; } g_simple_async_result_set_error (ctx->result, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "%s", result); } detailed_connect_context_complete_and_free (ctx); }
static MMModemPowerState load_power_state_finish (MMIfaceModem *self, GAsyncResult *res, GError **error) { const gchar *response; guint a; response = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, error); if (!response) return FALSE; if (mm_get_uint_from_str (mm_strip_tag (response, "+CFUN:"), &a)) { switch (a) { case MBM_NETWORK_MODE_OFFLINE: return MM_MODEM_POWER_STATE_OFF; case MBM_NETWORK_MODE_LOW_POWER: return MM_MODEM_POWER_STATE_LOW; case MBM_NETWORK_MODE_ANY: case MBM_NETWORK_MODE_2G: case MBM_NETWORK_MODE_3G: return MM_MODEM_POWER_STATE_ON; default: break; } } g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Couldn't parse +CFUN response: '%s'", response); return MM_MODEM_POWER_STATE_UNKNOWN; }
static void disconnect_3gpp_status_complete (MMBaseModem *modem, GAsyncResult *res, DetailedDisconnectContext *ctx) { const gchar *result; GError *error = NULL; result = mm_base_modem_at_command_finish (MM_BASE_MODEM (modem), res, &error); g_simple_async_result_set_op_res_gboolean (ctx->result, FALSE); if (error) { mm_dbg("QMI connection status failed: %s", error->message); g_error_free (error); } result = mm_strip_tag (result, "$NWQMISTATUS:"); if (g_strrstr(result, "QMI State: DISCONNECTED")) g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE); detailed_disconnect_context_complete_and_free (ctx); }
const MMHuaweiSyscfgexCombination * mm_huawei_parse_syscfgex_response (const gchar *response, const GArray *supported_mode_combinations, GError **error) { gchar **split; guint i; gsize len; gchar *str; if (!response || !g_str_has_prefix (response, "^SYSCFGEX:")) { g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Missing ^SYSCFGEX prefix"); return NULL; } /* Format: * * ^SYSCFGEX: "00",3FFFFFFF,1,2,7FFFFFFFFFFFFFFF * ^SYSCFGEX: <mode>,<band>,<roam>,<srvdomain>,<lte-band> */ response = mm_strip_tag (response, "^SYSCFGEX:"); split = g_strsplit (response, ",", -1); /* We expect 5 string chunks */ if (g_strv_length (split) < 5) { g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Unexpected ^SYSCFGEX response format"); g_strfreev (split); return NULL; } /* Unquote */ str = split[0]; len = strlen (str); if ((len >= 2) && (str[0] == '"') && (str[len - 1] == '"')) { str[0] = ' '; str[len - 1] = ' '; str = g_strstrip (str); } /* Look for current modes among the supported ones */ for (i = 0; i < supported_mode_combinations->len; i++) { const MMHuaweiSyscfgexCombination *combination; combination = &g_array_index (supported_mode_combinations, MMHuaweiSyscfgexCombination, i); if (g_str_equal (str, combination->mode_str)) { g_strfreev (split); return combination; } } g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "No SYSCFGEX combination found matching the current one (%s)", str); g_strfreev (split); return NULL; }
const MMHuaweiSyscfgCombination * mm_huawei_parse_syscfg_response (const gchar *response, const GArray *supported_mode_combinations, GError **error) { gchar **split; guint mode; guint acqorder; guint i; if (!response || !g_str_has_prefix (response, "^SYSCFG:")) { g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Missing ^SYSCFG prefix"); return NULL; } /* Format: * * ^SYSCFG: <mode>,<acqorder>,<band>,<roam>,<srvdomain> */ response = mm_strip_tag (response, "^SYSCFG:"); split = g_strsplit (response, ",", -1); /* We expect 5 string chunks */ if (g_strv_length (split) < 5 || !mm_get_uint_from_str (split[0], &mode) || !mm_get_uint_from_str (split[1], &acqorder)) { /* Dump error to upper layer */ g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Unexpected ^SYSCFG response: '%s'", response); g_strfreev (split); return NULL; } /* Fix invalid modes with non-sensical acquisition orders */ if (mode == 14 && acqorder != 0) /* WCDMA only but acqorder != "Automatic" */ acqorder = 0; else if (mode == 13 && acqorder != 0) /* GSM only but acqorder != "Automatic" */ acqorder = 0; /* Look for current modes among the supported ones */ for (i = 0; i < supported_mode_combinations->len; i++) { const MMHuaweiSyscfgCombination *combination; combination = &g_array_index (supported_mode_combinations, MMHuaweiSyscfgCombination, i); if (mode == combination->mode && acqorder == combination->acqorder) { g_strfreev (split); return combination; } } g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "No SYSCFG combination found matching the current one (%d,%d)", mode, acqorder); g_strfreev (split); return NULL; }
static void current_ms_class_ready (MMBaseModem *self, GAsyncResult *res, GSimpleAsyncResult *simple) { LoadAllowedModesResult result; const gchar *response; GError *error = NULL; response = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, &error); if (!response) { g_simple_async_result_take_error (simple, error); g_simple_async_result_complete (simple); g_object_unref (simple); return; } response = mm_strip_tag (response, "+CGCLASS:"); if (strncmp (response, WAVECOM_MS_CLASS_A_IDSTR, strlen (WAVECOM_MS_CLASS_A_IDSTR)) == 0) { mm_dbg ("Modem configured as a Class A mobile station"); /* For 3G devices, query WWSM status */ mm_base_modem_at_command (MM_BASE_MODEM (self), "+WWSM?", 3, FALSE, (GAsyncReadyCallback)wwsm_read_ready, simple); return; } result.allowed = MM_MODEM_MODE_NONE; result.preferred = MM_MODEM_MODE_NONE; if (strncmp (response, WAVECOM_MS_CLASS_B_IDSTR, strlen (WAVECOM_MS_CLASS_B_IDSTR)) == 0) { mm_dbg ("Modem configured as a Class B mobile station"); result.allowed = (MM_MODEM_MODE_2G | MM_MODEM_MODE_CS); result.preferred = MM_MODEM_MODE_2G; } else if (strncmp (response, WAVECOM_MS_CLASS_CG_IDSTR, strlen (WAVECOM_MS_CLASS_CG_IDSTR)) == 0) { mm_dbg ("Modem configured as a Class CG mobile station"); result.allowed = MM_MODEM_MODE_2G; result.preferred = MM_MODEM_MODE_NONE; } else if (strncmp (response, WAVECOM_MS_CLASS_CC_IDSTR, strlen (WAVECOM_MS_CLASS_CC_IDSTR)) == 0) { mm_dbg ("Modem configured as a Class CC mobile station"); result.allowed = MM_MODEM_MODE_CS; result.preferred = MM_MODEM_MODE_NONE; } if (result.allowed == MM_MODEM_MODE_NONE) g_simple_async_result_set_error (simple, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Unknown mobile station class: '%s'", response); else g_simple_async_result_set_op_res_gpointer (simple, &result, NULL); g_simple_async_result_complete (simple); g_object_unref (simple); }
GArray * mm_huawei_parse_prefmode_test (const gchar *response, GError **error) { gchar **split; guint i; MMModemMode all = MM_MODEM_MODE_NONE; GArray *out; response = mm_strip_tag (response, "^PREFMODE:"); split = g_strsplit_set (response, " (,)\r\n", -1); if (!split) { g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Unexpected ^PREFMODE format output"); return NULL; } out = g_array_sized_new (FALSE, FALSE, sizeof (MMHuaweiPrefmodeCombination), 3); for (i = 0; split[i]; i++) { guint val; MMModemMode preferred = MM_MODEM_MODE_NONE; GError *inner_error = NULL; MMHuaweiPrefmodeCombination combination; if (split[i][0] == '\0') continue; if (!mm_get_uint_from_str (split[i], &val)) { mm_dbg ("Error parsing ^PREFMODE value: %s", split[i]); continue; } if (!mode_from_prefmode (val, &preferred, &inner_error)) { mm_dbg ("Unhandled ^PREFMODE: %s", inner_error->message); g_error_free (inner_error); continue; } combination.prefmode = val; combination.allowed = MM_MODEM_MODE_NONE; /* reset it later */ combination.preferred = preferred; all |= preferred; g_array_append_val (out, combination); } g_strfreev (split); /* No value */ if (out->len == 0) { g_array_unref (out); g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "^PREFMODE response contains no valid values"); return NULL; } /* Single value listed; PREFERRED=NONE... */ if (out->len == 1) { MMHuaweiPrefmodeCombination *combination; combination = &g_array_index (out, MMHuaweiPrefmodeCombination, 0); combination->allowed = all; combination->preferred = MM_MODEM_MODE_NONE; } else { /* Multiple values, reset ALLOWED */ for (i = 0; i < out->len; i++) { MMHuaweiPrefmodeCombination *combination; combination = &g_array_index (out, MMHuaweiPrefmodeCombination, i); combination->allowed = all; if (combination->preferred == all) combination->preferred = MM_MODEM_MODE_NONE; } } return out; }
static void imsi_read_ready (MMBaseModem *modem, GAsyncResult *res, GSimpleAsyncResult *simple) { GError *error = NULL; const gchar *response, *str; gchar buf[19]; gchar imsi[16]; gsize len = 0; gint sw1, sw2; gint i; response = mm_base_modem_at_command_finish (modem, res, &error); if (!response) { g_simple_async_result_take_error (simple, error); g_simple_async_result_complete (simple); g_object_unref (simple); return; } memset (buf, 0, sizeof (buf)); str = mm_strip_tag (response, "+CRSM:"); /* With or without quotes... */ if (sscanf (str, "%d,%d,\"%18c\"", &sw1, &sw2, (char *) &buf) != 3 && sscanf (str, "%d,%d,%18c", &sw1, &sw2, (char *) &buf) != 3) { g_simple_async_result_set_error (simple, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Failed to parse the CRSM response: '%s'", response); g_simple_async_result_complete (simple); g_object_unref (simple); return; } if ((sw1 != 0x90 || sw2 != 0x00) && (sw1 != 0x91) && (sw1 != 0x92) && (sw1 != 0x9f)) { g_simple_async_result_set_error (simple, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "SIM failed to handle CRSM request (sw1 %d sw2 %d)", sw1, sw2); g_simple_async_result_complete (simple); g_object_unref (simple); return; } /* Make sure the buffer is only digits or 'F' */ for (len = 0; len < sizeof (buf) && buf[len]; len++) { if (isdigit (buf[len])) continue; if (buf[len] == 'F' || buf[len] == 'f') { buf[len] = 'F'; /* canonicalize the F */ continue; } if (buf[len] == '\"') { buf[len] = 0; break; } /* Invalid character */ g_simple_async_result_set_error (simple, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "CRSM IMSI response contained invalid character '%c'", buf[len]); g_simple_async_result_complete (simple); g_object_unref (simple); return; } /* BCD encoded IMSIs plus the length byte and parity are 18 digits long */ if (len != 18) { g_simple_async_result_set_error (simple, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Invalid +CRSM IMSI response size (was %zd, expected 18)", len); g_simple_async_result_complete (simple); g_object_unref (simple); return; } /* Skip the length byte (digit 0-1) and parity (digit 3). Swap digits in * the EFimsi response to get the actual IMSI, each group of 2 digits is * reversed in the +CRSM response. i.e.: * * **0*21436587a9cbed -> 0123456789abcde */ memset (imsi, 0, sizeof (imsi)); imsi[0] = buf[2]; for (i = 1; i < 8; i++) { imsi[(i * 2) - 1] = buf[(i * 2) + 3]; imsi[i * 2] = buf[(i * 2) + 2]; } /* Zero out the first F, if any, for IMSIs shorter than 15 digits */ for (i = 0; i < 15; i++) { if (imsi[i] == 'F') { imsi[i++] = 0; break; } } /* Ensure all 'F's, if any, are at the end */ for (; i < 15; i++) { if (imsi[i] != 'F') { g_simple_async_result_set_error (simple, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Invalid +CRSM IMSI length (unexpected F)"); g_simple_async_result_complete (simple); g_object_unref (simple); return; } } g_simple_async_result_set_op_res_gpointer (simple, imsi, NULL); g_simple_async_result_complete (simple); g_object_unref (simple); }