diff --git a/.gitignore b/.gitignore index e62fc8392..63bd30bfa 100644 --- a/.gitignore +++ b/.gitignore @@ -20,6 +20,7 @@ contrib/sysmobts-calib/sysmobts-calib src/osmo-bts-sysmo/l1fwd-proxy src/osmo-bts-sysmo/sysmobts src/osmo-bts-sysmo/sysmobts-remote +src/osmo-bts-sysmo/sysmobts-mgr tests/atconfig diff --git a/src/osmo-bts-sysmo/Makefile.am b/src/osmo-bts-sysmo/Makefile.am index ab3e706f7..e69ee2ac9 100644 --- a/src/osmo-bts-sysmo/Makefile.am +++ b/src/osmo-bts-sysmo/Makefile.am @@ -2,7 +2,9 @@ INCLUDES = $(all_includes) -I$(top_srcdir)/include AM_CFLAGS = -Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOVTY_CFLAGS) $(LIBOSMOTRAU_CFLAGS) LDADD = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(LIBOSMOVTY_LIBS) $(LIBOSMOTRAU_LIBS) -lortp -bin_PROGRAMS = sysmobts sysmobts-remote l1fwd-proxy +EXTRA_DIST = misc/sysmobts_mgr.h misc/sysmobts_misc.h misc/sysmobts_par.h misc/sysmobts_eeprom.h + +bin_PROGRAMS = sysmobts sysmobts-remote l1fwd-proxy sysmobts-mgr COMMON_SOURCES = main.c femtobts.c l1_if.c oml.c sysmobts_vty.c tch.c hw_misc.c @@ -14,3 +16,5 @@ sysmobts_remote_LDADD = $(top_builddir)/src/common/libbts.a $(LDADD) l1fwd_proxy_SOURCES = l1_fwd_main.c l1_transp_hw.c l1fwd_proxy_LDADD = $(top_builddir)/src/common/libbts.a $(LDADD) + +sysmobts_mgr_SOURCES = misc/sysmobts_mgr.c misc/sysmobts_misc.c misc/sysmobts_par.c diff --git a/src/osmo-bts-sysmo/misc/sysmobts_eeprom.h b/src/osmo-bts-sysmo/misc/sysmobts_eeprom.h new file mode 100644 index 000000000..4d27d0289 --- /dev/null +++ b/src/osmo-bts-sysmo/misc/sysmobts_eeprom.h @@ -0,0 +1,19 @@ +#ifndef _SYSMOBTS_EEPROM_H +#define _SYSMOBTS_EEPROM_H + +#include + +struct sysmobts_eeprom { /* offset */ + uint8_t eth_mac[6]; /* 0-5 */ + uint8_t _pad0[10]; /* 6-15 */ + uint16_t clk_cal_fact; /* 16-17 */ + uint8_t temp1_max; /* 18 */ + uint8_t temp2_max; /* 19 */ + uint32_t serial_nr; /* 20-23 */ + uint32_t operational_hours; /* 24-27 */ + uint32_t boot_count; /* 28-31 */ + uint8_t _pad1[89]; /* 32-127 */ + uint8_t gpg_key[128]; /* 121-249 */ +} __attribute__((packed)); + +#endif diff --git a/src/osmo-bts-sysmo/misc/sysmobts_mgr.c b/src/osmo-bts-sysmo/misc/sysmobts_mgr.c new file mode 100644 index 000000000..01d65ce76 --- /dev/null +++ b/src/osmo-bts-sysmo/misc/sysmobts_mgr.c @@ -0,0 +1,163 @@ +/* Main program for SysmoBTS management daemon */ + +/* (C) 2012 by Harald Welte + * + * All Rights Reserved + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "misc/sysmobts_misc.h" +#include "misc/sysmobts_mgr.h" + +static int daemonize = 0; +void *tall_mgr_ctx; + +/* every 6 hours means 365*4 = 1460 EEprom writes per year (max) */ +#define TEMP_TIMER_SECS (6 * 3600) + +/* every 1 hours means 365*24 = 8760 EEprom writes per year (max) */ +#define HOURS_TIMER_SECS (1 * 3600) + +static struct osmo_timer_list temp_timer; +static void check_temp_timer_cb(void *unused) +{ + sysmobts_check_temp(); + + osmo_timer_schedule(&temp_timer, TEMP_TIMER_SECS, 0); +} + +static struct osmo_timer_list hours_timer; +static void hours_timer_cb(void *unused) +{ + sysmobts_update_hours(); + + osmo_timer_schedule(&hours_timer, HOURS_TIMER_SECS, 0); +} + +static void signal_handler(int signal) +{ + fprintf(stderr, "signal %u received\n", signal); + + switch (signal) { + case SIGINT: + sysmobts_check_temp(); + sysmobts_update_hours(); + exit(0); + break; + case SIGABRT: + case SIGUSR1: + case SIGUSR2: + talloc_report_full(tall_mgr_ctx, stderr); + break; + default: + break; + } +} + +#include +#include +#include + +#include +#include + +static struct log_info_cat mgr_log_info_cat[] = { + [DTEMP] = { + .name = "DTEMP", + .description = "Temperature monitoring", + .color = "\033[1;35m", + .enabled = 1, .loglevel = LOGL_INFO, + }, + [DFW] = { + .name = "DFW", + .description = "DSP/FPGA firmware management", + .color = "\033[1;36m", + .enabled = 1, .loglevel = LOGL_INFO, + }, +}; + +static const struct log_info mgr_log_info = { + .cat = mgr_log_info_cat, + .num_cat = ARRAY_SIZE(mgr_log_info_cat), +}; + +static int mgr_log_init(const char *category_mask) +{ + osmo_init_logging(&mgr_log_info); + + if (category_mask) + log_parse_category_mask(osmo_stderr_target, category_mask); + + return 0; +} + +int main(int argc, char **argv) +{ + void *tall_msgb_ctx; + int rc; + + tall_mgr_ctx = talloc_named_const(NULL, 1, "bts manager"); + tall_msgb_ctx = talloc_named_const(tall_mgr_ctx, 1, "msgb"); + msgb_set_talloc_ctx(tall_msgb_ctx); + + //handle_options(argc, argv); + + mgr_log_init(NULL); + + signal(SIGINT, &signal_handler); + //signal(SIGABRT, &signal_handler); + signal(SIGUSR1, &signal_handler); + signal(SIGUSR2, &signal_handler); + osmo_init_ignore_signals(); + + if (daemonize) { + rc = osmo_daemonize(); + if (rc < 0) { + perror("Error during daemonize"); + exit(1); + } + } + + /* start temperature check timer */ + temp_timer.cb = check_temp_timer_cb; + check_temp_timer_cb(NULL); + + /* start operational hours timer */ + hours_timer.cb = hours_timer_cb; + hours_timer_cb(NULL); + + while (1) { + log_reset_context(); + osmo_select_main(0); + } +} diff --git a/src/osmo-bts-sysmo/misc/sysmobts_mgr.h b/src/osmo-bts-sysmo/misc/sysmobts_mgr.h new file mode 100644 index 000000000..3b948b1c9 --- /dev/null +++ b/src/osmo-bts-sysmo/misc/sysmobts_mgr.h @@ -0,0 +1,9 @@ +#ifndef _SYSMOBTS_MGR_H +#define _SYSMOBTS_MGR_H + +enum { + DTEMP, + DFW, +}; + +#endif diff --git a/src/osmo-bts-sysmo/misc/sysmobts_misc.c b/src/osmo-bts-sysmo/misc/sysmobts_misc.c new file mode 100644 index 000000000..266eb00b9 --- /dev/null +++ b/src/osmo-bts-sysmo/misc/sysmobts_misc.c @@ -0,0 +1,268 @@ +/* (C) 2012 by Harald Welte + * + * All Rights Reserved + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "sysmobts_misc.h" +#include "sysmobts_par.h" +#include "sysmobts_mgr.h" + + +/********************************************************************* + * Temperature handling + *********************************************************************/ + +#define TEMP_PATH "/sys/class/hwmon/hwmon0/device%u_%s" + +static const char *temp_type_str[_NUM_TEMP_TYPES] = { + [SYSMOBTS_TEMP_INPUT] = "input", + [SYSMOBTS_TEMP_LOWEST] = "lowest", + [SYSMOBTS_TEMP_HIGHEST] = "highest", +}; + +int sysmobts_temp_get(enum sysmobts_temp_sensor sensor, + enum sysmobts_temp_type type) +{ + char buf[PATH_MAX]; + char tempstr[8]; + int fd, rc; + + if (sensor < SYSMOBTS_TEMP_DIGITAL || + sensor > SYSMOBTS_TEMP_RF) + return -EINVAL; + + if (type > _NUM_TEMP_TYPES) + return -EINVAL; + + snprintf(buf, sizeof(buf)-1, TEMP_PATH, sensor, temp_type_str[type]); + buf[sizeof(buf)-1] = '\0'; + + fd = open(buf, O_RDONLY); + if (fd < 0) + return fd; + + rc = read(fd, tempstr, sizeof(tempstr)); + tempstr[sizeof(tempstr)-1] = '\0'; + if (rc < 0) { + close(fd); + return rc; + } + if (rc == 0) { + close(fd); + return -EIO; + } + + close(fd); + + return atoi(tempstr); +} + +static const struct { + const char *name; + enum sysmobts_temp_sensor sensor; + enum sysmobts_par ee_par; +} temp_data[] = { + { + .name = "digital", + .sensor = SYSMOBTS_TEMP_DIGITAL, + .ee_par = SYSMOBTS_PAR_TEMP_DIG_MAX, + }, { + .name = "rf", + .sensor = SYSMOBTS_TEMP_RF, + .ee_par = SYSMOBTS_PAR_TEMP_RF_MAX, + } +}; + +void sysmobts_check_temp(void) +{ + int temp_old[ARRAY_SIZE(temp_data)]; + int temp_hi[ARRAY_SIZE(temp_data)]; + int temp_cur[ARRAY_SIZE(temp_data)]; + int i, rc; + + for (i = 0; i < ARRAY_SIZE(temp_data); i++) { + temp_old[i] = sysmobts_par_get_int(temp_data[i].ee_par) * 1000; + temp_hi[i] = sysmobts_temp_get(temp_data[i].sensor, + SYSMOBTS_TEMP_HIGHEST); + temp_cur[i] = sysmobts_temp_get(temp_data[i].sensor, + SYSMOBTS_TEMP_INPUT); + + if ((temp_cur[i] < 0 && temp_cur[i] > -1000) || + (temp_hi[i] < 0 && temp_hi[i] > -1000)) { + LOGP(DTEMP, LOGL_ERROR, "Error reading temperature\n"); + return; + } + + LOGP(DTEMP, LOGL_DEBUG, "Current %s temperature: %d.%d C\n", + temp_data[i].name, temp_cur[i]/1000, temp_cur[i]%1000); + + if (temp_hi[i] > temp_old[i]) { + LOGP(DTEMP, LOGL_NOTICE, "New maximum %s " + "temperature: %d.%d C\n", temp_data[i].name, + temp_hi[i]/1000, temp_hi[i]%1000); + rc = sysmobts_par_set_int(SYSMOBTS_PAR_TEMP_DIG_MAX, + temp_hi[0]/1000); + if (rc < 0) + LOGP(DTEMP, LOGL_ERROR, "error writing new %s " + "max temp %d (%s)\n", temp_data[i].name, + rc, strerror(errno)); + } + } +} + +/********************************************************************* + * Hours handling + *********************************************************************/ +static time_t last_update; + +int sysmobts_update_hours(void) +{ + time_t now = time(NULL); + int op_hrs; + + /* first time after start of manager program */ + if (last_update == 0) { + last_update = now; + + op_hrs = sysmobts_par_get_int(SYSMOBTS_PAR_HOURS); + if (op_hrs < 0) { + LOGP(DTEMP, LOGL_ERROR, "Unable to read " + "operational hours: %d (%s)\n", op_hrs, + strerror(errno)); + return op_hrs; + } + + LOGP(DTEMP, LOGL_INFO, "Total hours of Operation: %u\n", + op_hrs); + + return 0; + } + + if (now >= last_update + 3600) { + int rc; + op_hrs = sysmobts_par_get_int(SYSMOBTS_PAR_HOURS); + if (op_hrs < 0) { + LOGP(DTEMP, LOGL_ERROR, "Unable to read " + "operational hours: %d (%s)\n", op_hrs, + strerror(errno)); + return op_hrs; + } + + /* number of hours to increase */ + op_hrs += (now-last_update)/3600; + + LOGP(DTEMP, LOGL_INFO, "Total hours of Operation: %u\n", + op_hrs); + + rc = sysmobts_par_set_int(SYSMOBTS_PAR_HOURS, op_hrs); + if (rc < 0) + return rc; + + last_update = now; + } + + return 0; +} + +/********************************************************************* + * Firmware reloading + *********************************************************************/ + +#define SYSMOBTS_FW_PATH "/lib/firmware" + +static const char *fw_names[_NUM_FW] = { + [SYSMOBTS_FW_FPGA] = "sysmobts-v2.bit", + [SYSMOBTS_FW_DSP] = "sysmobts-v2.out", +}; +static const char *fw_devs[_NUM_FW] = { + [SYSMOBTS_FW_FPGA] = "/dev/fpgadl_par0", + [SYSMOBTS_FW_DSP] = "/dev/dspdl_dm644x_0", +}; + +int sysmobts_firmware_reload(enum sysmobts_firmware_type type) +{ + char name[PATH_MAX]; + uint8_t buf[1024]; + int fd_in, fd_out, rc; + + if (type >= _NUM_FW) + return -EINVAL; + + snprintf(name, sizeof(name)-1, "%s/%s", + SYSMOBTS_FW_PATH, fw_names[type]); + name[sizeof(name)-1] = '\0'; + + fd_in = open(name, O_RDONLY); + if (fd_in < 0) { + LOGP(DFW, LOGL_ERROR, "unable ot open firmware file %s: %s\n", + name, strerror(errno)); + return fd_in; + } + + fd_out = open(fw_devs[type], O_WRONLY); + if (fd_out < 0) { + LOGP(DFW, LOGL_ERROR, "unable ot open firmware device %s: %s\n", + fw_devs[type], strerror(errno)); + close(fd_in); + return fd_out; + } + + while ((rc = read(fd_in, buf, sizeof(buf)))) { + int written; + + if (rc < 0) { + LOGP(DFW, LOGL_ERROR, "error %d during read " + "from %s: %s\n", rc, name, strerror(errno)); + close(fd_in); + close(fd_out); + return -EIO; + } + + written = write(fd_out, buf, rc); + if (written < rc) { + LOGP(DFW, LOGL_ERROR, "short write during " + "fw write to %s\n", fw_devs[type]); + close(fd_in); + close(fd_out); + return -EIO; + } + } + + close(fd_in); + close(fd_out); + + return 0; +} diff --git a/src/osmo-bts-sysmo/misc/sysmobts_misc.h b/src/osmo-bts-sysmo/misc/sysmobts_misc.h new file mode 100644 index 000000000..13d0add3a --- /dev/null +++ b/src/osmo-bts-sysmo/misc/sysmobts_misc.h @@ -0,0 +1,31 @@ +#ifndef _SYSMOBTS_MISC_H +#define _SYSMOBTS_MISC_H + +enum sysmobts_temp_sensor { + SYSMOBTS_TEMP_DIGITAL = 1, + SYSMOBTS_TEMP_RF = 2, +}; + +enum sysmobts_temp_type { + SYSMOBTS_TEMP_INPUT, + SYSMOBTS_TEMP_LOWEST, + SYSMOBTS_TEMP_HIGHEST, + _NUM_TEMP_TYPES +}; + +int sysmobts_temp_get(enum sysmobts_temp_sensor sensor, + enum sysmobts_temp_type type); + +void sysmobts_check_temp(void); + +int sysmobts_update_hours(void); + +enum sysmobts_firmware_type { + SYSMOBTS_FW_FPGA, + SYSMOBTS_FW_DSP, + _NUM_FW +}; + +int sysmobts_firmware_reload(enum sysmobts_firmware_type type); + +#endif diff --git a/src/osmo-bts-sysmo/misc/sysmobts_par.c b/src/osmo-bts-sysmo/misc/sysmobts_par.c new file mode 100644 index 000000000..3399e4ff9 --- /dev/null +++ b/src/osmo-bts-sysmo/misc/sysmobts_par.c @@ -0,0 +1,226 @@ +/* sysmobts - access to hardware related parameters */ + +/* (C) 2012 by Harald Welte + * + * All Rights Reserved + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sysmobts_eeprom.h" +#include "sysmobts_par.h" + +#define EEPROM_PATH "/sys/devices/platform/i2c_davinci.1/i2c-1/1-0050/eeprom" + + +static struct { + int read; + struct sysmobts_eeprom ee; +} g_ee; + +static struct sysmobts_eeprom *get_eeprom(int update_rqd) +{ + if (update_rqd || g_ee.read == 0) { + int fd, rc; + + fd = open(EEPROM_PATH, O_RDONLY); + if (fd < 0) + return NULL; + + rc = read(fd, &g_ee.ee, sizeof(g_ee.ee)); + + close(fd); + + if (rc < sizeof(g_ee.ee)) + return NULL; + + g_ee.read = 1; + } + + return &g_ee.ee; +} + +static int set_eeprom(struct sysmobts_eeprom *ee) +{ + int fd, rc; + + memcpy(&g_ee.ee, ee, sizeof(*ee)); + + fd = open(EEPROM_PATH, O_WRONLY); + if (fd < 0) + return fd; + + rc = write(fd, ee, sizeof(*ee)); + if (rc < sizeof(*ee)) { + close(fd); + return -EIO; + } + + close(fd); + + return 0; +} + +int sysmobts_par_get_int(enum sysmobts_par par) +{ + int ret; + struct sysmobts_eeprom *ee = get_eeprom(0); + + if (!ee) + return -EIO; + + if (par >= _NUM_SYSMOBTS_PAR) + return -ENODEV; + + switch (par) { + case SYSMOBTS_PAR_CLK_FACTORY: + ret = ee->clk_cal_fact; + break; + case SYSMOBTS_PAR_TEMP_DIG_MAX: + ret = ee->temp1_max; + break; + case SYSMOBTS_PAR_TEMP_RF_MAX: + ret = ee->temp2_max; + break; + case SYSMOBTS_PAR_SERNR: + ret = ee->serial_nr; + break; + case SYSMOBTS_PAR_HOURS: + ret = ee->operational_hours; + break; + case SYSMOBTS_PAR_BOOTS: + ret = ee->boot_count; + break; + default: + return -EINVAL; + } + + return ret; +} + +int sysmobts_par_set_int(enum sysmobts_par par, unsigned int val) +{ + struct sysmobts_eeprom *ee = get_eeprom(1); + + if (!ee) + return -EIO; + + if (par >= _NUM_SYSMOBTS_PAR) + return -ENODEV; + + switch (par) { + case SYSMOBTS_PAR_CLK_FACTORY: + ee->clk_cal_fact = val; + break; + case SYSMOBTS_PAR_TEMP_DIG_MAX: + ee->temp1_max = val; + break; + case SYSMOBTS_PAR_TEMP_RF_MAX: + ee->temp2_max = val; + break; + case SYSMOBTS_PAR_SERNR: + ee->serial_nr = val; + break; + case SYSMOBTS_PAR_HOURS: + ee->operational_hours = val; + break; + case SYSMOBTS_PAR_BOOTS: + ee->boot_count = val; + break; + default: + return -EINVAL; + } + + set_eeprom(ee); + + return 0; +} + +int sysmobts_par_get_buf(enum sysmobts_par par, uint8_t *buf, + unsigned int size) +{ + uint8_t *ptr; + unsigned int len; + struct sysmobts_eeprom *ee = get_eeprom(0); + + if (!ee) + return -EIO; + + if (par >= _NUM_SYSMOBTS_PAR) + return -ENODEV; + + switch (par) { + case SYSMOBTS_PAR_MAC: + ptr = ee->eth_mac; + len = sizeof(ee->eth_mac); + break; + case SYSMOBTS_PAR_KEY: + ptr = ee->gpg_key; + len = sizeof(ee->gpg_key); + break; + default: + return -EINVAL; + } + + if (size < len) + len = size; + memcpy(buf, ptr, len); + + return len; +} + +int sysmobts_par_set_buf(enum sysmobts_par par, const uint8_t *buf, + unsigned int size) +{ + uint8_t *ptr; + unsigned int len; + struct sysmobts_eeprom *ee = get_eeprom(0); + + if (!ee) + return -EIO; + + if (par >= _NUM_SYSMOBTS_PAR) + return -ENODEV; + + switch (par) { + case SYSMOBTS_PAR_MAC: + ptr = ee->eth_mac; + len = sizeof(ee->eth_mac); + break; + case SYSMOBTS_PAR_KEY: + ptr = ee->gpg_key; + len = sizeof(ee->gpg_key); + break; + default: + return -EINVAL; + } + + if (len < size) + size = len; + + memcpy(ptr, buf, size); + + return len; +} diff --git a/src/osmo-bts-sysmo/misc/sysmobts_par.h b/src/osmo-bts-sysmo/misc/sysmobts_par.h new file mode 100644 index 000000000..85a38abca --- /dev/null +++ b/src/osmo-bts-sysmo/misc/sysmobts_par.h @@ -0,0 +1,26 @@ +#ifndef _SYSMOBTS_PAR_H +#define _SYSMOBTS_PAR_H + +#include + +enum sysmobts_par { + SYSMOBTS_PAR_MAC, + SYSMOBTS_PAR_CLK_FACTORY, + SYSMOBTS_PAR_TEMP_DIG_MAX, + SYSMOBTS_PAR_TEMP_RF_MAX, + SYSMOBTS_PAR_SERNR, + SYSMOBTS_PAR_HOURS, + SYSMOBTS_PAR_BOOTS, + SYSMOBTS_PAR_KEY, + _NUM_SYSMOBTS_PAR +}; + + +int sysmobts_par_get_int(enum sysmobts_par par); +int sysmobts_par_set_int(enum sysmobts_par par, unsigned int val); +int sysmobts_par_get_buf(enum sysmobts_par par, uint8_t *buf, + unsigned int size); +int sysmobts_par_set_buf(enum sysmobts_par par, const uint8_t *buf, + unsigned int size); + +#endif