VIRT-PHY: Properly destroy l1_model_ms after disconnect
[osmocom-bb.git] / src / host / virt_phy / src / virt_prim_pm.c
blob46370138fffe79bb1a645a4f803d97f5586516cc
2 /* (C) 2010 by Dieter Spaar <spaar@mirider.augusta.de>
3 * (C) 2010,2017 by Harald Welte <laforge@gnumonks.org>
4 * (C) 2016 by Sebastian Stumpf <sebastian.stumpf87@googlemail.com>
6 * All Rights Reserved
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 #include <stdint.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include <stdlib.h>
29 #include <osmocom/gsm/gsm_utils.h>
30 #include <osmocom/gsm/protocol/gsm_08_58.h>
31 #include <osmocom/core/msgb.h>
32 #include <virtphy/l1ctl_sap.h>
33 #include <virtphy/virt_l1_sched.h>
34 #include <osmocom/core/gsmtap.h>
35 #include <virtphy/logging.h>
36 #include <l1ctl_proto.h>
38 /**
39 * @brief Change the signal strength for a given arfcn.
41 * Should be called if a msg is received on the virtual layer. The configured signal level reduction is applied.
43 * @param [in] arfcn to change sig str for.
44 * @param [in] sig_lev the measured signal level value.
46 uint16_t prim_pm_set_sig_strength(struct l1_model_ms *ms, uint16_t arfcn, int16_t sig_lev)
48 struct l1_state_ms *l1s = &ms->state;
50 if (l1s->pm.timeout_s > 0 || l1s->pm.timeout_us > 0) {
51 osmo_timer_schedule(&l1s->pm.meas.arfcn_sig_lev_timers[arfcn],
52 l1s->pm.timeout_s, l1s->pm.timeout_us);
54 l1s->pm.meas.arfcn_sig_lev_dbm[arfcn] = sig_lev - l1s->pm.meas.arfcn_sig_lev_red_dbm[arfcn];
55 DEBUGPMS(DL1C, ms, "Power measurement set for arfcn %u. Set signal level to %d (== rxlev: %u).\n",
56 arfcn, l1s->pm.meas.arfcn_sig_lev_dbm[arfcn],
57 dbm2rxlev(l1s->pm.meas.arfcn_sig_lev_dbm[arfcn]));
58 return l1s->pm.meas.arfcn_sig_lev_dbm[arfcn];
61 void prim_pm_timer_cb(void *data)
63 /* reset the signal level to bad value if no messages have been
64 * received from that rfcn for a given time */
65 DEBUGP(DL1C, "Timeout occurred for arfcn, signal level reset to worst value.\n");
66 *((int16_t*)data) = MIN_SIG_LEV_DBM;
69 /**
70 * @brief Handler for received L1CTL_PM_REQ from L23.
72 * -- power measurement request --
74 * @param [in] msg the received message.
76 * Process power measurement for a given range of arfcns to calculate
77 * signal power and connection quality.
79 * Note: This should only be called after a certain time so some
80 * messages have already been received.
82 void l1ctl_rx_pm_req(struct l1_model_ms *ms, struct msgb *msg)
84 struct l1_state_ms *l1s = &ms->state;
85 struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
86 struct l1ctl_pm_req *pm_req = (struct l1ctl_pm_req *) l1h->data;
87 struct msgb *resp_msg = l1ctl_msgb_alloc(L1CTL_PM_CONF);
88 uint16_t arfcn_next;
90 /* convert to host order */
91 pm_req->range.band_arfcn_from = ntohs(pm_req->range.band_arfcn_from);
92 pm_req->range.band_arfcn_to = ntohs(pm_req->range.band_arfcn_to);
94 LOGPMS(DL1C, LOGL_INFO, ms, "Rx L1CTL_PM_REQ TYPE=%u, FROM=%d, TO=%d\n",
95 pm_req->type, pm_req->range.band_arfcn_from, pm_req->range.band_arfcn_to);
97 for (arfcn_next = pm_req->range.band_arfcn_from;
98 arfcn_next <= pm_req->range.band_arfcn_to; ++arfcn_next) {
99 struct l1ctl_pm_conf *pm_conf = (struct l1ctl_pm_conf *) msgb_put(resp_msg, sizeof(*pm_conf));
100 pm_conf->band_arfcn = htons(arfcn_next);
101 /* set min and max to the value calculated for that
102 * arfcn (IGNORE UPLINKK AND PCS AND OTHER FLAGS) */
103 pm_conf->pm[0] = dbm2rxlev(l1s->pm.meas.arfcn_sig_lev_dbm[arfcn_next & ARFCN_NO_FLAGS_MASK]);
104 pm_conf->pm[1] = dbm2rxlev(l1s->pm.meas.arfcn_sig_lev_dbm[arfcn_next & ARFCN_NO_FLAGS_MASK]);
105 if (arfcn_next == pm_req->range.band_arfcn_to) {
106 struct l1ctl_hdr *resp_l1h = msgb_l1(resp_msg);
107 resp_l1h->flags |= L1CTL_F_DONE;
109 /* no more space to hold mor pm info in msgb, flush to l23 */
110 if (msgb_tailroom(resp_msg) < sizeof(*pm_conf)) {
111 LOGPMS(DL1C, LOGL_INFO, ms, "Tx L1CTL_PM_CONF\n");
112 l1ctl_sap_tx_to_l23_inst(ms, resp_msg);
113 resp_msg = l1ctl_msgb_alloc(L1CTL_PM_CONF);
116 /* transmit the remaining part of pm response to l23 */
117 if (resp_msg) {
118 LOGPMS(DL1C, LOGL_INFO, ms, "Tx L1CTL_PM_CONF\n");
119 l1ctl_sap_tx_to_l23_inst(ms, resp_msg);
124 * @brief Initialize virtual prim pm.
126 * @param [in] model the l1 model instance
128 void prim_pm_init(struct l1_model_ms *model)
130 struct l1_state_ms *l1s = &model->state;
131 int i;
133 /* init the signal level of all arfcns with the lowest value possible */
134 memset(l1s->pm.meas.arfcn_sig_lev_dbm, MIN_SIG_LEV_DBM, sizeof (int16_t) * 1024);
135 /* init timers */
136 for (i = 0; i < 1024; ++i) {
137 l1s->pm.meas.arfcn_sig_lev_timers[i].cb = prim_pm_timer_cb;
138 l1s->pm.meas.arfcn_sig_lev_timers[i].data = &l1s->pm.meas.arfcn_sig_lev_dbm[i];
142 void prim_pm_exit(struct l1_model_ms *model)
144 struct l1_state_ms *l1s = &model->state;
145 int i;
147 for (i = 0; i < 1024; ++i)
148 osmo_timer_del(&l1s->pm.meas.arfcn_sig_lev_timers[i]);