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], &current)) {
            *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);
}
Пример #16
0
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;
}
Пример #22
0
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;
}
Пример #30
0
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);
}