From 0ebf985492e528e85acb60692c0cb91219598e04 Mon Sep 17 00:00:00 2001 From: Max Date: Thu, 20 Jul 2017 16:28:20 +0200 Subject: lc15: port lc15bts-mgr dependency changes That's mostly changes related to lc15bts-mgr from https://gitlab.com/nrw_noa/osmo-bts branch nrw/litecell15 based on eb5b7f80510b603579f7af6d7d5ead296c2fa260 commit: * adjust comments to simplify further diffs * add libsystemd dependency to lc15bts-mgr * add software watchdog which uses it * ocxo calibration and gps related code Change-Id: I475a330af771891ba3c897294ce0dd57ec2ba8db Related: SYS#3732 --- src/osmo-bts-litecell15/Makefile.am | 9 +- src/osmo-bts-litecell15/calib_file.c | 62 ++++---- src/osmo-bts-litecell15/misc/lc15bts_mgr.c | 9 ++ src/osmo-bts-litecell15/misc/lc15bts_mgr_calib.c | 140 ++++++++++++------ src/osmo-bts-litecell15/misc/lc15bts_mgr_temp.c | 6 +- src/osmo-bts-litecell15/misc/lc15bts_swd.c | 178 +++++++++++++++++++++++ src/osmo-bts-litecell15/misc/lc15bts_swd.h | 7 + 7 files changed, 326 insertions(+), 85 deletions(-) create mode 100644 src/osmo-bts-litecell15/misc/lc15bts_swd.c create mode 100644 src/osmo-bts-litecell15/misc/lc15bts_swd.h (limited to 'src/osmo-bts-litecell15') diff --git a/src/osmo-bts-litecell15/Makefile.am b/src/osmo-bts-litecell15/Makefile.am index 90e6c463..78a770a9 100644 --- a/src/osmo-bts-litecell15/Makefile.am +++ b/src/osmo-bts-litecell15/Makefile.am @@ -1,14 +1,14 @@ AUTOMAKE_OPTIONS = subdir-objects AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -I$(OPENBSC_INCDIR) -I$(LITECELL15_INCDIR) -AM_CFLAGS = -Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOCODEC_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOVTY_CFLAGS) $(LIBOSMOTRAU_CFLAGS) $(LIBOSMOABIS_CFLAGS) $(LIBOSMOCTRL_CFLAGS) $(LIBOSMOABIS_CFLAGS) $(LIBGPS_CFLAGS) $(ORTP_CFLAGS) +AM_CFLAGS = -Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOCODEC_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOVTY_CFLAGS) $(LIBOSMOTRAU_CFLAGS) $(LIBOSMOABIS_CFLAGS) $(LIBOSMOCTRL_CFLAGS) $(LIBOSMOABIS_CFLAGS) $(LIBGPS_CFLAGS) $(ORTP_CFLAGS) $(LIBSYSTEMD_CFLAGS) COMMON_LDADD = $(LIBOSMOCORE_LIBS) $(LIBOSMOCODEC_LIBS) $(LIBOSMOGSM_LIBS) $(LIBOSMOVTY_LIBS) $(LIBOSMOTRAU_LIBS) $(LIBOSMOABIS_LIBS) $(LIBOSMOCTRL_LIBS) $(ORTP_LIBS) AM_CFLAGS += -DENABLE_LC15BTS EXTRA_DIST = misc/lc15bts_mgr.h misc/lc15bts_misc.h misc/lc15bts_par.h misc/lc15bts_led.h \ misc/lc15bts_temp.h misc/lc15bts_power.h misc/lc15bts_clock.h \ - misc/lc15bts_bid.h misc/lc15bts_nl.h misc/lc15bts_bts.h \ + misc/lc15bts_bid.h misc/lc15bts_nl.h misc/lc15bts_bts.h misc/lc15bts_swd.h \ hw_misc.h l1_if.h l1_transp.h lc15bts.h oml_router.h utils.h bin_PROGRAMS = osmo-bts-lc15 lc15bts-mgr lc15bts-util @@ -29,9 +29,10 @@ lc15bts_mgr_SOURCES = \ misc/lc15bts_mgr_temp.c \ misc/lc15bts_mgr_calib.c \ misc/lc15bts_led.c \ - misc/lc15bts_bts.c + misc/lc15bts_bts.c \ + misc/lc15bts_swd.c -lc15bts_mgr_LDADD = $(top_builddir)/src/common/libbts.a $(LIBGPS_LIBS) $(LIBOSMOCORE_LIBS) $(LIBOSMOVTY_LIBS) $(LIBOSMOABIS_LIBS) $(LIBOSMOGSM_LIBS) $(LIBOSMOCTRL_LIBS) $(COMMON_LDADD) +lc15bts_mgr_LDADD = $(top_builddir)/src/common/libbts.a $(LIBGPS_LIBS) $(LIBOSMOCORE_LIBS) $(LIBOSMOVTY_LIBS) $(LIBOSMOABIS_LIBS) $(LIBOSMOGSM_LIBS) $(LIBOSMOCTRL_LIBS) $(LIBSYSTEMD_LIBS) $(COMMON_LDADD) lc15bts_util_SOURCES = misc/lc15bts_util.c misc/lc15bts_par.c lc15bts_util_LDADD = $(LIBOSMOCORE_LIBS) diff --git a/src/osmo-bts-litecell15/calib_file.c b/src/osmo-bts-litecell15/calib_file.c index ac39e464..b7049df1 100644 --- a/src/osmo-bts-litecell15/calib_file.c +++ b/src/osmo-bts-litecell15/calib_file.c @@ -42,10 +42,9 @@ #include "lc15bts.h" #include "utils.h" -/** - * * Maximum calibration data chunk size - * */ +/* Maximum calibration data chunk size */ #define MAX_CALIB_TBL_SIZE 65536 +/* Calibration header version */ #define CALIB_HDR_V1 0x01 struct calib_file_desc { @@ -93,19 +92,19 @@ struct calTbl_t { struct { - uint8_t u8Version; // Header version (1) - uint8_t u8Parity; // Parity byte (xor) - uint8_t u8Type; // Table type (0:TX Downlink, 1:RX-A Uplink, 2:RX-B Uplink) - uint8_t u8Band; // GSM Band (0:GSM-850, 1:EGSM-900, 2:DCS-1800, 3:PCS-1900) - uint32_t u32Len; // Table length in bytes including the header + uint8_t u8Version; /* Header version (1) */ + uint8_t u8Parity; /* Parity byte (xor) */ + uint8_t u8Type; /* Table type (0:TX Downlink, 1:RX-A Uplink, 2:RX-B Uplink) */ + uint8_t u8Band; /* GSM Band (0:GSM-850, 1:EGSM-900, 2:DCS-1800, 3:PCS-1900) */ + uint32_t u32Len; /* Table length in bytes including the header */ struct { - uint32_t u32DescOfst; // Description section offset - uint32_t u32DateOfst; // Date section offset - uint32_t u32StationOfst; // Calibration test station section offset - uint32_t u32FpgaFwVerOfst; // Calibration FPGA firmware version section offset - uint32_t u32DspFwVerOfst; // Calibration DSP firmware section offset - uint32_t u32DataOfst; // Calibration data section offset + uint32_t u32DescOfst; /* Description section offset */ + uint32_t u32DateOfst; /* Date section offset */ + uint32_t u32StationOfst; /* Calibration test station section offset */ + uint32_t u32FpgaFwVerOfst; /* Calibration FPGA firmware version section offset */ + uint32_t u32DspFwVerOfst; /* Calibration DSP firmware section offset */ + uint32_t u32DataOfst; /* Calibration data section offset */ } toc; } v1; } hdr; @@ -314,15 +313,14 @@ static int calib_verify(struct lc15l1_hdl *fl1h, const struct calib_file_desc *d struct calTbl_t *calTbl; char calChkSum ; - - //calculate file size in bytes + /* calculate file size in bytes */ fseek(st->fp, 0L, SEEK_END); sz = ftell(st->fp); - //rewind read poiner + /* rewind read poiner */ fseek(st->fp, 0L, SEEK_SET); - //read file + /* read file */ rbuf = (char *) malloc( sizeof(char) * sz ); rc = fread(rbuf, 1, sizeof(char) * sz, st->fp); @@ -331,7 +329,7 @@ static int calib_verify(struct lc15l1_hdl *fl1h, const struct calib_file_desc *d LOGP(DL1C, LOGL_ERROR, "%s reading error\n", desc->fname); free(rbuf); - //close file + /* close file */ rc = calib_file_close(fl1h); if (rc < 0 ) { LOGP(DL1C, LOGL_ERROR, "%s can not close\n", desc->fname); @@ -341,33 +339,32 @@ static int calib_verify(struct lc15l1_hdl *fl1h, const struct calib_file_desc *d return -2; } - calTbl = (struct calTbl_t*) rbuf; - //calcualte file checksum + /* calculate file checksum */ calChkSum = 0; while ( sz-- ) { calChkSum ^= rbuf[sz]; } - //validate Tx calibration parity + /* validate Tx calibration parity */ if ( calChkSum ) { LOGP(DL1C, LOGL_ERROR, "%s has invalid checksum %x.\n", desc->fname, calChkSum); return -4; } - //validate Tx calibration header + /* validate Tx calibration header */ if ( calTbl->hdr.v1.u8Version != CALIB_HDR_V1 ) { LOGP(DL1C, LOGL_ERROR, "%s has invalid header version %u.\n", desc->fname, calTbl->hdr.v1.u8Version); return -5; } - //validate calibration description + /* validate calibration description */ if ( calTbl->hdr.v1.toc.u32DescOfst == 0xFFFFFFFF ) { LOGP(DL1C, LOGL_ERROR, "%s has invalid calibration description offset.\n", desc->fname); return -6; } - //validate calibration date + /* validate calibration date */ if ( calTbl->hdr.v1.toc.u32DateOfst == 0xFFFFFFFF ) { LOGP(DL1C, LOGL_ERROR, "%s has invalid calibration date offset.\n", desc->fname); return -7; @@ -377,24 +374,25 @@ static int calib_verify(struct lc15l1_hdl *fl1h, const struct calib_file_desc *d desc->fname, calTbl->u8RawData + calTbl->hdr.v1.toc.u32DateOfst); - //validate calibration station + /* validate calibration station */ if ( calTbl->hdr.v1.toc.u32StationOfst == 0xFFFFFFFF ) { LOGP(DL1C, LOGL_ERROR, "%s has invalid calibration station ID offset.\n", desc->fname); return -8; } - //validate FPGA FW version + /* validate FPGA FW version */ if ( calTbl->hdr.v1.toc.u32FpgaFwVerOfst == 0xFFFFFFFF ) { LOGP(DL1C, LOGL_ERROR, "%s has invalid FPGA FW version offset.\n", desc->fname); return -9; } - //validate DSP FW version + + /* validate DSP FW version */ if ( calTbl->hdr.v1.toc.u32DspFwVerOfst == 0xFFFFFFFF ) { LOGP(DL1C, LOGL_ERROR, "%s has invalid DSP FW version offset.\n", desc->fname); return -10; } - //validate Tx calibration data offset + /* validate Tx calibration data offset */ if ( calTbl->hdr.v1.toc.u32DataOfst == 0xFFFFFFFF ) { LOGP(DL1C, LOGL_ERROR, "%s has invalid calibration data offset.\n", desc->fname); return -11; @@ -402,11 +400,11 @@ static int calib_verify(struct lc15l1_hdl *fl1h, const struct calib_file_desc *d if ( !desc->rx ) { - //parse min/max Tx power + /* parse min/max Tx power */ fl1h->phy_inst->u.lc15.minTxPower = calTbl->u8RawData[calTbl->hdr.v1.toc.u32DataOfst + (5 << 2)]; fl1h->phy_inst->u.lc15.maxTxPower = calTbl->u8RawData[calTbl->hdr.v1.toc.u32DataOfst + (6 << 2)]; - //override nominal Tx power of given TRX if needed + /* override nominal Tx power of given TRX if needed */ if ( fl1h->phy_inst->trx->nominal_power > fl1h->phy_inst->u.lc15.maxTxPower) { LOGP(DL1C, LOGL_INFO, "Set TRX %u nominal Tx power to %d dBm (%d)\n", plink->num, @@ -449,7 +447,7 @@ static int calib_verify(struct lc15l1_hdl *fl1h, const struct calib_file_desc *d fl1h->phy_inst->u.lc15.maxTxPower ); } - //rewind read poiner for subsequence tasks + /* rewind read pointer for subsequence tasks */ fseek(st->fp, 0L, SEEK_SET); free(rbuf); 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 @@ -41,10 +44,14 @@ #include #include +#include + 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 @@ -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 + * + * 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 . + * + */ + +#include "misc/lc15bts_mgr.h" +#include "misc/lc15bts_swd.h" +#include + +/* Needed for service watchdog notification */ +#include + +/* 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 -- cgit v1.2.3