1 /* Cell Monitor of Free Software for Calypso Phone */
3 /* (C) 2012 by Andreas Eversberg <jolly@eversberg.eu>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
31 #include <byteorder.h>
35 #include <abb/twl3025.h>
36 #include <rf/trf6151.h>
37 #include <calypso/clock.h>
38 #include <calypso/tpu.h>
39 #include <calypso/tsp.h>
40 #include <calypso/dsp.h>
41 #include <calypso/irq.h>
42 #include <calypso/misc.h>
43 #include <calypso/buzzer.h>
44 #include <comm/sercomm.h>
45 #include <comm/timer.h>
46 #include <fb/framebuffer.h>
47 #include <layer1/sync.h>
48 #include <layer1/async.h>
49 #include <layer1/l23_api.h>
51 enum key_codes key_code
= KEY_INV
;
53 enum key_codes key_pressed_code
;
54 unsigned long key_pressed_when
;
55 unsigned int key_pressed_delay
;
62 enum mode last_mode
; /* where to return after entering ARFCN */
64 static uint16_t arfcn
= 0;
68 uint8_t power
, max_power
;
73 int min
, max
, prev
, next
, freq_ul
, freq_dl
;
75 { 128, 251, 124, 512, 8242, 8692 }, /* GSM 850 */
76 { 955, 124, 885, 128, 8762, 9212 }, /* P,E,R GSM */
77 { 512, 885, 251, 955, 17102, 18052 }, /* DCS 1800 */
100 int pm_meas
[NUM_PM_UL
];
103 uint8_t pm_spectrum
[1024];
104 int pm_scale
= 1; /* scale measured power level */
106 #define TONE_JIFFIES 4
108 unsigned long tone_time
;
113 static void refresh_display(void)
120 fb_setbg(FB_COLOR_WHITE
);
121 if (mode
!= MODE_SPECTRUM
) {
122 fb_setfg(FB_COLOR_BLUE
);
123 fb_setfont(FB_FONT_HELVR08
);
125 fb_putstr("Osmocom Monitor Tool",-1);
127 fb_setfg(FB_COLOR_BLACK
);
128 fb_boxto(framebuffer
->width
-1,10);
130 fb_setfg(FB_COLOR_BLACK
);
131 fb_setfont(FB_FONT_C64
);
134 if (mode
== MODE_MAIN
|| mode
== MODE_ARFCN
) {
136 if (mode
== MODE_ARFCN
)
137 sprintf(text
, "ARFCN %s", input
);
138 else if (pcs
&& arfcn
>= PCS_MIN
&& arfcn
<= PCS_MAX
)
139 sprintf(text
, "ARFCN %dPCS", arfcn
);
140 else if (arfcn
>= DCS_MIN
&& arfcn
<= DCS_MAX
)
141 sprintf(text
, "ARFCN %dDCS", arfcn
);
143 sprintf(text
, "ARFCN %d", arfcn
);
144 fb_putstr(text
,framebuffer
->width
);
148 if (mode
== MODE_ARFCN
) {
149 fb_setfg(FB_COLOR_WHITE
);
150 fb_setbg(FB_COLOR_BLUE
);
151 fb_putstr(" ", framebuffer
->width
);
152 fb_setfg(FB_COLOR_BLACK
);
153 fb_setbg(FB_COLOR_WHITE
);
156 /* Frequency / power */
157 if (mode
== MODE_MAIN
) {
160 if (pcs
&& arfcn
>= PCS_MIN
&& arfcn
<= PCS_MAX
) {
169 f
+= ((arfcn
- band
->min
) & 1023) << 1;
172 sprintf(text
, "Freq. %d.%d", f
/ 10, f
% 10);
173 fb_putstr(text
,framebuffer
->width
);
176 sprintf(text
, "Power %d", ((max
) ? max_power
: power
) - 110);
177 fb_putstr(text
,framebuffer
->width
);
179 fb_setfont(FB_FONT_HELVR08
);
181 fb_putstr("max",framebuffer
->width
);
182 fb_setfont(FB_FONT_C64
);
184 fb_setbg(FB_COLOR_BLACK
);
186 fb_boxto(framebuffer
->width
* power
/ 64, 50);
188 fb_gotoxy(framebuffer
->width
* max_power
/ 64 ,45);
189 fb_boxto(framebuffer
->width
* max_power
/ 64, 50);
191 fb_setbg(FB_COLOR_WHITE
);
195 if (mode
== MODE_SPECTRUM
) {
200 if (pcs
&& arfcn
>= PCS_MIN
&& arfcn
<= PCS_MAX
)
201 sprintf(text
, "%4dP", arfcn
);
202 else if (arfcn
>= DCS_MIN
&& arfcn
<= DCS_MAX
)
203 sprintf(text
, "%4dD", arfcn
);
205 sprintf(text
, "%4d ", arfcn
);
206 sprintf(text
+ 5, " %d", pm_spectrum
[arfcn
& 1023] - 110);
207 fb_putstr(text
,framebuffer
->width
);
209 fb_setfont(FB_FONT_HELVR08
);
211 fb_putstr("max",framebuffer
->width
);
212 fb_setfont(FB_FONT_C64
);
215 fb_setfont(FB_FONT_HELVR08
);
217 sprintf(text
, "x%d", pm_scale
);
218 fb_putstr(text
,framebuffer
->width
);
219 fb_setfont(FB_FONT_C64
);
221 if (pcs
&& arfcn
>= PCS_MIN
&& arfcn
<= PCS_MAX
) {
228 for (i
= 0; i
< framebuffer
->width
- 1; i
++) {
229 p
= (arfcn
+ i
- (framebuffer
->width
>> 1)) & 1023;
230 if ((((p
- a
) & 1023) & 512))
232 if ((((e
- p
) & 1023) & 512))
234 p
= (pm_spectrum
[p
] * pm_scale
* 40 / 64);
237 fb_gotoxy(i
, 50 - p
);
240 i
= framebuffer
->width
>> 1;
249 fb_boxto(framebuffer
->width
-1,55);
251 if (mode
== MODE_ARFCN
)
252 sprintf(text
, "%s %s", (cursor
) ? "del " : "back",
253 (cursor
) ? "enter" : " ");
255 sprintf(text
, "%s %s", (pcs
) ? "PCS" : "DCS",
256 (uplink
) ? "UL" : "DL");
257 fb_putstr(text
,framebuffer
->width
);
258 fb_setfont(FB_FONT_HELVR08
);
260 sprintf(text
, "%d", tone
/ 25);
266 static void exit_arfcn(void)
272 static void enter_arfcn(enum key_codes code
)
275 if (mode
!= MODE_ARFCN
) {
278 input
[0] = code
- KEY_0
+ '0';
285 if (code
== KEY_LEFT_SB
) {
293 input
[cursor
] = '\0';
298 if (code
== KEY_RIGHT_SB
) {
301 struct band
*temp
= NULL
;
303 /* nothing entered */
307 for (i
= 0; i
< cursor
; i
++)
308 check
= (check
<< 3) + (check
<< 1) + input
[i
] - '0';
311 for (i
= 0; bands
[i
].max
; i
++) {
313 if (temp
->min
< temp
->max
) {
314 if (check
>= temp
->min
&& check
<= temp
->max
)
317 if (check
>= temp
->min
|| check
<= temp
->max
)
335 input
[cursor
] = code
- KEY_0
+ '0';
337 input
[cursor
] = '\0';
341 static int inc_dec_arfcn(int inc
)
345 /* select current band */
346 for (i
= 0; bands
[i
].max
; i
++) {
348 if (band
->min
< band
->max
) {
349 if (arfcn
>= band
->min
&& arfcn
<= band
->max
)
352 if (arfcn
>= band
->min
|| arfcn
<= band
->max
)
360 if (arfcn
== band
->max
)
362 else if (arfcn
== 1023)
367 if (arfcn
== band
->min
)
374 /* select next band */
375 for (i
= 0; bands
[i
].max
; i
++) {
377 if (band
->min
< band
->max
) {
378 if (arfcn
>= band
->min
&& arfcn
<= band
->max
)
381 if (arfcn
>= band
->min
|| arfcn
<= band
->max
)
393 static void toggle_dcs_pcs(void)
399 static void toggle_up_down(void)
405 static void toggle_spectrum(void)
407 if (mode
== MODE_MAIN
) {
408 mode
= MODE_SPECTRUM
;
410 } else if (mode
== MODE_SPECTRUM
) {
420 static void tone_inc_dec(int inc
)
423 if (tone
+ 25 <= 255)
433 static void hold_max(void)
440 static int inc_dec_spectrum(int inc
)
457 static void handle_key_code()
461 unsigned long elapsed
= jiffies
- key_pressed_when
;
462 if (elapsed
> key_pressed_delay
) {
463 key_pressed_when
= jiffies
;
464 key_pressed_delay
= 10;
465 /* only repeat these keys */
466 if (key_pressed_code
== KEY_LEFT
467 || key_pressed_code
== KEY_RIGHT
)
468 key_code
= key_pressed_code
;
472 if (key_code
== KEY_INV
)
475 /* do later, do not disturb tone */
490 if (mode
== MODE_MAIN
|| mode
== MODE_SPECTRUM
|| mode
== MODE_ARFCN
)
491 enter_arfcn(key_code
);
494 if (mode
== MODE_MAIN
)
496 else if (mode
== MODE_SPECTRUM
)
500 if (mode
== MODE_MAIN
)
502 else if (mode
== MODE_SPECTRUM
)
506 if (mode
== MODE_MAIN
|| mode
== MODE_SPECTRUM
)
510 if (mode
== MODE_MAIN
|| mode
== MODE_SPECTRUM
)
514 if (mode
== MODE_MAIN
|| mode
== MODE_SPECTRUM
)
516 else if (mode
== MODE_ARFCN
)
517 enter_arfcn(key_code
);
520 if (mode
== MODE_MAIN
|| mode
== MODE_SPECTRUM
)
522 else if (mode
== MODE_ARFCN
)
523 enter_arfcn(key_code
);
529 if (mode
== MODE_ARFCN
)
531 else if (mode
== MODE_SPECTRUM
)
535 if (mode
== MODE_MAIN
|| mode
== MODE_SPECTRUM
)
545 static void handle_tone(void)
547 unsigned long elapsed
= jiffies
- tone_time
;
550 if (!tone
|| mode
!= MODE_MAIN
)
552 /* wait depending on power level */
553 if (elapsed
< (uint8_t)(63-power
))
556 buzzer_note(NOTE(NOTE_C
, OCTAVE_5
));
562 if (elapsed
>= TONE_JIFFIES
) {
571 static void handle_pm(void)
573 /* start power measurement */
574 if (pm_mode
== PM_IDLE
&& (mode
== MODE_MAIN
|| mode
== MODE_SPECTRUM
)) {
575 struct msgb
*msg
= l1ctl_msgb_alloc(L1CTL_PM_REQ
);
576 struct l1ctl_pm_req
*pm
;
579 pm
= (struct l1ctl_pm_req
*) msgb_put(msg
, sizeof(*pm
));
581 if (mode
== MODE_MAIN
) {
583 if (pcs
&& arfcn
>= PCS_MIN
&& arfcn
<= PCS_MAX
)
590 if (mode
== MODE_SPECTRUM
) {
591 if (pcs
&& arfcn
>= PCS_MIN
&& arfcn
<= PCS_MAX
) {
592 a
= PCS_MIN
| ARFCN_PCS
;
593 e
= PCS_MAX
| ARFCN_PCS
;
598 pm_mode
= PM_RANGE_SENT
;
604 pm
->range
.band_arfcn_from
= htons(a
);
605 pm
->range
.band_arfcn_to
= htons(e
);
607 l1a_l23_rx(SC_DLCI_L1A_L23
, msg
);
612 if (pm_mode
== PM_RESULT
) {
614 if (pm_count
== pm_max
) {
620 for (i
= 0; i
< pm_count
; i
++) {
621 if (pm_meas
[i
] > sum
)
626 for (i
= 0; i
< pm_count
; i
++)
628 power
= sum
/ pm_count
;
630 if (power
> max_power
)
633 pm_max
= (uplink
) ? NUM_PM_UL
: NUM_PM_DL
;
640 if (pm_mode
== PM_RANGE_RESULT
) {
644 buzzer_note(NOTE(NOTE_C
, OCTAVE_5
));
652 const char *hr
= "======================================================================\n";
654 /* note: called from IRQ context */
655 static void l1a_l23_tx(struct msgb
*msg
)
657 struct l1ctl_hdr
*l1h
= (struct l1ctl_hdr
*) msg
->l1h
;
658 struct l1ctl_pm_conf
*pmr
;
660 switch (l1h
->msg_type
) {
662 if (pm_mode
== PM_SENT
) {
663 pmr
= (struct l1ctl_pm_conf
*) l1h
->data
;
664 pm_meas
[pm_count
] = pmr
->pm
[0];
668 if (pm_mode
== PM_RANGE_SENT
) {
669 for (pmr
= (struct l1ctl_pm_conf
*) l1h
->data
;
670 (uint8_t *) pmr
< msg
->tail
; pmr
++) {
671 if (!max
|| pm_spectrum
[ntohs(pmr
->band_arfcn
) & 1023] < pmr
->pm
[0])
672 pm_spectrum
[ntohs(pmr
->band_arfcn
) & 1023] = pmr
->pm
[0];
674 if ((l1h
->flags
& L1CTL_F_DONE
))
675 pm_mode
= PM_RANGE_RESULT
;
677 l1s
.tpu_offset_correction
+= 5000 / NUM_PM_UL
;
685 static void console_rx_cb(uint8_t dlci
, struct msgb
*msg
)
687 if (dlci
!= SC_DLCI_CONSOLE
) {
688 printf("Message for unknown DLCI %u\n", dlci
);
692 printf("Message on console DLCI: '%s'\n", msg
->data
);
696 static void l1a_l23_rx_cb(uint8_t dlci
, struct msgb
*msg
)
699 printf("l1a_l23_rx_cb (DLCI %d): ", dlci
);
700 for (i
= 0; i
< msg
->len
; i
++)
701 printf("%02x ", msg
->data
[i
]);
705 static void key_handler(enum key_codes code
, enum key_states state
)
707 if (state
!= PRESSED
) {
714 key_pressed_when
= jiffies
;
715 key_pressed_code
= code
;
716 key_pressed_delay
= 60;
726 puts("\n\nOSMOCOM Monitor Tool (revision " GIT_REVISION
")\n");
729 /* Dump device identification */
733 /* Dump clock config before PLL set */
737 keypad_set_handler(&key_handler
);
739 /* Dump clock config after PLL set */
743 sercomm_register_rx_cb(SC_DLCI_CONSOLE
, console_rx_cb
);
744 sercomm_register_rx_cb(SC_DLCI_L1A_L23
, l1a_l23_rx_cb
);
747 l1a_l23_tx_cb
= l1a_l23_tx
;
749 // display_unset_attr(DISP_ATTR_INVERT);
751 tpu_frame_irq_en(1, 1);
756 memset(pm_spectrum
, 0, sizeof(pm_spectrum
));
758 /* inc 0 to 1 and refresh */
763 osmo_timers_update();