aboutsummaryrefslogtreecommitdiffstats
path: root/src/osmo-bts-oc2g/misc/oc2gbts_led.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/osmo-bts-oc2g/misc/oc2gbts_led.c')
-rw-r--r--src/osmo-bts-oc2g/misc/oc2gbts_led.c332
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;
+ }
+ }
+}