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.
This commit is contained in:
@@ -16,6 +16,8 @@ libqcdm_la_SOURCES = \
|
||||
commands.h \
|
||||
errors.c \
|
||||
errors.h \
|
||||
logs.c \
|
||||
logs.h \
|
||||
result.c \
|
||||
result.h \
|
||||
result-private.h \
|
||||
|
||||
+17
-17
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
@@ -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 */
|
||||
Reference in New Issue
Block a user