blob: aea12bf9b342f4c4173bb093746317d501cf5763 [file] [log] [blame]
Harald Welteb4771a62012-11-11 10:58:51 +01001#include <string.h>
2#include <errno.h>
3#include <unistd.h>
4#include <stdlib.h>
5#include <stdio.h>
6
7#include <netinet/in.h>
8
9#include <cdk/cdk.h>
10
11#include <osmocom/core/socket.h>
12#include <osmocom/core/utils.h>
13#include <osmocom/core/msgb.h>
14#include <osmocom/core/select.h>
15#include <osmocom/core/talloc.h>
Keith85fe6102020-03-27 19:43:34 -050016#include <osmocom/core/logging.h>
17#include <osmocom/core/application.h>
Harald Welteb4771a62012-11-11 10:58:51 +010018
19#include <osmocom/gsm/gsm_utils.h>
20
Neels Hofmeyrc0164792017-09-04 15:15:32 +020021#include <osmocom/bsc/meas_feed.h>
Harald Welteb4771a62012-11-11 10:58:51 +010022
23struct ms_state_uni {
24 CDKSLIDER *cdk;
25 CDKLABEL *cdk_label;
26
27 time_t last_update;
28 char label[32];
29 char *_lbl[1];
30};
31
32
33struct ms_state {
34 struct llist_head list;
35
36 char name[31+1];
37 char imsi[15+1];
38 struct gsm_meas_rep mr;
39
40 struct ms_state_uni ul;
41 struct ms_state_uni dl;
42};
43
Harald Welteb4771a62012-11-11 10:58:51 +010044struct state {
45 struct osmo_fd udp_ofd;
46 struct llist_head ms_list;
47
48 CDKSCREEN *cdkscreen;
49 WINDOW *curses_win;
Harald Welte61c91562012-11-11 12:57:05 +010050
51 CDKLABEL *cdk_title;
52 char *title;
53
54 CDKLABEL *cdk_header;
55 char header[256];
Harald Welteb4771a62012-11-11 10:58:51 +010056};
57
58static struct state g_st;
59
60struct ms_state *find_ms(const char *imsi)
61{
62 struct ms_state *ms;
63
64 llist_for_each_entry(ms, &g_st.ms_list, list) {
65 if (!strcmp(ms->imsi, imsi))
66 return ms;
67 }
68 return NULL;
69}
70
71static struct ms_state *find_alloc_ms(const char *imsi)
72{
73 struct ms_state *ms;
74
75 ms = find_ms(imsi);
76 if (!ms) {
77 ms = talloc_zero(NULL, struct ms_state);
Neels Hofmeyr93bafb62017-01-13 03:12:08 +010078 osmo_strlcpy(ms->imsi, imsi, sizeof(ms->imsi));
Harald Welteb4771a62012-11-11 10:58:51 +010079 ms->ul._lbl[0] = ms->ul.label;
80 ms->dl._lbl[0] = ms->dl.label;
81 llist_add_tail(&ms->list, &g_st.ms_list);
82 }
83
84 return ms;
85}
86
87static int handle_meas(struct msgb *msg)
88{
89 struct meas_feed_meas *mfm = (struct meas_feed_meas *) msgb_data(msg);
90 struct ms_state *ms = find_alloc_ms(mfm->imsi);
91 time_t now = time(NULL);
92
Neels Hofmeyr93bafb62017-01-13 03:12:08 +010093 osmo_strlcpy(ms->name, mfm->name, sizeof(ms->name));
Harald Welteb4771a62012-11-11 10:58:51 +010094 memcpy(&ms->mr, &mfm->mr, sizeof(ms->mr));
95 ms->ul.last_update = now;
96 if (ms->mr.flags & MEAS_REP_F_DL_VALID)
97 ms->dl.last_update = now;
98
99 /* move to head of list */
100 llist_del(&ms->list);
101 llist_add(&ms->list, &g_st.ms_list);
102
103 return 0;
104}
105
106static int handle_msg(struct msgb *msg)
107{
108 struct meas_feed_hdr *mfh = (struct meas_feed_hdr *) msgb_data(msg);
109
110 if (mfh->version != MEAS_FEED_VERSION)
111 return -EINVAL;
112
113 switch (mfh->msg_type) {
114 case MEAS_FEED_MEAS:
115 handle_meas(msg);
116 break;
117 default:
118 break;
119 }
Martin Hauke4316cb22015-11-05 21:02:47 +0100120
121 return 0;
Harald Welteb4771a62012-11-11 10:58:51 +0100122}
123
124static int udp_fd_cb(struct osmo_fd *ofd, unsigned int what)
125{
126 int rc;
127
128 if (what & BSC_FD_READ) {
129 struct msgb *msg = msgb_alloc(1024, "UDP Rx");
130
131 rc = read(ofd->fd, msgb_data(msg), msgb_tailroom(msg));
132 if (rc < 0)
133 return rc;
134 msgb_put(msg, rc);
135 handle_msg(msg);
136 msgb_free(msg);
137 }
138
139 return 0;
140}
141
142
143static void destroy_dir(struct ms_state_uni *uni)
144{
145 if (uni->cdk) {
146 destroyCDKSlider(uni->cdk);
147 uni->cdk = NULL;
148 }
149 if (uni->cdk_label) {
150 destroyCDKLabel(uni->cdk_label);
151 uni->cdk_label = NULL;
152 }
153}
154
155#define DIR_UL 0
156#define DIR_DL 1
157static const char *dir_str[2] = {
158 [DIR_UL] = "UL",
159 [DIR_DL] = "DL",
160};
161
Harald Welte98ba6352012-11-11 12:33:30 +0100162static int colpair_by_qual(uint8_t rx_qual)
163{
164 if (rx_qual == 0)
165 return 24;
166 else if (rx_qual <= 4)
167 return 32;
168 else
169 return 16;
170}
171
172static int colpair_by_lev(int rx_lev)
173{
174 if (rx_lev < -95)
175 return 16;
176 else if (rx_lev < -80)
177 return 32;
178 else
179 return 24;
180}
181
182
Harald Welteb4771a62012-11-11 10:58:51 +0100183void write_uni(struct ms_state *ms, struct ms_state_uni *msu,
184 struct gsm_rx_lev_qual *lq, int dir, int row)
185{
186
187 char label[128];
188 time_t now = time(NULL);
Harald Welte98ba6352012-11-11 12:33:30 +0100189 int qual_col = colpair_by_qual(lq->rx_qual);
190 int lev_col = colpair_by_lev(rxlev2dbm(lq->rx_lev));
Harald Welteb4771a62012-11-11 10:58:51 +0100191 int color, pwr;
192
193 if (dir == DIR_UL) {
Harald Welteb4771a62012-11-11 10:58:51 +0100194 pwr = ms->mr.ms_l1.pwr;
195 } else {
Harald Welteb4771a62012-11-11 10:58:51 +0100196 pwr = ms->mr.bs_power;
197 }
198
Harald Welte98ba6352012-11-11 12:33:30 +0100199 color = A_REVERSE | COLOR_PAIR(lev_col) | ' ';
Harald Welteb4771a62012-11-11 10:58:51 +0100200 snprintf(label, sizeof(label), "%s %s ", ms->imsi, dir_str[dir]);
201 msu->cdk = newCDKSlider(g_st.cdkscreen, 0, row, NULL, label, color,
Harald Welte61c91562012-11-11 12:57:05 +0100202 COLS-40, rxlev2dbm(lq->rx_lev), -110, -47,
Harald Welteb4771a62012-11-11 10:58:51 +0100203 1, 2, FALSE, FALSE);
204 //IsVisibleObj(ms->ul.cdk) = FALSE;
Max11e4e412017-04-20 13:07:58 +0200205 snprintf(msu->label, sizeof(msu->label), "</%d>%1d<!%d> %3d %2u %2d %4u",
Harald Welte61c91562012-11-11 12:57:05 +0100206 qual_col, lq->rx_qual, qual_col, pwr,
207 ms->mr.ms_l1.ta, ms->mr.ms_timing_offset,
208 now - msu->last_update);
Harald Welteb4771a62012-11-11 10:58:51 +0100209 msu->cdk_label = newCDKLabel(g_st.cdkscreen, RIGHT, row,
210 msu->_lbl, 1, FALSE, FALSE);
211}
212
213static void update_sliders(void)
214{
215 int num_vis_sliders = 0;
216 struct ms_state *ms;
Harald Welte61c91562012-11-11 12:57:05 +0100217#define HEADER_LINES 2
Harald Welteb4771a62012-11-11 10:58:51 +0100218
219 /* remove all sliders */
220 llist_for_each_entry(ms, &g_st.ms_list, list) {
221 destroy_dir(&ms->ul);
222 destroy_dir(&ms->dl);
223
224 }
225
226 llist_for_each_entry(ms, &g_st.ms_list, list) {
227 struct gsm_rx_lev_qual *lq;
Harald Welte61c91562012-11-11 12:57:05 +0100228 unsigned int row = HEADER_LINES + num_vis_sliders*3;
Harald Welteb4771a62012-11-11 10:58:51 +0100229
230 if (ms->mr.flags & MEAS_REP_F_UL_DTX)
231 lq = &ms->mr.ul.sub;
232 else
233 lq = &ms->mr.ul.full;
234 write_uni(ms, &ms->ul, lq, DIR_UL, row);
235
236 if (ms->mr.flags & MEAS_REP_F_DL_DTX)
237 lq = &ms->mr.dl.sub;
238 else
239 lq = &ms->mr.dl.full;
240 write_uni(ms, &ms->dl, lq, DIR_DL, row+1);
241
242 num_vis_sliders++;
243 if (num_vis_sliders >= LINES/3)
244 break;
245 }
246
247 refreshCDKScreen(g_st.cdkscreen);
248
249}
250
Harald Welte98ba6352012-11-11 12:33:30 +0100251const struct value_string col_strs[] = {
252 { COLOR_WHITE, "white" },
253 { COLOR_RED, "red" },
254 { COLOR_GREEN, "green" },
255 { COLOR_YELLOW, "yellow" },
256 { COLOR_BLUE, "blue" },
257 { COLOR_MAGENTA,"magenta" },
258 { COLOR_CYAN, "cyan" },
259 { COLOR_BLACK, "black" },
260 { 0, NULL }
261};
262
Keith85fe6102020-03-27 19:43:34 -0500263/* default categories */
264static struct log_info_cat default_categories[] = {
265};
266
267static const struct log_info meas_vis_log_info = {
268 .cat = default_categories,
269 .num_cat = ARRAY_SIZE(default_categories),
270};
271
Harald Welteb4771a62012-11-11 10:58:51 +0100272int main(int argc, char **argv)
273{
274 int rc;
Harald Welte61c91562012-11-11 12:57:05 +0100275 char *header[1];
276 char *title[1];
Keith85fe6102020-03-27 19:43:34 -0500277 struct log_target *stderr_target;
278
279 void *tall_ctx = talloc_named_const(NULL, 0, "meas_vis");
280 osmo_init_logging2(tall_ctx, &meas_vis_log_info);
Harald Welteb4771a62012-11-11 10:58:51 +0100281
Neels Hofmeyr4c2d4ab2016-09-16 02:31:17 +0200282 msgb_talloc_ctx_init(NULL, 0);
283
Harald Welteb4771a62012-11-11 10:58:51 +0100284 printf("sizeof(gsm_meas_rep)=%u\n", sizeof(struct gsm_meas_rep));
285 printf("sizeof(meas_feed_meas)=%u\n", sizeof(struct meas_feed_meas));
286
287 INIT_LLIST_HEAD(&g_st.ms_list);
288 g_st.curses_win = initscr();
289 g_st.cdkscreen = initCDKScreen(g_st.curses_win);
290 initCDKColor();
291
Daniel Willmann2dcdf442019-04-15 16:50:46 +0200292 g_st.title = "OsmoBSC link quality monitor";
Harald Welte61c91562012-11-11 12:57:05 +0100293 title[0] = g_st.title;
294 g_st.cdk_title = newCDKLabel(g_st.cdkscreen, CENTER, 0, title, 1, FALSE, FALSE);
295
296 snprintf(g_st.header, sizeof(g_st.header), "Q Pwr TA TO Time");
297 header[0] = g_st.header;
298 g_st.cdk_header = newCDKLabel(g_st.cdkscreen, RIGHT, 1, header, 1, FALSE, FALSE);
299
Harald Welte98ba6352012-11-11 12:33:30 +0100300#if 0
301 int i;
302 for (i = 0; i < 64; i++) {
303 short f, b;
304 pair_content(i, &f, &b);
305 attron(COLOR_PAIR(i));
306 printw("%u: %u (%s) ", i, f, get_value_string(col_strs, f));
307 printw("%u (%s)\n\r", b, get_value_string(col_strs, b));
308 }
309 refresh();
310 getch();
311 exit(0);
312#endif
313
Harald Welteb4771a62012-11-11 10:58:51 +0100314 g_st.udp_ofd.cb = udp_fd_cb;
315 rc = osmo_sock_init_ofd(&g_st.udp_ofd, AF_INET, SOCK_DGRAM, IPPROTO_UDP, NULL, 8888, OSMO_SOCK_F_BIND);
316 if (rc < 0)
317 exit(1);
318
319 while (1) {
320 osmo_select_main(0);
321 update_sliders();
322 };
323
324 exit(0);
325}