/* Copyright (C) 2016 by NuRAN Wireless * * 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 Affero 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 "oc2gbts_led.h" #include "oc2gbts_bts.h" #include #include 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->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; } } }