aboutsummaryrefslogtreecommitdiffstats
path: root/src/utils/meas_vis.c
diff options
context:
space:
mode:
authorNeels Hofmeyr <neels@hofmeyr.de>2017-07-04 23:08:44 +0200
committerNeels Hofmeyr <neels@hofmeyr.de>2017-08-27 03:52:43 +0200
commit218e4b4aa0fc6de842ff820dec8e97d1f083268a (patch)
tree268a6e509270b1c80a36dd1a526da41a9b01a8e0 /src/utils/meas_vis.c
parent5ea6bfce56d6ae7be6d85e05b5e4eaebc94d1005 (diff)
move openbsc/* to repos root
This is the first step in creating this repository from the legacy openbsc.git. Like all other Osmocom repositories, keep the autoconf and automake files in the repository root. openbsc.git has been the sole exception, which ends now. Change-Id: I9c6f2a448d9cb1cc088cf1cf6918b69d7e69b4e7
Diffstat (limited to 'src/utils/meas_vis.c')
-rw-r--r--src/utils/meas_vis.c310
1 files changed, 310 insertions, 0 deletions
diff --git a/src/utils/meas_vis.c b/src/utils/meas_vis.c
new file mode 100644
index 000000000..77194ded4
--- /dev/null
+++ b/src/utils/meas_vis.c
@@ -0,0 +1,310 @@
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <netinet/in.h>
+
+#include <cdk/cdk.h>
+
+#include <osmocom/core/socket.h>
+#include <osmocom/core/utils.h>
+#include <osmocom/core/msgb.h>
+#include <osmocom/core/select.h>
+#include <osmocom/core/talloc.h>
+
+#include <osmocom/gsm/gsm_utils.h>
+
+#include <openbsc/meas_feed.h>
+
+struct ms_state_uni {
+ CDKSLIDER *cdk;
+ CDKLABEL *cdk_label;
+
+ time_t last_update;
+ char label[32];
+ char *_lbl[1];
+};
+
+
+struct ms_state {
+ struct llist_head list;
+
+ char name[31+1];
+ char imsi[15+1];
+ struct gsm_meas_rep mr;
+
+ struct ms_state_uni ul;
+ struct ms_state_uni dl;
+};
+
+struct state {
+ struct osmo_fd udp_ofd;
+ struct llist_head ms_list;
+
+ CDKSCREEN *cdkscreen;
+ WINDOW *curses_win;
+
+ CDKLABEL *cdk_title;
+ char *title;
+
+ CDKLABEL *cdk_header;
+ char header[256];
+};
+
+static struct state g_st;
+
+struct ms_state *find_ms(const char *imsi)
+{
+ struct ms_state *ms;
+
+ llist_for_each_entry(ms, &g_st.ms_list, list) {
+ if (!strcmp(ms->imsi, imsi))
+ return ms;
+ }
+ return NULL;
+}
+
+static struct ms_state *find_alloc_ms(const char *imsi)
+{
+ struct ms_state *ms;
+
+ ms = find_ms(imsi);
+ if (!ms) {
+ ms = talloc_zero(NULL, struct ms_state);
+ osmo_strlcpy(ms->imsi, imsi, sizeof(ms->imsi));
+ ms->ul._lbl[0] = ms->ul.label;
+ ms->dl._lbl[0] = ms->dl.label;
+ llist_add_tail(&ms->list, &g_st.ms_list);
+ }
+
+ return ms;
+}
+
+static int handle_meas(struct msgb *msg)
+{
+ struct meas_feed_meas *mfm = (struct meas_feed_meas *) msgb_data(msg);
+ struct ms_state *ms = find_alloc_ms(mfm->imsi);
+ time_t now = time(NULL);
+
+ osmo_strlcpy(ms->name, mfm->name, sizeof(ms->name));
+ memcpy(&ms->mr, &mfm->mr, sizeof(ms->mr));
+ ms->ul.last_update = now;
+ if (ms->mr.flags & MEAS_REP_F_DL_VALID)
+ ms->dl.last_update = now;
+
+ /* move to head of list */
+ llist_del(&ms->list);
+ llist_add(&ms->list, &g_st.ms_list);
+
+ return 0;
+}
+
+static int handle_msg(struct msgb *msg)
+{
+ struct meas_feed_hdr *mfh = (struct meas_feed_hdr *) msgb_data(msg);
+
+ if (mfh->version != MEAS_FEED_VERSION)
+ return -EINVAL;
+
+ switch (mfh->msg_type) {
+ case MEAS_FEED_MEAS:
+ handle_meas(msg);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int udp_fd_cb(struct osmo_fd *ofd, unsigned int what)
+{
+ int rc;
+
+ if (what & BSC_FD_READ) {
+ struct msgb *msg = msgb_alloc(1024, "UDP Rx");
+
+ rc = read(ofd->fd, msgb_data(msg), msgb_tailroom(msg));
+ if (rc < 0)
+ return rc;
+ msgb_put(msg, rc);
+ handle_msg(msg);
+ msgb_free(msg);
+ }
+
+ return 0;
+}
+
+
+static void destroy_dir(struct ms_state_uni *uni)
+{
+ if (uni->cdk) {
+ destroyCDKSlider(uni->cdk);
+ uni->cdk = NULL;
+ }
+ if (uni->cdk_label) {
+ destroyCDKLabel(uni->cdk_label);
+ uni->cdk_label = NULL;
+ }
+}
+
+#define DIR_UL 0
+#define DIR_DL 1
+static const char *dir_str[2] = {
+ [DIR_UL] = "UL",
+ [DIR_DL] = "DL",
+};
+
+static int colpair_by_qual(uint8_t rx_qual)
+{
+ if (rx_qual == 0)
+ return 24;
+ else if (rx_qual <= 4)
+ return 32;
+ else
+ return 16;
+}
+
+static int colpair_by_lev(int rx_lev)
+{
+ if (rx_lev < -95)
+ return 16;
+ else if (rx_lev < -80)
+ return 32;
+ else
+ return 24;
+}
+
+
+void write_uni(struct ms_state *ms, struct ms_state_uni *msu,
+ struct gsm_rx_lev_qual *lq, int dir, int row)
+{
+
+ char label[128];
+ time_t now = time(NULL);
+ int qual_col = colpair_by_qual(lq->rx_qual);
+ int lev_col = colpair_by_lev(rxlev2dbm(lq->rx_lev));
+ int color, pwr;
+
+ if (dir == DIR_UL) {
+ pwr = ms->mr.ms_l1.pwr;
+ } else {
+ pwr = ms->mr.bs_power;
+ }
+
+ color = A_REVERSE | COLOR_PAIR(lev_col) | ' ';
+ snprintf(label, sizeof(label), "%s %s ", ms->imsi, dir_str[dir]);
+ msu->cdk = newCDKSlider(g_st.cdkscreen, 0, row, NULL, label, color,
+ COLS-40, rxlev2dbm(lq->rx_lev), -110, -47,
+ 1, 2, FALSE, FALSE);
+ //IsVisibleObj(ms->ul.cdk) = FALSE;
+ snprintf(msu->label, sizeof(msu->label), "</%d>%1d<!%d> %3d %2u %2d %4u",
+ qual_col, lq->rx_qual, qual_col, pwr,
+ ms->mr.ms_l1.ta, ms->mr.ms_timing_offset,
+ now - msu->last_update);
+ msu->cdk_label = newCDKLabel(g_st.cdkscreen, RIGHT, row,
+ msu->_lbl, 1, FALSE, FALSE);
+}
+
+static void update_sliders(void)
+{
+ int num_vis_sliders = 0;
+ struct ms_state *ms;
+#define HEADER_LINES 2
+
+ /* remove all sliders */
+ llist_for_each_entry(ms, &g_st.ms_list, list) {
+ destroy_dir(&ms->ul);
+ destroy_dir(&ms->dl);
+
+ }
+
+ llist_for_each_entry(ms, &g_st.ms_list, list) {
+ struct gsm_rx_lev_qual *lq;
+ unsigned int row = HEADER_LINES + num_vis_sliders*3;
+
+ if (ms->mr.flags & MEAS_REP_F_UL_DTX)
+ lq = &ms->mr.ul.sub;
+ else
+ lq = &ms->mr.ul.full;
+ write_uni(ms, &ms->ul, lq, DIR_UL, row);
+
+ if (ms->mr.flags & MEAS_REP_F_DL_DTX)
+ lq = &ms->mr.dl.sub;
+ else
+ lq = &ms->mr.dl.full;
+ write_uni(ms, &ms->dl, lq, DIR_DL, row+1);
+
+ num_vis_sliders++;
+ if (num_vis_sliders >= LINES/3)
+ break;
+ }
+
+ refreshCDKScreen(g_st.cdkscreen);
+
+}
+
+const struct value_string col_strs[] = {
+ { COLOR_WHITE, "white" },
+ { COLOR_RED, "red" },
+ { COLOR_GREEN, "green" },
+ { COLOR_YELLOW, "yellow" },
+ { COLOR_BLUE, "blue" },
+ { COLOR_MAGENTA,"magenta" },
+ { COLOR_CYAN, "cyan" },
+ { COLOR_BLACK, "black" },
+ { 0, NULL }
+};
+
+int main(int argc, char **argv)
+{
+ int rc;
+ char *header[1];
+ char *title[1];
+
+ msgb_talloc_ctx_init(NULL, 0);
+
+ printf("sizeof(gsm_meas_rep)=%u\n", sizeof(struct gsm_meas_rep));
+ printf("sizeof(meas_feed_meas)=%u\n", sizeof(struct meas_feed_meas));
+
+ INIT_LLIST_HEAD(&g_st.ms_list);
+ g_st.curses_win = initscr();
+ g_st.cdkscreen = initCDKScreen(g_st.curses_win);
+ initCDKColor();
+
+ g_st.title = "OpenBSC link quality monitor";
+ title[0] = g_st.title;
+ g_st.cdk_title = newCDKLabel(g_st.cdkscreen, CENTER, 0, title, 1, FALSE, FALSE);
+
+ snprintf(g_st.header, sizeof(g_st.header), "Q Pwr TA TO Time");
+ header[0] = g_st.header;
+ g_st.cdk_header = newCDKLabel(g_st.cdkscreen, RIGHT, 1, header, 1, FALSE, FALSE);
+
+#if 0
+ int i;
+ for (i = 0; i < 64; i++) {
+ short f, b;
+ pair_content(i, &f, &b);
+ attron(COLOR_PAIR(i));
+ printw("%u: %u (%s) ", i, f, get_value_string(col_strs, f));
+ printw("%u (%s)\n\r", b, get_value_string(col_strs, b));
+ }
+ refresh();
+ getch();
+ exit(0);
+#endif
+
+ g_st.udp_ofd.cb = udp_fd_cb;
+ rc = osmo_sock_init_ofd(&g_st.udp_ofd, AF_INET, SOCK_DGRAM, IPPROTO_UDP, NULL, 8888, OSMO_SOCK_F_BIND);
+ if (rc < 0)
+ exit(1);
+
+ while (1) {
+ osmo_select_main(0);
+ update_sliders();
+ };
+
+ exit(0);
+}