aboutsummaryrefslogtreecommitdiffstats
path: root/src/osmo-bts-litecell15/misc
diff options
context:
space:
mode:
Diffstat (limited to 'src/osmo-bts-litecell15/misc')
-rw-r--r--src/osmo-bts-litecell15/misc/lc15bts_mgr.c9
-rw-r--r--src/osmo-bts-litecell15/misc/lc15bts_mgr_calib.c140
-rw-r--r--src/osmo-bts-litecell15/misc/lc15bts_mgr_temp.c6
-rw-r--r--src/osmo-bts-litecell15/misc/lc15bts_swd.c178
-rw-r--r--src/osmo-bts-litecell15/misc/lc15bts_swd.h7
5 files changed, 291 insertions, 49 deletions
diff --git a/src/osmo-bts-litecell15/misc/lc15bts_mgr.c b/src/osmo-bts-litecell15/misc/lc15bts_mgr.c
index 51a05f93..cec9a822 100644
--- a/src/osmo-bts-litecell15/misc/lc15bts_mgr.c
+++ b/src/osmo-bts-litecell15/misc/lc15bts_mgr.c
@@ -46,6 +46,8 @@
#include "misc/lc15bts_par.h"
#include "misc/lc15bts_bid.h"
#include "misc/lc15bts_power.h"
+#include "misc/lc15bts_swd.h"
+
#include "lc15bts_led.h"
static int no_rom_write = 0;
@@ -163,6 +165,7 @@ static void check_sensor_timer_cb(void *unused)
lc15bts_check_vswr(no_rom_write);
osmo_timer_schedule(&sensor_timer, SENSOR_TIMER_SECS, 0);
/* TODO checks if lc15bts_check_temp/lc15bts_check_power/lc15bts_check_vswr went ok */
+ lc15bts_swd_event(&manager, SWD_CHECK_SENSOR);
}
static struct osmo_timer_list hours_timer;
@@ -172,6 +175,7 @@ static void hours_timer_cb(void *unused)
osmo_timer_schedule(&hours_timer, HOURS_TIMER_SECS, 0);
/* TODO: validates if lc15bts_update_hours went correctly */
+ lc15bts_swd_event(&manager, SWD_UPDATE_HOURS);
}
static void print_help(void)
@@ -317,6 +321,10 @@ int main(int argc, char **argv)
INIT_LLIST_HEAD(&manager.lc15bts_leds.list);
INIT_LLIST_HEAD(&manager.alarms.list);
+ /* Initialize the service watchdog notification for SWD_LAST event(s) */
+ if (lc15bts_swd_init(&manager, (int)(SWD_LAST)) != 0)
+ exit(3);
+
/* start temperature check timer */
sensor_timer.cb = check_sensor_timer_cb;
check_sensor_timer_cb(NULL);
@@ -357,5 +365,6 @@ int main(int argc, char **argv)
while (1) {
log_reset_context();
osmo_select_main(0);
+ lc15bts_swd_event(&manager, SWD_MAINLOOP);
}
}
diff --git a/src/osmo-bts-litecell15/misc/lc15bts_mgr_calib.c b/src/osmo-bts-litecell15/misc/lc15bts_mgr_calib.c
index fb494770..badb5455 100644
--- a/src/osmo-bts-litecell15/misc/lc15bts_mgr_calib.c
+++ b/src/osmo-bts-litecell15/misc/lc15bts_mgr_calib.c
@@ -27,6 +27,9 @@
#include "misc/lc15bts_mgr.h"
#include "misc/lc15bts_misc.h"
#include "misc/lc15bts_clock.h"
+#include "misc/lc15bts_swd.h"
+#include "misc/lc15bts_par.h"
+#include "misc/lc15bts_led.h"
#include "osmo-bts/msg_utils.h"
#include <osmocom/core/logging.h>
@@ -41,10 +44,14 @@
#include <osmocom/abis/e1_input.h>
#include <osmocom/abis/ipa.h>
+#include <time.h>
+
static void calib_adjust(struct lc15bts_mgr_instance *mgr);
static void calib_state_reset(struct lc15bts_mgr_instance *mgr, int reason);
static void calib_loop_run(void *_data);
+static int ocxodac_saved_value = -1;
+
enum calib_state {
CALIB_INITIAL,
CALIB_IN_PROGRESS,
@@ -88,7 +95,9 @@ static void calib_adjust(struct lc15bts_mgr_instance *mgr)
int interval_sec;
int dac_value;
int new_dac_value;
- double dac_correction;
+ int dac_correction;
+ time_t now;
+ time_t last_gps_fix;
rc = lc15bts_clock_err_get(&fault, &error_ppt,
&accuracy_ppq, &interval_sec);
@@ -99,12 +108,32 @@ static void calib_adjust(struct lc15bts_mgr_instance *mgr)
return;
}
+ /* get current time */
+ now = time(NULL);
+
+ /* first time after start of manager program */
+ if (mgr->gps.last_update == 0)
+ mgr->gps.last_update = now;
+
+ /* read last GPS 3D fix from storage */
+ rc = lc15bts_par_get_gps_fix(&last_gps_fix);
+ if (rc < 0) {
+ LOGP(DCALIB, LOGL_NOTICE, "Last GPS 3D fix can not read (%d). Last GPS 3D fix sets to zero\n", rc);
+ last_gps_fix = 0;
+ }
+
if (fault) {
LOGP(DCALIB, LOGL_NOTICE, "GPS has no fix\n");
calib_state_reset(mgr, CALIB_FAIL_GPSFIX);
return;
}
+ /* We got GPS 3D fix */
+ LOGP(DCALIB, LOGL_DEBUG, "Got GPS 3D fix warn_flags=0x%08x, last=%lld, now=%lld\n",
+ mgr->lc15bts_ctrl.warn_flags,
+ (long long)last_gps_fix,
+ (long long)now);
+
rc = lc15bts_clock_dac_get(&dac_value);
if (rc < 0) {
LOGP(DCALIB, LOGL_ERROR,
@@ -113,60 +142,74 @@ static void calib_adjust(struct lc15bts_mgr_instance *mgr)
return;
}
+ /* Set OCXO initial dac value */
+ if (ocxodac_saved_value < 0)
+ ocxodac_saved_value = dac_value;
+
LOGP(DCALIB, LOGL_NOTICE,
"Calibration ERR(%f PPB) ACC(%f PPB) INT(%d) DAC(%d)\n",
error_ppt / 1000., accuracy_ppq / 1000000., interval_sec, dac_value);
- /* 1 unit of correction equal about 0.5 - 1 PPB correction */
- dac_correction = (int)(-error_ppt * 0.00056);
- new_dac_value = dac_value + dac_correction + 0.5;
-
- /* We have a fix, make sure the measured error is
- meaningful (10 times the accuracy) */
- if ((new_dac_value != dac_value) && ((100l * abs(error_ppt)) > accuracy_ppq)) {
-
+ /* Need integration time to correct */
+ if (interval_sec) {
+ /* 1 unit of correction equal about 0.5 - 1 PPB correction */
+ dac_correction = (int)(-error_ppt * 0.0015);
+ new_dac_value = dac_value + dac_correction;
+
if (new_dac_value > 4095)
- dac_value = 4095;
+ new_dac_value = 4095;
else if (new_dac_value < 0)
- dac_value = 0;
- else
- dac_value = new_dac_value;
-
- LOGP(DCALIB, LOGL_NOTICE,
- "Going to apply %d as new clock setting.\n",
- dac_value);
-
- rc = lc15bts_clock_dac_set(dac_value);
- if (rc < 0) {
- LOGP(DCALIB, LOGL_ERROR,
- "Failed to set OCXO dac value %d\n", rc);
- calib_state_reset(mgr, CALIB_FAIL_OCXODAC);
- return;
- }
- rc = lc15bts_clock_err_reset();
- if (rc < 0) {
- LOGP(DCALIB, LOGL_ERROR,
- "Failed to set reset clock error module %d\n", rc);
+ new_dac_value = 0;
+
+ /* We have a fix, make sure the measured error is
+ meaningful (10 times the accuracy) */
+ if ((new_dac_value != dac_value) && ((100l * abs(error_ppt)) > accuracy_ppq)) {
+
+ LOGP(DCALIB, LOGL_NOTICE,
+ "Going to apply %d as new clock setting.\n",
+ new_dac_value);
+
+ rc = lc15bts_clock_dac_set(new_dac_value);
+ if (rc < 0) {
+ LOGP(DCALIB, LOGL_ERROR,
+ "Failed to set OCXO dac value %d\n", rc);
+ calib_state_reset(mgr, CALIB_FAIL_OCXODAC);
+ return;
+ }
+ rc = lc15bts_clock_err_reset();
+ if (rc < 0) {
+ LOGP(DCALIB, LOGL_ERROR,
+ "Failed to reset clock error module %d\n", rc);
calib_state_reset(mgr, CALIB_FAIL_CLKERR);
- return;
+ return;
+ }
}
- }
-
- /* Save the correction value in the DAC eeprom if the
- frequency has been stable for 24 hours */
- else if (interval_sec >= (24 * 60 * 60)) {
- rc = lc15bts_clock_dac_save();
- if (rc < 0) {
- LOGP(DCALIB, LOGL_ERROR,
- "Failed to save OCXO dac value %d\n", rc);
- calib_state_reset(mgr, CALIB_FAIL_OCXODAC);
- }
- rc = lc15bts_clock_err_reset();
- if (rc < 0) {
- LOGP(DCALIB, LOGL_ERROR,
- "Failed to set reste clock error module %d\n", rc);
- calib_state_reset(mgr, CALIB_FAIL_CLKERR);
+ /* New conditions to store DAC value:
+ * - Resolution accuracy less or equal than 0.01PPB (or 10000 PPQ)
+ * - Error less or equal than 2PPB (or 2000PPT)
+ * - Solution different than the last one */
+ else if (accuracy_ppq <= 10000) {
+ if((dac_value != ocxodac_saved_value) && (abs(error_ppt) < 2000)) {
+ LOGP(DCALIB, LOGL_NOTICE, "Saving OCXO DAC value to memory... val = %d\n", dac_value);
+ rc = lc15bts_clock_dac_save();
+ if (rc < 0) {
+ LOGP(DCALIB, LOGL_ERROR,
+ "Failed to save OCXO dac value %d\n", rc);
+ calib_state_reset(mgr, CALIB_FAIL_OCXODAC);
+ } else {
+ ocxodac_saved_value = dac_value;
+ }
+ }
+
+ rc = lc15bts_clock_err_reset();
+ if (rc < 0) {
+ LOGP(DCALIB, LOGL_ERROR,
+ "Failed to reset clock error module %d\n", rc);
+ calib_state_reset(mgr, CALIB_FAIL_CLKERR);
+ }
}
+ } else {
+ LOGP(DCALIB, LOGL_NOTICE, "Skipping this iteration, no integration time\n");
}
calib_state_reset(mgr, CALIB_SUCCESS);
@@ -197,6 +240,8 @@ static void calib_state_reset(struct lc15bts_mgr_instance *mgr, int outcome)
mgr->calib.calib_timeout.data = mgr;
mgr->calib.calib_timeout.cb = calib_loop_run;
osmo_timer_schedule(&mgr->calib.calib_timeout, timeout, 0);
+ /* TODO: do we want to notify if we got a calibration error, like no gps fix? */
+ lc15bts_swd_event(mgr, SWD_CHECK_CALIB);
}
mgr->calib.state = CALIB_INITIAL;
@@ -241,6 +286,7 @@ int lc15bts_mgr_calib_init(struct lc15bts_mgr_instance *mgr)
mgr->calib.calib_timeout.data = mgr;
mgr->calib.calib_timeout.cb = calib_loop_run;
osmo_timer_schedule(&mgr->calib.calib_timeout, 0, 0);
- return 0;
+
+ return 0;
}
diff --git a/src/osmo-bts-litecell15/misc/lc15bts_mgr_temp.c b/src/osmo-bts-litecell15/misc/lc15bts_mgr_temp.c
index 9d2dfecf..9665e1db 100644
--- a/src/osmo-bts-litecell15/misc/lc15bts_mgr_temp.c
+++ b/src/osmo-bts-litecell15/misc/lc15bts_mgr_temp.c
@@ -28,6 +28,7 @@
#include "misc/lc15bts_temp.h"
#include "misc/lc15bts_power.h"
#include "misc/lc15bts_led.h"
+#include "misc/lc15bts_swd.h"
#include "limits.h"
#include <osmo-bts/logging.h>
@@ -116,7 +117,7 @@ static void handle_normal_actions(int actions)
* and used SIGCHLD/waitpid to pick up the dead processes
* without invoking shell.
*/
- system("/bin/systemctl start lc15bts.service");
+ system("/bin/systemctl start osmo-bts.service");
}
}
@@ -151,7 +152,7 @@ static void handle_actions(int actions)
* and used SIGCHLD/waitpid to pick up the dead processes
* without invoking shell.
*/
- system("/bin/systemctl stop lc15bts.service");
+ system("/bin/systemctl stop osmo-bts.service");
}
}
@@ -364,6 +365,7 @@ static void sensor_ctrl_check_cb(void *_data)
osmo_timer_schedule(&sensor_ctrl_timer, LC15BTS_SENSOR_TIMER_DURATION, 0);
LOGP(DTEMP, LOGL_DEBUG,"Check sensors timer expired\n");
/* TODO: do we want to notify if some sensors could not be read? */
+ lc15bts_swd_event(mgr, SWD_CHECK_TEMP_SENSOR);
}
int lc15bts_mgr_sensor_init(struct lc15bts_mgr_instance *mgr)
diff --git a/src/osmo-bts-litecell15/misc/lc15bts_swd.c b/src/osmo-bts-litecell15/misc/lc15bts_swd.c
new file mode 100644
index 00000000..59c7b616
--- /dev/null
+++ b/src/osmo-bts-litecell15/misc/lc15bts_swd.c
@@ -0,0 +1,178 @@
+/* Systemd service wd notification for Litecell 1.5 BTS management daemon */
+
+/* Copyright (C) 2015 by Yves Godin <support@nuranwireless.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 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 Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "misc/lc15bts_mgr.h"
+#include "misc/lc15bts_swd.h"
+#include <osmocom/core/logging.h>
+
+/* Needed for service watchdog notification */
+#include <systemd/sd-daemon.h>
+
+/* This is the period used to verify if all events have been registered to be allowed
+ to notify the systemd service watchdog
+*/
+#define SWD_PERIOD 30
+
+static void swd_start(struct lc15bts_mgr_instance *mgr);
+static void swd_process(struct lc15bts_mgr_instance *mgr);
+static void swd_close(struct lc15bts_mgr_instance *mgr);
+static void swd_state_reset(struct lc15bts_mgr_instance *mgr, int reason);
+static int swd_run(struct lc15bts_mgr_instance *mgr, int from_loop);
+static void swd_loop_run(void *_data);
+
+enum swd_state {
+ SWD_INITIAL,
+ SWD_IN_PROGRESS,
+};
+
+enum swd_result {
+ SWD_FAIL_START,
+ SWD_FAIL_NOTIFY,
+ SWD_SUCCESS,
+};
+
+static void swd_start(struct lc15bts_mgr_instance *mgr)
+{
+ swd_process(mgr);
+}
+
+static void swd_process(struct lc15bts_mgr_instance *mgr)
+{
+ int rc = 0, notify = 0;
+
+ /* Did we get all needed conditions ? */
+ if (mgr->swd.swd_eventmasks == mgr->swd.swd_events) {
+ /* Ping systemd service wd if enabled */
+ rc = sd_notify(0, "WATCHDOG=1");
+ LOGP(DSWD, LOGL_NOTICE, "Watchdog notification attempt\n");
+ notify = 1;
+ }
+ else {
+ LOGP(DSWD, LOGL_NOTICE, "Missing watchdog events: e:0x%016llx,m:0x%016llx\n",mgr->swd.swd_events,mgr->swd.swd_eventmasks);
+ }
+
+ if (rc < 0) {
+ LOGP(DSWD, LOGL_ERROR,
+ "Failed to notify system service watchdog: %d\n", rc);
+ swd_state_reset(mgr, SWD_FAIL_NOTIFY);
+ return;
+ }
+ else {
+ /* Did we notified the watchdog? */
+ if (notify) {
+ mgr->swd.swd_events = 0;
+ /* Makes sure we really cleared it in case any event was notified at this same moment (it would be lost) */
+ if (mgr->swd.swd_events != 0)
+ mgr->swd.swd_events = 0;
+ }
+ }
+
+ swd_state_reset(mgr, SWD_SUCCESS);
+ return;
+}
+
+static void swd_close(struct lc15bts_mgr_instance *mgr)
+{
+}
+
+static void swd_state_reset(struct lc15bts_mgr_instance *mgr, int outcome)
+{
+ if (mgr->swd.swd_from_loop) {
+ mgr->swd.swd_timeout.data = mgr;
+ mgr->swd.swd_timeout.cb = swd_loop_run;
+ osmo_timer_schedule(&mgr->swd.swd_timeout, SWD_PERIOD, 0);
+ }
+
+ mgr->swd.state = SWD_INITIAL;
+ swd_close(mgr);
+}
+
+static int swd_run(struct lc15bts_mgr_instance *mgr, int from_loop)
+{
+ if (mgr->swd.state != SWD_INITIAL) {
+ LOGP(DSWD, LOGL_ERROR, "Swd is already in progress.\n");
+ return -1;
+ }
+
+ mgr->swd.swd_from_loop = from_loop;
+
+ /* From now on everything will be handled from the failure */
+ mgr->swd.state = SWD_IN_PROGRESS;
+ swd_start(mgr);
+ return 0;
+}
+
+static void swd_loop_run(void *_data)
+{
+ int rc;
+ struct lc15bts_mgr_instance *mgr = _data;
+
+ LOGP(DSWD, LOGL_NOTICE, "Going to check for watchdog notification.\n");
+ rc = swd_run(mgr, 1);
+ if (rc != 0) {
+ swd_state_reset(mgr, SWD_FAIL_START);
+ }
+}
+
+/* 'swd_num_events' configures the number of events to be monitored before notifying the
+ systemd service watchdog. It must be in the range of [1,64]. Events are notified
+ through the function 'lc15bts_swd_event'
+*/
+int lc15bts_swd_init(struct lc15bts_mgr_instance *mgr, int swd_num_events)
+{
+ /* Checks for a valid number of events to validate */
+ if (swd_num_events < 1 || swd_num_events > 64)
+ return(-1);
+
+ mgr->swd.state = SWD_INITIAL;
+ mgr->swd.swd_timeout.data = mgr;
+ mgr->swd.swd_timeout.cb = swd_loop_run;
+ osmo_timer_schedule(&mgr->swd.swd_timeout, 0, 0);
+
+ if (swd_num_events == 64){
+ mgr->swd.swd_eventmasks = 0xffffffffffffffffULL;
+ }
+ else {
+ mgr->swd.swd_eventmasks = ((1ULL << swd_num_events) - 1);
+ }
+ mgr->swd.swd_events = 0;
+ mgr->swd.num_events = swd_num_events;
+
+ return 0;
+}
+
+/* Notifies that the specified event 'swd_event' happened correctly;
+ the value must be in the range of [0,'swd_num_events'[ (see lc15bts_swd_init).
+ For example, if 'swd_num_events' was 64, 'swd_event' events are numbered 0 to 63.
+ WARNING: if this function can be used from multiple threads at the same time,
+ it must be protected with a kind of mutex to avoid loosing event notification.
+*/
+int lc15bts_swd_event(struct lc15bts_mgr_instance *mgr, enum mgr_swd_events swd_event)
+{
+ /* Checks for a valid specified event (smaller than max possible) */
+ if ((int)(swd_event) < 0 || (int)(swd_event) >= mgr->swd.num_events)
+ return(-1);
+
+ mgr->swd.swd_events = mgr->swd.swd_events | ((unsigned long long int)(1) << (int)(swd_event));
+
+ /* !!! Uncomment following line to debug events notification */
+ LOGP(DSWD, LOGL_DEBUG,"Swd event notified: %d\n", (int)(swd_event));
+
+ return 0;
+}
diff --git a/src/osmo-bts-litecell15/misc/lc15bts_swd.h b/src/osmo-bts-litecell15/misc/lc15bts_swd.h
new file mode 100644
index 00000000..b78a2c2a
--- /dev/null
+++ b/src/osmo-bts-litecell15/misc/lc15bts_swd.h
@@ -0,0 +1,7 @@
+#ifndef _LC15BTS_SWD_H
+#define _LC15BTS_SWD_H
+
+int lc15bts_swd_init(struct lc15bts_mgr_instance *mgr, int swd_num_events);
+int lc15bts_swd_event(struct lc15bts_mgr_instance *mgr, enum mgr_swd_events swd_event);
+
+#endif