Introduce new file for various measurements

The measurements include:
- DL bandwidth usage
- DL packet loss rate
- DL measurements by mobile
- UL measurements by BTS

In order to receive DL measurements from mobile, it must be enabled via
system information message at BSC.
diff --git a/src/gprs_rlcmac_meas.cpp b/src/gprs_rlcmac_meas.cpp
new file mode 100644
index 0000000..75da835
--- /dev/null
+++ b/src/gprs_rlcmac_meas.cpp
@@ -0,0 +1,190 @@
+/* Measurements
+ *
+ * Copyright (C) 2012 Andreas Eversberg <jolly@eversberg.eu>
+ *
+ * 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.
+ */
+ 
+#include <gprs_rlcmac.h>
+#include <gprs_debug.h>
+#include <pcu_l1_if.h>
+
+#include <string.h>
+#include <errno.h>
+
+/*
+ * downlink measurement
+ */
+
+/* received Measurement Report */
+int gprs_rlcmac_meas_rep(Packet_Measurement_Report_t *pmr)
+{
+	NC_Measurement_Report_t *ncr;
+	NC_Measurements_t *nc;
+	int i;
+
+	LOGP(DRLCMACMEAS, LOGL_INFO, "Measuement Report of TLLI=0x%08x:",
+		pmr->TLLI);
+
+	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,
+			" <EXT Reporting not supported!>\n");
+		break;
+	}
+
+	return 0;
+}
+
+
+/*
+ * uplink measurement
+ */
+
+/* RSSI values received from MS */
+int gprs_rlcmac_rssi(struct gprs_rlcmac_tbf *tbf, int8_t rssi)
+{
+	struct timeval now_tv, *rssi_tv = &tbf->meas.rssi_tv;
+	uint32_t elapsed;
+
+	tbf->meas.rssi_sum += rssi;
+	tbf->meas.rssi_num++;
+
+	gettimeofday(&now_tv, NULL);
+	elapsed = ((now_tv.tv_sec - rssi_tv->tv_sec) << 7)
+		+ ((now_tv.tv_usec - rssi_tv->tv_usec) << 7) / 1000000;
+	if (elapsed < 128)
+		return 0;
+
+	gprs_rlcmac_rssi_rep(tbf);
+
+	/* reset rssi values and timestamp */
+	memcpy(rssi_tv, &now_tv, sizeof(struct timeval));
+	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;
+
+	LOGP(DRLCMACMEAS, LOGL_INFO, "UL RSSI of TLLI=0x%08x: %d dBm\n",
+		tbf->tlli, 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_tbf *tbf, uint16_t received,
+	uint16_t lost)
+{
+	struct timeval now_tv, *loss_tv = &tbf->meas.dl_loss_tv;
+	uint32_t 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->meas.dl_loss_received += received;
+	tbf->meas.dl_loss_lost += lost;
+
+	gettimeofday(&now_tv, NULL);
+	elapsed = ((now_tv.tv_sec - loss_tv->tv_sec) << 7)
+		+ ((now_tv.tv_usec - loss_tv->tv_usec) << 7) / 1000000;
+	if (elapsed < 128)
+		return 0;
+
+	gprs_rlcmac_lost_rep(tbf);
+
+	/* reset lost values and timestamp */
+	memcpy(loss_tv, &now_tv, sizeof(struct timeval));
+	tbf->meas.dl_loss_received = 0;
+	tbf->meas.dl_loss_lost = 0;
+
+	return 0;
+}
+
+/* Give Lost report */
+int gprs_rlcmac_lost_rep(struct gprs_rlcmac_tbf *tbf)
+{
+	uint16_t sum = tbf->meas.dl_loss_lost + tbf->meas.dl_loss_received;
+
+	/* No measurement values */
+	if (!sum)
+		return -EINVAL;
+
+	LOGP(DRLCMACMEAS, LOGL_INFO, "DL packet loss of IMSI=%s / TLLI=0x%08x: "
+		"%d%%\n", tbf->meas.imsi, tbf->tlli,
+		tbf->meas.dl_loss_lost * 100 / sum);
+
+	return 0;
+}
+
+
+/*
+ * downlink bandwidth
+ */
+
+int gprs_rlcmac_dl_bw(struct gprs_rlcmac_tbf *tbf, uint16_t octets)
+{
+	struct timeval now_tv, *bw_tv = &tbf->meas.dl_bw_tv;
+	uint32_t elapsed;
+
+	tbf->meas.dl_bw_octets += octets;
+
+	gettimeofday(&now_tv, NULL);
+	elapsed = ((now_tv.tv_sec - bw_tv->tv_sec) << 7)
+		+ ((now_tv.tv_usec - bw_tv->tv_usec) << 7) / 1000000;
+	if (elapsed < 128)
+		return 0;
+
+	LOGP(DRLCMACMEAS, LOGL_INFO, "DL Bandwitdh of IMSI=%s / TLLI=0x%08x: "
+		"%d KBits/s\n", tbf->meas.imsi, tbf->tlli,
+		tbf->meas.dl_bw_octets / elapsed);
+
+	/* reset bandwidth values timestamp */
+	memcpy(bw_tv, &now_tv, sizeof(struct timeval));
+	tbf->meas.dl_bw_octets = 0;
+
+	return 0;
+}
+