stat: Add global stat group

Add a global stat_item group for measurement values and a
corresponding macro to get and set the values.
Add a stat_item STAT_MS_PRESET to monitor the number of
MS objects in the storage.

Sponsored-by: On-Waves ehf
diff --git a/src/bts.cpp b/src/bts.cpp
index 2d8a91a..edae737 100644
--- a/src/bts.cpp
+++ b/src/bts.cpp
@@ -86,6 +86,19 @@
 	bts_ctr_description,
 };
 
+static const struct osmo_stat_item_desc bts_stat_item_description[] = {
+	{ "ms.present",		"MS Present           ",
+		OSMO_STAT_ITEM_NO_UNIT, 4, 0},
+};
+
+static const struct osmo_stat_item_group_desc bts_statg_desc = {
+	"bts",
+	"BTS Statistics",
+	OSMO_STATS_CLASS_GLOBAL,
+	ARRAY_SIZE(bts_stat_item_description),
+	bts_stat_item_description,
+};
+
 BTS* BTS::main_bts()
 {
 	return &s_bts;
@@ -132,6 +145,7 @@
 	}
 
 	m_ratectrs = rate_ctr_group_alloc(tall_pcu_ctx, &bts_ctrg_desc, 0);
+	m_statg = osmo_stat_item_group_alloc(tall_pcu_ctx, &bts_statg_desc, 0);
 }
 
 BTS::~BTS()
diff --git a/src/bts.h b/src/bts.h
index 4129483..329f399 100644
--- a/src/bts.h
+++ b/src/bts.h
@@ -25,6 +25,7 @@
 extern "C" {
 #include <osmocom/core/linuxlist.h>
 #include <osmocom/core/rate_ctr.h>
+#include <osmocom/core/stat_item.h>
 #include <osmocom/core/timer.h>
 }
 
@@ -234,6 +235,10 @@
 	};
 
 	enum {
+		STAT_MS_PRESENT,
+	};
+
+	enum {
 		TIMER_T3190_MSEC = 5000,
 	};
 
@@ -301,10 +306,14 @@
 	void llc_frame_sched();
 	void rach_frame();
 
+	void ms_present(int32_t n);
+	int32_t ms_present_get();
+
 	/*
 	 * Below for C interface for the VTY
 	 */
 	struct rate_ctr_group *rate_counters() const;
+	struct osmo_stat_item_group *stat_items() const;
 
 private:
 	int m_cur_fn;
@@ -313,6 +322,7 @@
 	PollController m_pollController;
 	SBAController m_sba;
 	struct rate_ctr_group *m_ratectrs;
+	struct osmo_stat_item_group *m_statg;
 
 	GprsMsStorage m_ms_store;
 
@@ -379,6 +389,11 @@
 	return m_ratectrs;
 }
 
+inline struct osmo_stat_item_group *BTS::stat_items() const
+{
+	return m_statg;
+}
+
 #define CREATE_COUNT_INLINE(func_name, ctr_name) \
 	inline void BTS::func_name() {\
 		rate_ctr_inc(&m_ratectrs->ctr[ctr_name]); \
@@ -413,6 +428,17 @@
 
 #undef CREATE_COUNT_INLINE
 
+#define CREATE_STAT_INLINE(func_name, func_name_get, stat_name) \
+	inline void BTS::func_name(int32_t val) {\
+		osmo_stat_item_set(m_statg->items[stat_name], val); \
+	} \
+	inline int32_t BTS::func_name_get() {\
+		return osmo_stat_item_get_last(m_statg->items[stat_name]); \
+	}
+
+CREATE_STAT_INLINE(ms_present, ms_present_get, STAT_MS_PRESENT);
+
+#undef CREATE_STAT_INLINE
 
 inline gprs_rlcmac_bts *gprs_rlcmac_pdch::bts_data() const
 {
@@ -430,6 +456,7 @@
 #endif
 	struct gprs_rlcmac_bts *bts_main_data();
 	struct rate_ctr_group *bts_main_data_stats();
+	struct osmo_stat_item_group *bts_main_data_stat_items();
 #ifdef __cplusplus
 }
 
diff --git a/src/gprs_ms_storage.cpp b/src/gprs_ms_storage.cpp
index 36f9b6b..e0aee5e 100644
--- a/src/gprs_ms_storage.cpp
+++ b/src/gprs_ms_storage.cpp
@@ -22,6 +22,7 @@
 #include "gprs_ms_storage.h"
 
 #include "tbf.h"
+#include "bts.h"
 #include "gprs_debug.h"
 
 #define GPRS_UNDEFINED_IMSI "000"
@@ -45,6 +46,8 @@
 void GprsMsStorage::ms_idle(class GprsMs *ms)
 {
 	llist_del(&ms->list());
+	if (m_bts)
+		m_bts->ms_present(m_bts->ms_present_get() - 1);
 	if (ms->is_idle())
 		delete ms;
 }
@@ -90,6 +93,8 @@
 
 	ms->set_callback(this);
 	llist_add(&ms->list(), &m_list);
+	if (m_bts)
+		m_bts->ms_present(m_bts->ms_present_get() + 1);
 
 	return ms;
 }