diff options
-rw-r--r-- | src/bts.cpp | 64 | ||||
-rw-r--r-- | src/gprs_ms.cpp | 17 | ||||
-rw-r--r-- | src/pcu_l1_if.h | 46 | ||||
-rw-r--r-- | src/pcu_vty_functions.cpp | 16 |
4 files changed, 140 insertions, 3 deletions
diff --git a/src/bts.cpp b/src/bts.cpp index f94799b6..5fafd84a 100644 --- a/src/bts.cpp +++ b/src/bts.cpp @@ -790,11 +790,62 @@ void gprs_rlcmac_pdch::rcv_control_ack(Packet_Control_Acknowledgement_t *packet, "at no request\n"); } +static void get_rx_qual_meas(struct pcu_l1_meas *meas, uint8_t rx_qual_enc) +{ + static const int16_t rx_qual_map[] = { + 0, /* 0,14 % */ + 0, /* 0,28 % */ + 1, /* 0,57 % */ + 1, /* 1,13 % */ + 2, /* 2,26 % */ + 5, /* 4,53 % */ + 9, /* 9,05 % */ + 18, /* 18,10 % */ + }; + + meas->set_ms_rx_qual(rx_qual_map[ + OSMO_MIN(rx_qual_enc, ARRAY_SIZE(rx_qual_map)-1) + ]); +} + +static void get_meas(struct pcu_l1_meas *meas, + const Packet_Resource_Request_t *qr) +{ + unsigned i; + + meas->set_ms_c_value(qr->C_VALUE); + if (qr->Exist_SIGN_VAR) + meas->set_ms_sign_var((qr->SIGN_VAR + 2) / 4); /* SIGN_VAR * 0.25 dB */ + + for (i = 0; i < OSMO_MIN(ARRAY_SIZE(qr->Slot), ARRAY_SIZE(meas->ts)); i++) + { + if (qr->Slot[i].Exist) + meas->set_ms_i_level(i, -2 * qr->Slot[i].I_LEVEL); + } +} + +static void get_meas(struct pcu_l1_meas *meas, + const Channel_Quality_Report_t *qr) +{ + unsigned i; + + get_rx_qual_meas(meas, qr->RXQUAL); + meas->set_ms_c_value(qr->C_VALUE); + meas->set_ms_sign_var((qr->SIGN_VAR + 2) / 4); /* SIGN_VAR * 0.25 dB */ + + for (i = 0; i < OSMO_MIN(ARRAY_SIZE(qr->Slot), ARRAY_SIZE(meas->ts)); i++) + { + if (qr->Slot[i].Exist) + meas->set_ms_i_level(i, -2 * qr->Slot[i].I_LEVEL_TN); + } +} + void gprs_rlcmac_pdch::rcv_control_dl_ack_nack(Packet_Downlink_Ack_Nack_t *ack_nack, uint32_t fn) { int8_t tfi = 0; /* must be signed */ struct gprs_rlcmac_dl_tbf *tbf; int rc; + struct pcu_l1_meas meas; tfi = ack_nack->DOWNLINK_TFI; tbf = bts()->dl_tbf_by_poll_fn(fn, trx_no(), ts_no); @@ -841,6 +892,11 @@ void gprs_rlcmac_pdch::rcv_control_dl_ack_nack(Packet_Downlink_Ack_Nack_t *ack_n /* schedule uplink assignment */ tbf->ul_ass_state = GPRS_RLCMAC_UL_ASS_SEND_ASS; } + /* get measurements */ + if (tbf->ms()) { + get_meas(&meas, &ack_nack->Channel_Quality_Report); + tbf->ms()->update_l1_meas(&meas); + } } void gprs_rlcmac_pdch::rcv_resource_request(Packet_Resource_Request_t *request, uint32_t fn) @@ -853,6 +909,7 @@ void gprs_rlcmac_pdch::rcv_resource_request(Packet_Resource_Request_t *request, uint32_t tlli = request->ID.u.TLLI; uint8_t ms_class = 0; uint8_t ta = 0; + struct pcu_l1_meas meas; GprsMs *ms = bts()->ms_by_tlli(tlli); /* Keep the ms, even if it gets idle temporarily */ @@ -907,6 +964,12 @@ void gprs_rlcmac_pdch::rcv_resource_request(Packet_Resource_Request_t *request, ul_tbf->control_ts = ts_no; /* schedule uplink assignment */ ul_tbf->ul_ass_state = GPRS_RLCMAC_UL_ASS_SEND_ASS; + + /* get measurements */ + if (ul_tbf->ms()) { + get_meas(&meas, request); + ul_tbf->ms()->update_l1_meas(&meas); + } return; } @@ -933,7 +996,6 @@ void gprs_rlcmac_pdch::rcv_resource_request(Packet_Resource_Request_t *request, "RX: [PCU <- BTS] %s FIXME: Packet resource request\n", tbf_name(ul_tbf)); } - } void gprs_rlcmac_pdch::rcv_measurement_report(Packet_Measurement_Report_t *report, uint32_t fn) diff --git a/src/gprs_ms.cpp b/src/gprs_ms.cpp index cc211713..fe560e86 100644 --- a/src/gprs_ms.cpp +++ b/src/gprs_ms.cpp @@ -421,6 +421,7 @@ void GprsMs::update_l1_meas(const pcu_l1_meas *meas) { struct gprs_rlcmac_bts *bts_data; uint8_t max_cs_ul = 4; + unsigned i; OSMO_ASSERT(m_bts != NULL); bts_data = m_bts->bts_data(); @@ -464,4 +465,20 @@ void GprsMs::update_l1_meas(const pcu_l1_meas *meas) m_l1_meas.set_ber(meas->ber); if (meas->have_link_qual) m_l1_meas.set_link_qual(meas->link_qual); + + if (meas->have_ms_rx_qual) + m_l1_meas.set_ms_rx_qual(meas->ms_rx_qual); + if (meas->have_ms_c_value) + m_l1_meas.set_ms_c_value(meas->ms_c_value); + if (meas->have_ms_sign_var) + m_l1_meas.set_ms_sign_var(meas->ms_sign_var); + + if (meas->have_ms_i_level) { + for (i = 0; i < ARRAY_SIZE(meas->ts); ++i) { + if (meas->ts[i].have_ms_i_level) + m_l1_meas.set_ms_i_level(i, meas->ts[i].ms_i_level); + else + m_l1_meas.ts[i].have_ms_i_level = 0; + } + } } diff --git a/src/pcu_l1_if.h b/src/pcu_l1_if.h index 88c83991..59b9cba2 100644 --- a/src/pcu_l1_if.h +++ b/src/pcu_l1_if.h @@ -37,16 +37,42 @@ extern "C" { * L1 Measurement values */ +struct pcu_l1_meas_ts { + unsigned have_ms_i_level:1; + + int16_t ms_i_level; /* I_LEVEL in dB */ + +#ifdef __cplusplus + pcu_l1_meas_ts& set_ms_i_level(int16_t v) { + ms_i_level = v; have_ms_i_level = 1; return *this; + } + + pcu_l1_meas_ts() : + have_ms_i_level(0) + {} +#endif +}; + struct pcu_l1_meas { unsigned have_rssi:1; unsigned have_ber:1; unsigned have_bto:1; unsigned have_link_qual:1; + unsigned have_ms_rx_qual:1; + unsigned have_ms_c_value:1; + unsigned have_ms_sign_var:1; + unsigned have_ms_i_level:1; int8_t rssi; /* RSSI in dBm */ uint8_t ber; /* Bit error rate in % */ int16_t bto; /* Burst timing offset in quarter bits */ - int16_t link_qual; /* Link quality in db */ + int16_t link_qual; /* Link quality in dB */ + int16_t ms_rx_qual; /* MS RXQUAL value in % */ + int16_t ms_c_value; /* C value in dB */ + int16_t ms_sign_var; /* SIGN_VAR in dB */ + + struct pcu_l1_meas_ts ts[8]; + #ifdef __cplusplus pcu_l1_meas& set_rssi(int8_t v) { rssi = v; have_rssi = 1; return *this;} pcu_l1_meas& set_ber(uint8_t v) { ber = v; have_ber = 1; return *this;} @@ -54,11 +80,27 @@ struct pcu_l1_meas { pcu_l1_meas& set_link_qual(int16_t v) { link_qual = v; have_link_qual = 1; return *this; } + pcu_l1_meas& set_ms_rx_qual(int16_t v) { + ms_rx_qual = v; have_ms_rx_qual = 1; return *this; + } + pcu_l1_meas& set_ms_c_value(int16_t v) { + ms_c_value = v; have_ms_c_value = 1; return *this; + } + pcu_l1_meas& set_ms_sign_var(int16_t v) { + ms_sign_var = v; have_ms_sign_var = 1; return *this; + } + pcu_l1_meas& set_ms_i_level(size_t idx, int16_t v) { + ts[idx].set_ms_i_level(v); have_ms_i_level = 1; return *this; + } pcu_l1_meas() : have_rssi(0), have_ber(0), have_bto(0), - have_link_qual(0) + have_link_qual(0), + have_ms_rx_qual(0), + have_ms_c_value(0), + have_ms_sign_var(0), + have_ms_i_level(0) {} #endif }; diff --git a/src/pcu_vty_functions.cpp b/src/pcu_vty_functions.cpp index bf4843f1..4f54e8e2 100644 --- a/src/pcu_vty_functions.cpp +++ b/src/pcu_vty_functions.cpp @@ -58,6 +58,8 @@ int pcu_vty_show_ms_all(struct vty *vty, struct gprs_rlcmac_bts *bts_data) static int show_ms(struct vty *vty, GprsMs *ms) { + unsigned i; + vty_out(vty, "MS TLLI=%08x, IMSI=%s%s", ms->tlli(), ms->imsi(), VTY_NEWLINE); vty_out(vty, " Timing advance (TA): %d%s", ms->ta(), VTY_NEWLINE); vty_out(vty, " Coding scheme uplink: CS-%d%s", ms->current_cs_ul(), @@ -79,6 +81,20 @@ static int show_ms(struct vty *vty, GprsMs *ms) if (ms->l1_meas()->have_bto) vty_out(vty, " Burst timing offset: %d/4 bit%s", ms->l1_meas()->bto, VTY_NEWLINE); + if (ms->l1_meas()->have_ms_rx_qual) + vty_out(vty, " MS RX quality: %d %%%s", + ms->l1_meas()->ms_rx_qual, VTY_NEWLINE); + if (ms->l1_meas()->have_ms_c_value) + vty_out(vty, " MS C value: %d dB%s", + ms->l1_meas()->ms_c_value, VTY_NEWLINE); + if (ms->l1_meas()->have_ms_sign_var) + vty_out(vty, " MS SIGN variance: %d dB%s", + ms->l1_meas()->ms_sign_var, VTY_NEWLINE); + for (i = 0; i < ARRAY_SIZE(ms->l1_meas()->ts); ++i) { + if (ms->l1_meas()->ts[i].have_ms_i_level) + vty_out(vty, " MS I level (slot %d): %d dB%s", + i, ms->l1_meas()->ts[i].ms_i_level, VTY_NEWLINE); + } if (ms->ul_tbf()) vty_out(vty, " Uplink TBF: TFI=%d, state=%s%s", ms->ul_tbf()->tfi(), |