/* Measurements * * Copyright (C) 2012 Andreas Eversberg * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ extern "C" { #include } #include #include #include #include #include #include #include #include /* * downlink measurement */ /* TODO: trigger the measurement report from the pollcontroller and use it for flow control */ /* received Measurement Report */ int gprs_rlcmac_meas_rep(GprsMs *ms, Packet_Measurement_Report_t *pmr) { NC_Measurement_Report_t *ncr; NC_Measurements_t *nc; int i; LOGPMS(ms, DRLCMACMEAS, LOGL_INFO, "Rx Measurement Report:"); switch (pmr->UnionType) { case 0: ncr = &pmr->u.NC_Measurement_Report; LOGPC(DRLCMACMEAS, LOGL_INFO, " NC%u Serv %d dbm", ncr->NC_MODE + 1, ncr->Serving_Cell_Data.RXLEV_SERVING_CELL - 110); for (i = 0; i < ncr->NUMBER_OF_NC_MEASUREMENTS; i++) { nc = &ncr->NC_Measurements[i]; LOGPC(DRLCMACMEAS, LOGL_DEBUG, ", Neigh %u %d dbm", nc->FREQUENCY_N, nc->RXLEV_N - 110); } LOGPC(DRLCMACMEAS, LOGL_INFO, "\n"); break; case 1: LOGPC(DRLCMACMEAS, LOGL_INFO, " \n"); break; } return 0; } /* * uplink measurement */ /* RSSI values received from MS */ int gprs_rlcmac_rssi(struct gprs_rlcmac_tbf *tbf, int8_t rssi) { struct timespec now_tv, *rssi_tv = &tbf->meas.rssi_tv; struct timespec elapsed; tbf->meas.rssi_sum += rssi; tbf->meas.rssi_num++; osmo_clock_gettime(CLOCK_MONOTONIC, &now_tv); timespecsub(&now_tv, rssi_tv, &elapsed); if (elapsed.tv_sec < 1) return 0; gprs_rlcmac_rssi_rep(tbf); /* reset rssi values and timestamp */ memcpy(rssi_tv, &now_tv, sizeof(*rssi_tv)); tbf->meas.rssi_sum = 0; tbf->meas.rssi_num = 0; return 0; } /* Give RSSI report */ int gprs_rlcmac_rssi_rep(struct gprs_rlcmac_tbf *tbf) { /* No measurement values */ if (!tbf->meas.rssi_num) return -EINVAL; LOGPMS(tbf->ms(), DRLCMACMEAS, LOGL_INFO, "UL RSSI: %d dBm\n", tbf->meas.rssi_sum / tbf->meas.rssi_num); return 0; } /* * lost frames */ /* Lost frames reported from RLCMAC layer */ int gprs_rlcmac_received_lost(struct gprs_rlcmac_dl_tbf *tbf, uint16_t received, uint16_t lost) { struct timespec now_tv, *loss_tv = &tbf->m_bw.dl_loss_tv; struct timespec elapsed; uint16_t sum = received + lost; /* No measurement values */ if (!sum) return -EINVAL; LOGP(DRLCMACMEAS, LOGL_DEBUG, "DL Loss of TLLI 0x%08x: Received: %4d " "Lost: %4d Sum: %4d\n", tbf->tlli(), received, lost, sum); tbf->m_bw.dl_loss_received += received; tbf->m_bw.dl_loss_lost += lost; osmo_clock_gettime(CLOCK_MONOTONIC, &now_tv); timespecsub(&now_tv, loss_tv, &elapsed); if (elapsed.tv_sec < 1) return 0; gprs_rlcmac_lost_rep(tbf); /* reset lost values and timestamp */ memcpy(loss_tv, &now_tv, sizeof(*loss_tv)); tbf->m_bw.dl_loss_received = 0; tbf->m_bw.dl_loss_lost = 0; return 0; } /* Give Lost report */ int gprs_rlcmac_lost_rep(struct gprs_rlcmac_dl_tbf *tbf) { uint16_t sum = tbf->m_bw.dl_loss_lost + tbf->m_bw.dl_loss_received; /* No measurement values */ if (!sum) return -EINVAL; LOGP(DRLCMACMEAS, LOGL_DEBUG, "DL packet loss of IMSI=%s / TLLI=0x%08x: " "%d%%\n", tbf->imsi(), tbf->tlli(), tbf->m_bw.dl_loss_lost * 100 / sum); return 0; } /* * downlink bandwidth */ int gprs_rlcmac_dl_bw(struct gprs_rlcmac_dl_tbf *tbf, uint16_t octets) { struct timespec now_tv, *bw_tv = &tbf->m_bw.dl_bw_tv; struct timespec elapsed; tbf->m_bw.dl_bw_octets += octets; osmo_clock_gettime(CLOCK_MONOTONIC, &now_tv); timespecsub(&now_tv, bw_tv, &elapsed); if (elapsed.tv_sec < 1) return 0; tbf->m_bw.dl_throughput = (tbf->m_bw.dl_bw_octets << 10) / ((elapsed.tv_sec << 10) + (elapsed.tv_nsec >> 20)); LOGP(DRLCMACMEAS, LOGL_INFO, "DL Bandwitdh of IMSI=%s / TLLI=0x%08x: " "%d KBits/s\n", tbf->imsi(), tbf->tlli(), tbf->m_bw.dl_throughput); /* reset bandwidth values timestamp */ memcpy(bw_tv, &now_tv, sizeof(*bw_tv)); tbf->m_bw.dl_bw_octets = 0; return 0; }