Files
Oliver Smith f721e69bc1 treewide: remove FSF address
Remove the paragraph about writing to the Free Software Foundation's
mailing address. The FSF has changed addresses in the past, and may do
so again. In 2021 this is not useful, let's rather have a bit less
boilerplate at the start of source files.

Change-Id: Ie0a3b2273383adbb3303faffd6ff96be7f4cae99
2021-12-14 11:47:21 +01:00

301 lines
6.3 KiB
C

/* LED control
*
* (C) 2015-2017 by Harald Welte <hwelte@hmw-consulting.de>
* (C) 2018 by sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 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.
*/
#include <stdint.h>
#include <string.h>
#include <assert.h>
#include <osmocom/core/timer.h>
#include "board.h"
#include "utils.h"
#include "led.h"
#ifdef PINS_LEDS
static const Pin pinsLeds[] = { PINS_LEDS } ;
static void led_set(enum led led, int on)
{
ASSERT(led < PIO_LISTSIZE(pinsLeds));
if (on)
PIO_Clear(&pinsLeds[led]);
else
PIO_Set(&pinsLeds[led]);
}
/* LED blinking code */
/* a single state in a sequence of blinking */
struct blink_state {
/* duration of the state in ms */
uint16_t duration;
/* brightness of LED during the state */
uint8_t on;
} __attribute__((packed));
static const struct blink_state bs_off[] = {
{ 0, 0 }
};
static const struct blink_state bs_on[] = {
{ 0, 1 }
};
static const struct blink_state bs_5on_5off[] = {
{ 500, 1 }, { 500, 0 }
};
static const struct blink_state bs_3on_5off[] = {
{ 300, 1 }, { 500, 0 }
};
static const struct blink_state bs_3on_30off[] = {
{ 300, 1 }, { 3000, 0 }
};
static const struct blink_state bs_3on_1off_3on_30off[] = {
{ 300, 1 }, { 100, 0 }, { 300, 1 }, { 3000, 0 }
};
static const struct blink_state bs_3on_1off_3on_1off_3on_30off[] = {
{ 300, 1 }, { 100, 0 }, { 300, 1 }, { 100, 0 }, { 300, 1 }, { 3000, 0 }
};
static const struct blink_state bs_2on_off[] = {
{ 200, 1 }, { 0, 0 },
};
static const struct blink_state bs_200on_off[] = {
{ 20000, 1 }, { 0, 0 },
};
static const struct blink_state bs_600on_off[] = {
{ 60000, 1 }, { 0, 0 },
};
static const struct blink_state bs_2off_on[] = {
{ 200, 0 }, { 0, 1 },
};
/* a blink pattern is an array of blink_states */
struct blink_pattern {
const struct blink_state *states;
uint16_t size;
};
/* compiled-in default blinking patterns */
static const struct blink_pattern patterns[] = {
[BLINK_ALWAYS_OFF] = {
.states = bs_off,
.size = ARRAY_SIZE(bs_off),
},
[BLINK_ALWAYS_ON] = {
.states = bs_on,
.size = ARRAY_SIZE(bs_on),
},
[BLINK_5O_5F] = {
.states = bs_5on_5off,
.size = ARRAY_SIZE(bs_5on_5off),
},
[BLINK_3O_5F] = {
.states = bs_3on_5off,
.size = ARRAY_SIZE(bs_3on_5off),
},
[BLINK_3O_30F] = {
.states = bs_3on_30off,
.size = ARRAY_SIZE(bs_3on_30off),
},
[BLINK_3O_1F_3O_30F] = {
.states = bs_3on_1off_3on_30off,
.size = ARRAY_SIZE(bs_3on_1off_3on_30off),
},
[BLINK_3O_1F_3O_1F_3O_30F] = {
.states = bs_3on_1off_3on_1off_3on_30off,
.size = ARRAY_SIZE(bs_3on_1off_3on_1off_3on_30off),
},
[BLINK_2O_F] = {
.states = bs_2on_off,
.size = ARRAY_SIZE(bs_2on_off),
},
[BLINK_200O_F] = {
.states = bs_200on_off,
.size = ARRAY_SIZE(bs_200on_off),
},
[BLINK_600O_F] = {
.states = bs_600on_off,
.size = ARRAY_SIZE(bs_600on_off),
},
[BLINK_2F_O] = {
.states = bs_2off_on,
.size = ARRAY_SIZE(bs_2off_on),
},
};
struct led_state {
/* which led are we handling */
enum led led;
/* timer */
struct osmo_timer_list timer;
/* pointer and size of blink array */
const struct blink_pattern *pattern;
unsigned int cur_state;
unsigned int illuminated;
/* static allocated space for custom blinking pattern */
struct blink_pattern pattern_cust;
struct blink_state blink_cust[10];
};
static unsigned int cur_state_inc(struct led_state *ls)
{
ls->cur_state = (ls->cur_state + 1) % ls->pattern->size;
return ls->cur_state;
}
static const struct blink_state *
next_blink_state(struct led_state *ls)
{
return &ls->pattern->states[cur_state_inc(ls)];
}
/* apply the next state to the LED */
static void apply_blinkstate(struct led_state *ls,
const struct blink_state *bs)
{
led_set(ls->led, bs->on);
ls->illuminated = bs->on;
/* re-schedule the timer */
if (bs->duration) {
uint32_t us = bs->duration * 1000;
osmo_timer_schedule(&ls->timer, us / 1000000, us % 1000000);
}
}
static void blink_tmr_cb(void *data)
{
struct led_state *ls = data;
const struct blink_state *next_bs = next_blink_state(ls);
/* apply the next state to the LED */
apply_blinkstate(ls, next_bs);
}
static struct led_state led_state[] = {
[LED_RED] = {
.led = LED_RED,
.timer.cb = blink_tmr_cb,
.timer.data = &led_state[LED_RED],
},
[LED_GREEN] = {
.led = LED_GREEN,
.timer.cb = blink_tmr_cb,
.timer.data = &led_state[LED_GREEN],
},
};
#endif /* PINS_LEDS */
void led_blink(enum led led, enum led_pattern blink)
{
#ifdef PINS_LEDS
struct led_state *ls;
if (led >= ARRAY_SIZE(led_state))
return;
ls = &led_state[led];
/* stop previous blinking, if any */
osmo_timer_del(&ls->timer);
led_set(led, 0);
ls->illuminated = 0;
ls->pattern = NULL;
ls->cur_state = 0;
switch (blink) {
case BLINK_CUSTOM:
ls->pattern = &ls->pattern_cust;
break;
default:
if (blink >= ARRAY_SIZE(patterns))
return;
ls->pattern = &patterns[blink];
break;
}
if (ls->pattern && ls->pattern->size > 0)
apply_blinkstate(ls, &ls->pattern->states[0]);
#endif
}
enum led_pattern led_get(enum led led)
{
#ifdef PINS_LEDS
struct led_state *ls;
unsigned int i;
if (led >= ARRAY_SIZE(led_state))
return -1;
ls = &led_state[led];
if (ls->pattern == &ls->pattern_cust)
return BLINK_CUSTOM;
for (i = 0; i < ARRAY_SIZE(patterns); i++) {
if (ls->pattern == &patterns[i])
return i;
}
#endif
/* default case, shouldn't be reached */
return -1;
}
void led_start(void)
{
led_set(LED_GREEN, led_state[LED_GREEN].illuminated);
led_set(LED_RED, led_state[LED_RED].illuminated);
}
void led_stop(void)
{
led_set(LED_GREEN, 0);
led_set(LED_RED, 0);
}
void led_init(void)
{
#ifdef PINS_LEDS
PIO_Configure(pinsLeds, PIO_LISTSIZE(pinsLeds));
led_set(LED_GREEN, 0);
led_set(LED_RED, 0);
#endif
}
void led_fini(void)
{
#ifdef PINS_LEDS
/* we don't actually need to do this, but just in case... */
osmo_timer_del(&led_state[LED_RED].timer);
osmo_timer_del(&led_state[LED_GREEN].timer);
led_set(LED_GREEN, 0);
led_set(LED_RED, 0);
#endif
}