aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Williams <dcbw@redhat.com>2013-02-08 09:11:32 -0600
committerDan Williams <dcbw@redhat.com>2013-04-18 10:23:50 -0500
commit14031246ce05b1a282cfa0ec398ed8856d77e482 (patch)
treee1858228870f31608be13298dde86e47258aecde
parent07ce8b51a00ae4a88ef8090b0339047e71393f8e (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.h59
-rw-r--r--libqcdm/src/log-items.c151
-rw-r--r--libqcdm/src/log-items.h32
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 */