Review at  https://gerrit.osmocom.org/3316

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#3679
---
M configure.ac
M src/osmo-bts-litecell15/Makefile.am
M src/osmo-bts-litecell15/calib_file.c
M src/osmo-bts-litecell15/misc/lc15bts_mgr.c
M src/osmo-bts-litecell15/misc/lc15bts_mgr_calib.c
M src/osmo-bts-litecell15/misc/lc15bts_mgr_temp.c
A src/osmo-bts-litecell15/misc/lc15bts_swd.c
A src/osmo-bts-litecell15/misc/lc15bts_swd.h
8 files changed, 327 insertions(+), 85 deletions(-)


  git pull ssh://gerrit.osmocom.org:29418/osmo-bts refs/changes/16/3316/1

diff --git a/configure.ac b/configure.ac
index 0ceb8eb..bc36456 100644
--- a/configure.ac
+++ b/configure.ac
@@ -143,6 +143,7 @@
        AC_CHECK_HEADER([nrw/litecell15/litecell15.h],[],
                        [AC_MSG_ERROR([nrw/litecell15/litecell15.h can not be 
found in $litecell15_incdir])],
                        [#include <nrw/litecell15/litecell15.h>])
+       PKG_CHECK_MODULES(LIBSYSTEMD, libsystemd)
        CPPFLAGS=$oldCPPFLAGS
 fi
 
diff --git a/src/osmo-bts-litecell15/Makefile.am 
b/src/osmo-bts-litecell15/Makefile.am
index 90e6c46..78a770a 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 @@
                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 ac39e46..b7049df 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
         {
-            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 @@
        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 @@
                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 @@
                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 @@
                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 @@
 
        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 @@
                                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 51a05f9..cec9a82 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 @@
        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 @@
 
        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 @@
        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 @@
        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 fb49477..badb545 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,9 +44,13 @@
 #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,
@@ -88,7 +95,9 @@
        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,11 +108,31 @@
                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) {
@@ -113,60 +142,74 @@
                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);
-                               calib_state_reset(mgr, CALIB_FAIL_CLKERR);
-                       return;
-               }
-       } 
+                       new_dac_value = 0;
 
-       /* 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);
+               /* 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;
+                       }
                }
-               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 @@
                 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 @@
        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 9d2dfec..9665e1d 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 @@
                 * 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 @@
                 * 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 @@
        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 0000000..59c7b61
--- /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 <[email protected]>
+ *
+ * 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 0000000..b78a2c2
--- /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

-- 
To view, visit https://gerrit.osmocom.org/3316
To unsubscribe, visit https://gerrit.osmocom.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I475a330af771891ba3c897294ce0dd57ec2ba8db
Gerrit-PatchSet: 1
Gerrit-Project: osmo-bts
Gerrit-Branch: master
Gerrit-Owner: Max <[email protected]>

Reply via email to