diff options
Diffstat (limited to 'src/osmo-bts-oc2g/misc/oc2gbts_led.c')
-rw-r--r-- | src/osmo-bts-oc2g/misc/oc2gbts_led.c | 332 |
1 files changed, 332 insertions, 0 deletions
diff --git a/src/osmo-bts-oc2g/misc/oc2gbts_led.c b/src/osmo-bts-oc2g/misc/oc2gbts_led.c new file mode 100644 index 00000000..b8758b8e --- /dev/null +++ b/src/osmo-bts-oc2g/misc/oc2gbts_led.c @@ -0,0 +1,332 @@ +/* Copyright (C) 2016 by NuRAN Wireless <support@nuranwireless.com> + * + * 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 <http://www.gnu.org/licenses/>. + * + */ +#include "oc2gbts_led.h" +#include "oc2gbts_bts.h" +#include <osmocom/core/talloc.h> +#include <osmocom/core/linuxlist.h> + +static struct oc2gbts_led led_entries[] = { + { + .name = "led0", + .fullname = "led red", + .path = "/var/oc2g/leds/led0/brightness" + }, + { + .name = "led1", + .fullname = "led green", + .path = "/var/oc2g/leds/led1/brightness" + } +}; + +static const struct value_string oc2gbts_led_strs[] = { + { OC2GBTS_LED_RED, "LED red" }, + { OC2GBTS_LED_GREEN, "LED green" }, + { OC2GBTS_LED_ORANGE, "LED orange" }, + { OC2GBTS_LED_OFF, "LED off" }, + { 0, NULL } +}; + +static uint8_t led_priority[] = { + BLINK_PATTERN_INIT, + BLINK_PATTERN_INT_PROC_MALFUNC, + BLINK_PATTERN_SUPPLY_PWR_MAX, + BLINK_PATTERN_PA_PWR_MAX, + BLINK_PATTERN_VSWR_MAX, + BLINK_PATTERN_SUPPLY_VOLT_MIN, + BLINK_PATTERN_TEMP_MAX, + BLINK_PATTERN_EXT_LINK_MALFUNC, + BLINK_PATTERN_SUPPLY_VOLT_LOW, + BLINK_PATTERN_TEMP_HIGH, + BLINK_PATTERN_VSWR_HIGH, + BLINK_PATTERN_SUPPLY_PWR_HIGH, + BLINK_PATTERN_PA_PWR_HIGH, + BLINK_PATTERN_GPS_FIX_LOST, + BLINK_PATTERN_NORMAL +}; + + +char *blink_pattern_command[] = BLINK_PATTERN_COMMAND; + +static int oc2gbts_led_write(char *path, char *str) +{ + int fd; + + if ((fd = open(path, O_WRONLY)) == -1) + { + return 0; + } + + write(fd, str, strlen(str)+1); + close(fd); + return 1; +} + +static void led_set_red() +{ + oc2gbts_led_write(led_entries[0].path, "1"); + oc2gbts_led_write(led_entries[1].path, "0"); +} + +static void led_set_green() +{ + oc2gbts_led_write(led_entries[0].path, "0"); + oc2gbts_led_write(led_entries[1].path, "1"); +} + +static void led_set_orange() +{ + oc2gbts_led_write(led_entries[0].path, "1"); + oc2gbts_led_write(led_entries[1].path, "1"); +} + +static void led_set_off() +{ + oc2gbts_led_write(led_entries[0].path, "0"); + oc2gbts_led_write(led_entries[1].path, "0"); +} + +static void led_sleep( struct oc2gbts_mgr_instance *mgr, struct oc2gbts_led_timer *led_timer, void (*led_timer_cb)(void *_data)) { + /* Cancel any pending timer */ + osmo_timer_del(&led_timer->timer); + /* Start LED timer */ + led_timer->timer.cb = led_timer_cb; + led_timer->timer.data = mgr; + mgr->oc2gbts_leds.active_timer = led_timer->idx; + osmo_timer_schedule(&led_timer->timer, led_timer->param.sleep_sec, led_timer->param.sleep_usec); + LOGP(DTEMP, LOGL_DEBUG,"%s timer scheduled for %d sec + %d usec\n", + get_value_string(oc2gbts_led_strs, led_timer->idx), + led_timer->param.sleep_sec, + led_timer->param.sleep_usec); + + switch (led_timer->idx) { + case OC2GBTS_LED_RED: + led_set_red(); + break; + case OC2GBTS_LED_GREEN: + led_set_green(); + break; + case OC2GBTS_LED_ORANGE: + led_set_orange(); + break; + case OC2GBTS_LED_OFF: + led_set_off(); + break; + default: + led_set_off(); + } +} + +static void led_sleep_cb(void *_data) { + struct oc2gbts_mgr_instance *mgr = _data; + struct oc2gbts_led_timer_list *led_list; + + /* make sure the timer list is not empty */ + if (llist_empty(&mgr->oc2gbts_leds.list)) + return; + + llist_for_each_entry(led_list, &mgr->oc2gbts_leds.list, list) { + if (led_list->led_timer.idx == mgr->oc2gbts_leds.active_timer) { + LOGP(DTEMP, LOGL_DEBUG,"Delete expired %s timer %d sec + %d usec\n", + get_value_string(oc2gbts_led_strs, led_list->led_timer.idx), + led_list->led_timer.param.sleep_sec, + led_list->led_timer.param.sleep_usec); + + /* Delete current timer */ + osmo_timer_del(&led_list->led_timer.timer); + /* Rotate the timer list */ + llist_move_tail(led_list, &mgr->oc2gbts_leds.list); + break; + } + } + + /* Execute next timer */ + led_list = llist_first_entry(&mgr->oc2gbts_leds.list, struct oc2gbts_led_timer_list, list); + if (led_list) { + LOGP(DTEMP, LOGL_DEBUG,"Execute %s timer %d sec + %d usec, total entries=%d\n", + get_value_string(oc2gbts_led_strs, led_list->led_timer.idx), + led_list->led_timer.param.sleep_sec, + led_list->led_timer.param.sleep_usec, + llist_count(&mgr->oc2gbts_leds.list)); + + led_sleep(mgr, &led_list->led_timer, led_sleep_cb); + } + +} + +static void delete_led_timer_entries(struct oc2gbts_mgr_instance *mgr) +{ + struct oc2gbts_led_timer_list *led_list, *led_list2; + + if (llist_empty(&mgr->oc2gbts_leds.list)) + return; + + llist_for_each_entry_safe(led_list, led_list2, &mgr->oc2gbts_leds.list, list) { + /* Delete the timer in list */ + if (led_list) { + LOGP(DTEMP, LOGL_DEBUG,"Delete %s timer entry from list, %d sec + %d usec\n", + get_value_string(oc2gbts_led_strs, led_list->led_timer.idx), + led_list->led_timer.param.sleep_sec, + led_list->led_timer.param.sleep_usec); + + /* Delete current timer */ + osmo_timer_del(&led_list->led_timer.timer); + llist_del(&led_list->list); + talloc_free(led_list); + } + } + return; +} + +static int add_led_timer_entry(struct oc2gbts_mgr_instance *mgr, char *cmdstr) +{ + double sec, int_sec, frac_sec; + struct oc2gbts_sleep_time led_param; + + led_param.sleep_sec = 0; + led_param.sleep_usec = 0; + + if (strstr(cmdstr, "set red") != NULL) + mgr->oc2gbts_leds.led_idx = OC2GBTS_LED_RED; + else if (strstr(cmdstr, "set green") != NULL) + mgr->oc2gbts_leds.led_idx = OC2GBTS_LED_GREEN; + else if (strstr(cmdstr, "set orange") != NULL) + mgr->oc2gbts_leds.led_idx = OC2GBTS_LED_ORANGE; + else if (strstr(cmdstr, "set off") != NULL) + mgr->oc2gbts_leds.led_idx = OC2GBTS_LED_OFF; + else if (strstr(cmdstr, "sleep") != NULL) { + sec = atof(cmdstr + 6); + /* split time into integer and fractional of seconds */ + frac_sec = modf(sec, &int_sec) * 1000000.0; + led_param.sleep_sec = (int)int_sec; + led_param.sleep_usec = (int)frac_sec; + + if ((mgr->oc2gbts_leds.led_idx >= OC2GBTS_LED_RED) && (mgr->oc2gbts_leds.led_idx < _OC2GBTS_LED_MAX)) { + struct oc2gbts_led_timer_list *led_list; + + /* allocate timer entry */ + led_list = talloc_zero(tall_mgr_ctx, struct oc2gbts_led_timer_list); + if (led_list) { + led_list->led_timer.idx = mgr->oc2gbts_leds.led_idx; + led_list->led_timer.param.sleep_sec = led_param.sleep_sec; + led_list->led_timer.param.sleep_usec = led_param.sleep_usec; + llist_add_tail(&led_list->list, &mgr->oc2gbts_leds.list); + + LOGP(DTEMP, LOGL_DEBUG,"Add %s timer to list, %d sec + %d usec, total entries=%d\n", + get_value_string(oc2gbts_led_strs, mgr->oc2gbts_leds.led_idx), + led_list->led_timer.param.sleep_sec, + led_list->led_timer.param.sleep_usec, + llist_count(&mgr->oc2gbts_leds.list)); + } + } + } else + return -1; + + return 0; +} + +static int parse_led_pattern(char *pattern, struct oc2gbts_mgr_instance *mgr) +{ + char str[1024]; + char *pstr; + char *sep; + int rc = 0; + + strcpy(str, pattern); + pstr = str; + while ((sep = strsep(&pstr, ";")) != NULL) { + rc = add_led_timer_entry(mgr, sep); + if (rc < 0) { + break; + } + + } + return rc; +} + +/*** led interface ***/ + +void led_set(struct oc2gbts_mgr_instance *mgr, int pattern_id) +{ + int rc; + struct oc2gbts_led_timer_list *led_list; + + if (pattern_id > BLINK_PATTERN_MAX_ITEM - 1) { + LOGP(DTEMP, LOGL_ERROR, "Invalid LED pattern : %d. LED pattern must be between %d..%d\n", + pattern_id, + BLINK_PATTERN_POWER_ON, + BLINK_PATTERN_MAX_ITEM - 1); + return; + } + if (pattern_id == mgr->oc2gbts_leds.last_pattern_id) + return; + + mgr->oc2gbts_leds.last_pattern_id = pattern_id; + + LOGP(DTEMP, LOGL_INFO, "blink pattern command : %d\n", pattern_id); + LOGP(DTEMP, LOGL_INFO, "%s\n", blink_pattern_command[pattern_id]); + + /* Empty existing LED timer in the list */ + delete_led_timer_entries(mgr); + + /* parse LED pattern */ + rc = parse_led_pattern(blink_pattern_command[pattern_id], mgr); + if (rc < 0) { + LOGP(DTEMP, LOGL_ERROR,"LED pattern not found or invalid LED pattern\n"); + return; + } + + /* make sure the timer list is not empty */ + if (llist_empty(&mgr->oc2gbts_leds.list)) + return; + + /* Start the first LED timer in the list */ + led_list = llist_first_entry(&mgr->oc2gbts_leds.list, struct oc2gbts_led_timer_list, list); + if (led_list) { + LOGP(DTEMP, LOGL_DEBUG,"Execute timer %s for %d sec + %d usec\n", + get_value_string(oc2gbts_led_strs, led_list->led_timer.idx), + led_list->led_timer.param.sleep_sec, + led_list->led_timer.param.sleep_usec); + + led_sleep(mgr, &led_list->led_timer, led_sleep_cb); + } + +} + +void select_led_pattern(struct oc2gbts_mgr_instance *mgr) +{ + int i; + uint8_t led[BLINK_PATTERN_MAX_ITEM] = {0}; + + /* set normal LED pattern at first */ + led[BLINK_PATTERN_NORMAL] = 1; + + /* check on-board sensors for new LED pattern */ + check_sensor_led_pattern(mgr, led); + + /* check BTS status for new LED pattern */ + check_bts_led_pattern(led); + + /* check by priority */ + for (i = 0; i < sizeof(led_priority)/sizeof(uint8_t); i++) { + if(led[led_priority[i]] == 1) { + led_set(mgr, led_priority[i]); + break; + } + } +} |