diff options
author | Dan Williams <dcbw@redhat.com> | 2016-07-25 23:07:03 -0500 |
---|---|---|
committer | Dan Williams <dcbw@redhat.com> | 2016-07-27 10:44:43 -0500 |
commit | 5350b9f568dc4375c874a3e3912458d512a3cbe4 (patch) | |
tree | 4f4929183f2ba3d1a7360ccce7149ed2d0555081 /libqcdm | |
parent | 30f60de7d3f4d61a100ce1e6a01a746bd2409b81 (diff) |
broadband-modem/libqcdm: add signal strength from QCDM EVDO Pilot Sets log messages
When a CDMA-only modem is registered with the EVDO network, its not possible to
read signal strength in the following cases:
1) while a data connection is active on single-AT-port modems, because the AT
port is used for PPP and not available for AT+CSQ, AT+CIND or vendor-specific
signal strength commands
2) when the modem reports only CDMA 1x signal strength with AT+CSQ
Now that we have a reasonable interpretation of RSSI from the QCDM
EVDO Pilot Sets V2 log messgae, use that when other means of getting
signal strength aren't available.
Diffstat (limited to 'libqcdm')
-rw-r--r-- | libqcdm/src/Makefile.am | 2 | ||||
-rw-r--r-- | libqcdm/src/log-items.h | 34 | ||||
-rw-r--r-- | libqcdm/src/logs.c | 184 | ||||
-rw-r--r-- | libqcdm/src/logs.h | 50 |
4 files changed, 253 insertions, 17 deletions
diff --git a/libqcdm/src/Makefile.am b/libqcdm/src/Makefile.am index 2caaf008..f13098f3 100644 --- a/libqcdm/src/Makefile.am +++ b/libqcdm/src/Makefile.am @@ -16,6 +16,8 @@ libqcdm_la_SOURCES = \ commands.h \ errors.c \ errors.h \ + logs.c \ + logs.h \ result.c \ result.h \ result-private.h \ diff --git a/libqcdm/src/log-items.h b/libqcdm/src/log-items.h index 71f0f1e0..8802dfdb 100644 --- a/libqcdm/src/log-items.h +++ b/libqcdm/src/log-items.h @@ -37,7 +37,7 @@ enum { DM_LOG_ITEM_EVDO_REV_POWER_CONTROL = 0x1063, DM_LOG_ITEM_EVDO_ARQ_EFFECTIVE_RECEIVE_RATE = 0x1066, DM_LOG_ITEM_EVDO_AIR_LINK_SUMMARY = 0x1068, - DM_LOG_ITEM_EVDO_POWER = 0x1069 + DM_LOG_ITEM_EVDO_POWER = 0x1069, DM_LOG_ITEM_EVDO_FWD_LINK_PACKET_SNAPSHOT = 0x106A, DM_LOG_ITEM_EVDO_ACCESS_ATTEMPT = 0x106C, DM_LOG_ITEM_EVDO_REV_ACTIVITY_BITS_BUFFER = 0x106D, @@ -91,14 +91,14 @@ struct DMLogItemCdmaReversePowerControl { typedef struct DMLogItemCdmaReversePowerControl DMLogItemCdmaReversePowerControl; /* DM_LOG_ITEM_EVDO_PILOT_SETS_V2 */ -struct EvdoPilotSetsV2PilotRecord { +struct DMLogItemEvdoPilotSetsV2Pilot { u_int16_t pilot_pn; /* HDR pilot energy doesn't appear to be in the same units as 1x pilot - * energy (eg, -0.5 dBm increments). Instead, you can approximate EC/IO - * by using this formula empirically derived from simultaneous AT!ECIO - * and HDR Pilot Sets V2 results from a Sierra modem: + * energy (eg, -0.5 dBm increments). Instead it appears roughly correlated + * to RSSI dBm by using this formula empirically derived from simultaneous + * AT!RSSI and HDR Pilot Sets V2 results from a Sierra modem: * - * EC/IO = (pilot_energy / -50) + 1 + * RSSI dBm = -110 + (MAX(pilot_energy - 50, 0) / 14) */ u_int16_t pilot_energy; union { @@ -122,22 +122,22 @@ struct EvdoPilotSetsV2PilotRecord { } Remaining; }; } __attribute__ ((packed)); -typedef struct EvdoPilotSetsV2PilotRecord EvdoPilotSetsV2PilotRecord; +typedef struct DMLogItemEvdoPilotSetsV2Pilot DMLogItemEvdoPilotSetsV2Pilot; /* DM_LOG_ITEM_EVDO_PILOT_SETS_V2 */ struct DMLogItemEvdoPilotSetsV2 { u_int8_t pn_offset; - u_int8_t active_set_count; - u_int8_t active_set_window; - u_int16_t active_set_channel; + u_int8_t active_count; + u_int8_t active_window; + u_int16_t active_channel; u_int8_t unknown1; - u_int8_t candidate_set_count; - u_int8_t candidate_set_window; - u_int8_t remaining_set_count; - u_int8_t remaining_set_window; + u_int8_t candidate_count; + u_int8_t candidate_window; + u_int8_t remaining_count; + u_int8_t remaining_window; u_int8_t unknown2; - EvdoPilotSetsV2PilotRecord records[]; + DMLogItemEvdoPilotSetsV2Pilot sets[]; } __attribute__ ((packed)); typedef struct DMLogItemEvdoPilotSetsV2 DMLogItemEvdoPilotSetsV2; @@ -148,7 +148,7 @@ struct DMLogItemWcdmaTaFingerInfo { u_int8_t non_coherent_interval_len; u_int8_t num_paths; u_int32_t path_enr; - int32_t pn_pos_path + int32_t pn_pos_path; int16_t pri_cpich_psc; u_int8_t unknown1; u_int8_t sec_cpich_ssc; @@ -214,7 +214,7 @@ typedef struct DMLogItemGsmBurstMetric DMLogItemGsmBurstMetric; struct DMLogItemGsmBurstMetrics { u_int8_t channel; - DMLogItemBurstMetric metrics[4]; + DMLogItemGsmBurstMetric metrics[4]; } __attribute__ ((packed)); typedef struct DMLogItemGsmBurstMetrics DMLogItemGsmBurstMetrics; diff --git a/libqcdm/src/logs.c b/libqcdm/src/logs.c new file mode 100644 index 00000000..ef604f6e --- /dev/null +++ b/libqcdm/src/logs.c @@ -0,0 +1,184 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * Copyright (C) 2010 Red Hat, Inc. + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <string.h> +#include <stdlib.h> +#include <endian.h> + +#include "log-items.h" +#include "logs.h" +#include "errors.h" +#include "dm-commands.h" +#include "result-private.h" +#include "utils.h" + + +/**********************************************************************/ + +static qcdmbool +check_log_item (const char *buf, size_t len, u_int16_t log_code, size_t min_len, int *out_error) +{ + DMCmdLog *log_cmd = (DMCmdLog *) buf; + + if (len < sizeof (DMCmdLog)) { + qcdm_err (0, "DM log item malformed (must be at least %zu bytes in length)", sizeof (DMCmdLog)); + if (out_error) + *out_error = -QCDM_ERROR_RESPONSE_MALFORMED; + return FALSE; + } + + if (buf[0] != DIAG_CMD_LOG) { + if (out_error) + *out_error = -QCDM_ERROR_RESPONSE_UNEXPECTED; + return FALSE; + } + + if (le16toh (log_cmd->log_code) != log_code) { + if (out_error) + *out_error = -QCDM_ERROR_RESPONSE_UNEXPECTED; + return FALSE; + } + + if (len < sizeof (DMCmdLog) + min_len) { + qcdm_err (0, "DM log item response not long enough (got %zu, expected " + "at least %zu).", len, sizeof (DMCmdLog) + min_len); + if (out_error) + *out_error = -QCDM_ERROR_RESPONSE_BAD_LENGTH; + return FALSE; + } + + return TRUE; +} + +/**********************************************************************/ + +#define PILOT_SETS_LOG_ACTIVE_SET "active-set" +#define PILOT_SETS_LOG_CANDIDATE_SET "candidate-set" +#define PILOT_SETS_LOG_REMAINING_SET "remaining-set" + +static const char * +set_num_to_str (u_int32_t num) +{ + if (num == QCDM_LOG_ITEM_EVDO_PILOT_SETS_V2_TYPE_ACTIVE) + return PILOT_SETS_LOG_ACTIVE_SET; + if (num == QCDM_LOG_ITEM_EVDO_PILOT_SETS_V2_TYPE_CANDIDATE) + return PILOT_SETS_LOG_CANDIDATE_SET; + if (num == QCDM_LOG_ITEM_EVDO_PILOT_SETS_V2_TYPE_REMAINING) + return PILOT_SETS_LOG_REMAINING_SET; + return NULL; +} + +QcdmResult * +qcdm_log_item_evdo_pilot_sets_v2_new (const char *buf, size_t len, int *out_error) +{ + QcdmResult *result = NULL; + DMLogItemEvdoPilotSetsV2 *pilot_sets; + DMCmdLog *log_cmd = (DMCmdLog *) buf; + size_t sets_len; + + qcdm_return_val_if_fail (buf != NULL, NULL); + + if (!check_log_item (buf, len, DM_LOG_ITEM_EVDO_PILOT_SETS_V2, sizeof (DMLogItemEvdoPilotSetsV2), out_error)) + return NULL; + + pilot_sets = (DMLogItemEvdoPilotSetsV2 *) log_cmd->data; + + result = qcdm_result_new (); + + sets_len = pilot_sets->active_count * sizeof (DMLogItemEvdoPilotSetsV2Pilot); + if (sets_len > 0) { + qcdm_result_add_u8_array (result, + PILOT_SETS_LOG_ACTIVE_SET, + (const u_int8_t *) &pilot_sets->sets[0], + sets_len); + } + + sets_len = pilot_sets->candidate_count * sizeof (DMLogItemEvdoPilotSetsV2Pilot); + if (sets_len > 0) { + qcdm_result_add_u8_array (result, + PILOT_SETS_LOG_CANDIDATE_SET, + (const u_int8_t *) &pilot_sets->sets[pilot_sets->active_count], + sets_len); + } + + sets_len = pilot_sets->remaining_count * sizeof (DMLogItemEvdoPilotSetsV2Pilot); + if (sets_len > 0) { + qcdm_result_add_u8_array (result, + PILOT_SETS_LOG_REMAINING_SET, + (const u_int8_t *) &pilot_sets->sets[pilot_sets->active_count + pilot_sets->candidate_count], + sets_len); + } + + return result; + +} + +qcdmbool +qcdm_log_item_evdo_pilot_sets_v2_get_num (QcdmResult *result, + u_int32_t set_type, + u_int32_t *out_num) +{ + const char *set_name; + const u_int8_t *array = NULL; + size_t array_len = 0; + + qcdm_return_val_if_fail (result != NULL, FALSE); + + set_name = set_num_to_str (set_type); + qcdm_return_val_if_fail (set_name != NULL, FALSE); + + if (qcdm_result_get_u8_array (result, set_name, &array, &array_len)) + return FALSE; + + *out_num = array_len / sizeof (DMLogItemEvdoPilotSetsV2Pilot); + return TRUE; +} + +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) + +qcdmbool +qcdm_log_item_evdo_pilot_sets_v2_get_pilot (QcdmResult *result, + u_int32_t set_type, + u_int32_t num, + u_int32_t *out_pilot_pn, + u_int32_t *out_pilot_energy, + int32_t *out_rssi_dbm) +{ + const char *set_name; + DMLogItemEvdoPilotSetsV2Pilot *pilot; + const u_int8_t *array = NULL; + size_t array_len = 0; + + qcdm_return_val_if_fail (result != NULL, FALSE); + + set_name = set_num_to_str (set_type); + qcdm_return_val_if_fail (set_name != NULL, FALSE); + + if (qcdm_result_get_u8_array (result, set_name, &array, &array_len)) + return FALSE; + + qcdm_return_val_if_fail (num < array_len / sizeof (DMLogItemEvdoPilotSetsV2Pilot), FALSE); + + pilot = (DMLogItemEvdoPilotSetsV2Pilot *) &array[num * sizeof (DMLogItemEvdoPilotSetsV2Pilot)]; + *out_pilot_pn = le16toh (pilot->pilot_pn); + *out_pilot_energy = le16toh (pilot->pilot_energy); + *out_rssi_dbm = (int32_t) (-110.0 + ((float) MAX (le16toh (pilot->pilot_energy) - 50, 0) / 14.0)); + return TRUE; +} + +/**********************************************************************/ + diff --git a/libqcdm/src/logs.h b/libqcdm/src/logs.h new file mode 100644 index 00000000..bb17d1f8 --- /dev/null +++ b/libqcdm/src/logs.h @@ -0,0 +1,50 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * Copyright (C) 2010 Red Hat, Inc. + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef LIBQCDM_LOGS_H +#define LIBQCDM_LOGS_H + +#include "utils.h" +#include "result.h" + +/**********************************************************************/ + +enum { + QCDM_LOG_ITEM_EVDO_PILOT_SETS_V2_TYPE_UNKNOWN = 0, + QCDM_LOG_ITEM_EVDO_PILOT_SETS_V2_TYPE_ACTIVE = 1, + QCDM_LOG_ITEM_EVDO_PILOT_SETS_V2_TYPE_CANDIDATE = 2, + QCDM_LOG_ITEM_EVDO_PILOT_SETS_V2_TYPE_REMAINING = 3, +}; + +QcdmResult *qcdm_log_item_evdo_pilot_sets_v2_new (const char *buf, + size_t len, + int *out_error); + +qcdmbool qcdm_log_item_evdo_pilot_sets_v2_get_num (QcdmResult *result, + u_int32_t set_type, + u_int32_t *out_num); + +qcdmbool qcdm_log_item_evdo_pilot_sets_v2_get_pilot (QcdmResult *result, + u_int32_t set_type, + u_int32_t num, + u_int32_t *out_pilot_pn, + u_int32_t *out_pilot_energy, + int32_t *out_rssi_dbm); + +/**********************************************************************/ + +#endif /* LIBQCDM_LOGS_H */ |