diff options
author | Dan Williams <dcbw@redhat.com> | 2013-02-08 09:11:32 -0600 |
---|---|---|
committer | Dan Williams <dcbw@redhat.com> | 2013-04-18 10:23:50 -0500 |
commit | 14031246ce05b1a282cfa0ec398ed8856d77e482 (patch) | |
tree | e1858228870f31608be13298dde86e47258aecde | |
parent | 07ce8b51a00ae4a88ef8090b0339047e71393f8e (diff) |
qcdm: add support for EVDO Pilot Sets V2 log item
RE done experimentally with samples from a number of Verizon and
Sprint devices, and pilot energy bounds determined by correlating
the Novatel snapshot subsystem RSSI field to the pilot energy
at short intervals.
-rw-r--r-- | libqcdm/src/dm-log-items.h | 59 | ||||
-rw-r--r-- | libqcdm/src/log-items.c | 151 | ||||
-rw-r--r-- | libqcdm/src/log-items.h | 32 |
3 files changed, 242 insertions, 0 deletions
diff --git a/libqcdm/src/dm-log-items.h b/libqcdm/src/dm-log-items.h index 753d69d1..a10174c9 100644 --- a/libqcdm/src/dm-log-items.h +++ b/libqcdm/src/dm-log-items.h @@ -90,6 +90,65 @@ struct DMLogItemCdmaReversePowerControl { } __attribute__ ((packed)); typedef struct DMLogItemCdmaReversePowerControl DMLogItemCdmaReversePowerControl; +/* DM_LOG_ITEM_EVDO_PILOT_SETS_V2 */ +#define DM_LOG_ITEM_EVDO_PILOT_SETS_V2_GET_BAND_CLASS(c) ((c & 0xF000) >> 12) +#define DM_LOG_ITEM_EVDO_PILOT_SETS_V2_GET_CHANNEL(c) (c & 0xFFF) + +struct DMLogItemEvdoPilotSetsV2PilotActive { + u_int16_t pilot_pn; + u_int16_t energy; + u_int16_t unknown1; + u_int16_t mac_index; + u_int16_t window_center; +} __attribute__ ((packed)); +typedef struct DMLogItemEvdoPilotSetsV2PilotActive DMLogItemEvdoPilotSetsV2PilotActive; + +struct DMLogItemEvdoPilotSetsV2PilotCandidate { + u_int16_t pilot_pn; + u_int16_t energy; + u_int16_t channel; /* top 4 bits are band class, lower 12 are channel */ + u_int16_t unknown1; + u_int16_t window_center; +} __attribute__ ((packed)); +typedef struct DMLogItemEvdoPilotSetsV2PilotCandidate DMLogItemEvdoPilotSetsV2PilotCandidate; + +struct DMLogItemEvdoPilotSetsV2PilotNeighbor { + u_int16_t pilot_pn; + u_int16_t energy; + u_int16_t channel; /* top 4 bits are band class, lower 12 are channel */ + u_int16_t window_center; + u_int8_t unknown1; + u_int8_t age; +} __attribute__ ((packed)); +typedef struct DMLogItemEvdoPilotSetsV2PilotNeighbor DMLogItemEvdoPilotSetsV2PilotNeighbor; + +struct DMLogItemEvdoPilotSetsV2Pilot { + union { + struct DMLogItemEvdoPilotSetsV2PilotActive active; + struct DMLogItemEvdoPilotSetsV2PilotCandidate candidate; + struct DMLogItemEvdoPilotSetsV2PilotNeighbor neighbor; + } u; +} __attribute__ ((packed)); +typedef struct DMLogItemEvdoPilotSetsV2Pilot DMLogItemEvdoPilotSetsV2Pilot; + +struct DMLogItemEvdoPilotSetsV2 { + struct DMCmdLog cmd; + + u_int8_t pn_offset; + u_int8_t active_count; + u_int8_t active_window; + u_int16_t active_channel; /* top 4 bits are band class, lower 12 are channel */ + u_int8_t unknown1; + u_int8_t candidate_count; + u_int8_t candidate_window; + u_int8_t neighbor_count; + u_int8_t neighbor_window; + u_int8_t unknown2; + + struct DMLogItemEvdoPilotSetsV2Pilot sets[]; +} __attribute__ ((packed)); +typedef struct DMLogItemEvdoPilotSetsV2 DMLogItemEvdoPilotSetsV2; + /* DM_LOG_ITEM_WCDMA_TA_FINGER_INFO */ struct DMLogItemWcdmaTaFingerInfo { diff --git a/libqcdm/src/log-items.c b/libqcdm/src/log-items.c index 650fb775..de5302c7 100644 --- a/libqcdm/src/log-items.c +++ b/libqcdm/src/log-items.c @@ -24,6 +24,7 @@ #include "dm-commands.h" #include "dm-log-items.h" #include "result-private.h" +#include "commands-private.h" #include "utils.h" /**********************************************************************/ @@ -83,3 +84,153 @@ qcdm_get_log_item_code (const char *buf, size_t len) /**********************************************************************/ +#define ACTIVE_CHANNEL "active-channel" + +QcdmResult * +qcdm_log_item_evdo_pilot_sets_v2_result (const char *buf, size_t len, int *out_error) +{ + QcdmResult *result = NULL; + DMLogItemEvdoPilotSetsV2 *log = (DMLogItemEvdoPilotSetsV2 *) 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; + + result = qcdm_result_new (); + + qcdm_result_add_u32 (result, QCDM_LOG_ITEM_EVDO_PILOT_SETS_V2_PN_OFFSET, log->pn_offset); + qcdm_result_add_u32 (result, ACTIVE_CHANNEL, le16toh (log->active_channel)); + qcdm_result_add_u32 (result, QCDM_LOG_ITEM_EVDO_PILOT_SETS_V2_ACTIVE_SET_WINDOW, log->active_window); + qcdm_result_add_u32 (result, QCDM_LOG_ITEM_EVDO_PILOT_SETS_V2_CANDIDATE_SET_WINDOW, log->candidate_window); + qcdm_result_add_u32 (result, QCDM_LOG_ITEM_EVDO_PILOT_SETS_V2_NEIGHBOR_SET_WINDOW, log->neighbor_window); + + sets_len = log->active_count * sizeof (DMLogItemEvdoPilotSetsV2PilotActive); + if (sets_len > 0) { + qcdm_result_add_u8_array (result, + PILOT_SET_ACTIVE, + (const u_int8_t *) &log->sets[0], + sets_len); + } + + sets_len = log->candidate_count * sizeof (DMLogItemEvdoPilotSetsV2PilotCandidate); + if (sets_len > 0) { + qcdm_result_add_u8_array (result, + PILOT_SET_CANDIDATE, + (const u_int8_t *) &log->sets[log->active_count], + sets_len); + } + + sets_len = log->neighbor_count * sizeof (DMLogItemEvdoPilotSetsV2PilotNeighbor); + if (sets_len > 0) { + qcdm_result_add_u8_array (result, + PILOT_SET_NEIGHBOR, + (const u_int8_t *) &log->sets[log->active_count + log->candidate_count], + sets_len); + } + + return result; +} + +qcdmbool +qcdm_log_item_evdo_pilot_sets_v2_result_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 = pilot_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; + + /* we use Active here, but all the pilot type structs are the same size */ + *out_num = array_len / sizeof (DMLogItemEvdoPilotSetsV2PilotActive); + return TRUE; +} + +qcdmbool +qcdm_log_item_evdo_pilot_sets_result_get_pilot (QcdmResult *result, + u_int32_t set_type, + u_int32_t num, + u_int32_t *out_pilot_pn, + u_int32_t *out_energy, + float *out_db, + u_int32_t *out_band_class, + u_int32_t *out_channel, + u_int32_t *out_window_center) +{ + const char *set_name; + DMLogItemEvdoPilotSetsV2Pilot *set; + const u_int8_t *array = NULL; + size_t array_len = 0; + u_int32_t pilot_pn; + u_int32_t energy; + u_int32_t channel = 0; + u_int32_t window_center; + + qcdm_return_val_if_fail (result != NULL, FALSE); + + set_name = pilot_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); + + set = (DMLogItemEvdoPilotSetsV2Pilot *) &array[num * sizeof (DMLogItemEvdoPilotSetsV2Pilot)]; + if (set_type == QCDM_PILOT_SET_TYPE_ACTIVE) { + pilot_pn = le16toh (set[num].u.active.pilot_pn); + energy = le16toh (set[num].u.active.energy); + qcdm_result_get_u32 (result, ACTIVE_CHANNEL, &channel); + window_center = le16toh (set[num].u.active.window_center); + } else if (set_type == QCDM_PILOT_SET_TYPE_CANDIDATE) { + pilot_pn = le16toh (set[num].u.candidate.pilot_pn); + energy = le16toh (set[num].u.candidate.energy); + channel = le16toh (set[num].u.candidate.channel); + window_center = le16toh (set[num].u.candidate.window_center); + } else if (set_type == QCDM_PILOT_SET_TYPE_NEIGHBOR) { + pilot_pn = le16toh (set[num].u.neighbor.pilot_pn); + energy = le16toh (set[num].u.neighbor.energy); + channel = le16toh (set[num].u.neighbor.channel); + window_center = le16toh (set[num].u.neighbor.window_center); + } else + qcdm_assert_not_reached (); + + if (out_pilot_pn) + *out_pilot_pn = pilot_pn; + if (out_band_class) + *out_band_class = cdma_band_class_to_qcdm (DM_LOG_ITEM_EVDO_PILOT_SETS_V2_GET_BAND_CLASS (channel)); + if (out_channel) + *out_channel = DM_LOG_ITEM_EVDO_PILOT_SETS_V2_GET_CHANNEL (channel); + if (out_window_center) + *out_window_center = window_center; + + /* Log item pilot energy is in units from 0 (bad signal) to about 400 + * (excellent signal), derived by walking around and correlating active + * pilot energy from this log item to the RSSI from continuous Novatel + * Snapshot requests. + */ +#define MAX_ENERGY 400 +#define MAX_ECIO 32.0 + + if (energy > MAX_ENERGY) + energy = MAX_ENERGY; + if (out_energy) + *out_energy = energy; + + if (out_db) + *out_db = (MAX_ECIO - (((float) energy * MAX_ECIO) / (float) MAX_ENERGY)); + + return TRUE; +} + +/**********************************************************************/ + diff --git a/libqcdm/src/log-items.h b/libqcdm/src/log-items.h index 2cae59bf..04c4be80 100644 --- a/libqcdm/src/log-items.h +++ b/libqcdm/src/log-items.h @@ -35,4 +35,36 @@ u_int16_t qcdm_get_log_item_code (const char *buf, size_t len); /**********************************************************************/ +enum { + QCDM_LOG_ITEM_PILOT_SET_TYPE_UNKNOWN = 0, + QCDM_LOG_ITEM_PILOT_SET_TYPE_ACTIVE = 1, + QCDM_LOG_ITEM_PILOT_SET_TYPE_CANDIDATE = 2, + QCDM_LOG_ITEM_PILOT_SET_TYPE_NEIGHBOR = 3, +}; + +#define QCDM_LOG_ITEM_EVDO_PILOT_SETS_V2_PN_OFFSET "pn-offset" +#define QCDM_LOG_ITEM_EVDO_PILOT_SETS_V2_ACTIVE_SET_WINDOW "active-set-window" +#define QCDM_LOG_ITEM_EVDO_PILOT_SETS_V2_CANDIDATE_SET_WINDOW "candidate-set-window" +#define QCDM_LOG_ITEM_EVDO_PILOT_SETS_V2_NEIGHBOR_SET_WINDOW "neighbor-set-window" + +QcdmResult *qcdm_log_item_evdo_pilot_sets_v2_result (const char *buf, + size_t len, + int *out_error); + +qcdmbool qcdm_log_item_evdo_pilot_sets_v2_result_get_num (QcdmResult *result, + u_int32_t set_type, + u_int32_t *out_num); + +qcdmbool qcdm_log_item_evdo_pilot_sets_result_get_pilot (QcdmResult *result, + u_int32_t set_type, + u_int32_t num, + u_int32_t *out_pilot_pn, + u_int32_t *out_energy, + float *out_db, + u_int32_t *out_band_class, + u_int32_t *out_channel, + u_int32_t *out_window_center); + +/**********************************************************************/ + #endif /* LIBQCDM_LOG_ITEMS_H */ |