Сохранить текущие изменения NAND и LED перед объединением веток
This commit is contained in:
246
c/led-indicator/led_indicator.c
Normal file
246
c/led-indicator/led_indicator.c
Normal file
@@ -0,0 +1,246 @@
|
||||
#include "led_indicator.h"
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#define LEVELS_1 0x01U
|
||||
#define LEVELS_10 0x01U
|
||||
#define LEVELS_1010 0x05U
|
||||
#define LEVELS_101010 0x15U
|
||||
|
||||
static const LedIndicator_Pattern g_default_patterns[LED_INDICATOR_MODE_COUNT] = {
|
||||
{{0U}, 0U, 1U, 1U, 0U},
|
||||
{{0U}, LEVELS_1, 1U, 1U, 1U},
|
||||
{{100U, 100U, 100U, 100U, 100U, 100U}, LEVELS_101010, 6U, 0U, 1U},
|
||||
{{100U, 900U}, LEVELS_10, 2U, 1U, 0U},
|
||||
{{50U, 50U}, LEVELS_10, 2U, 1U, 0U},
|
||||
{{250U, 250U}, LEVELS_10, 2U, 1U, 0U},
|
||||
{{100U, 100U, 100U, 700U}, LEVELS_1010, 4U, 1U, 0U},
|
||||
{{100U, 100U, 100U, 100U, 100U, 700U}, LEVELS_101010, 6U, 1U, 0U}
|
||||
};
|
||||
|
||||
static uint8_t pattern_valid(const LedIndicator_Pattern *pattern)
|
||||
{
|
||||
size_t i;
|
||||
uint32_t total = 0U;
|
||||
|
||||
if ((pattern == NULL) || (pattern->step_count == 0U) ||
|
||||
(pattern->step_count > LED_INDICATOR_MAX_STEPS)) {
|
||||
return 0U;
|
||||
}
|
||||
if (pattern->step_count == 1U) {
|
||||
return 1U;
|
||||
}
|
||||
for (i = 0U; i < pattern->step_count; ++i) {
|
||||
if ((pattern->duration_ms[i] == 0U) ||
|
||||
(UINT32_MAX - total < pattern->duration_ms[i])) {
|
||||
return 0U;
|
||||
}
|
||||
total += pattern->duration_ms[i];
|
||||
}
|
||||
return (uint8_t)(total != 0U);
|
||||
}
|
||||
|
||||
static uint32_t pattern_period(const LedIndicator_Pattern *pattern)
|
||||
{
|
||||
size_t i;
|
||||
uint32_t total = 0U;
|
||||
|
||||
for (i = 0U; i < pattern->step_count; ++i) {
|
||||
total += pattern->duration_ms[i];
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
static uint8_t pattern_level(const LedIndicator_Pattern *pattern, uint32_t elapsed)
|
||||
{
|
||||
uint32_t position = elapsed;
|
||||
uint32_t period;
|
||||
size_t i;
|
||||
|
||||
if (pattern->step_count == 1U) {
|
||||
return (uint8_t)(pattern->levels & 1U);
|
||||
}
|
||||
|
||||
period = pattern_period(pattern);
|
||||
if (pattern->repeat != 0U) {
|
||||
position %= period;
|
||||
} else if (position >= period) {
|
||||
return (uint8_t)(pattern->final_level != 0U);
|
||||
}
|
||||
|
||||
for (i = 0U; i < pattern->step_count; ++i) {
|
||||
if (position < pattern->duration_ms[i]) {
|
||||
return (uint8_t)((pattern->levels >> i) & 1U);
|
||||
}
|
||||
position -= pattern->duration_ms[i];
|
||||
}
|
||||
return (uint8_t)(pattern->final_level != 0U);
|
||||
}
|
||||
|
||||
static void write_if_changed(LedIndicator *instance, size_t channel, uint8_t level,
|
||||
uint8_t force)
|
||||
{
|
||||
LedIndicator_Channel *state = &instance->channels[channel];
|
||||
|
||||
level = (uint8_t)(level != 0U);
|
||||
if ((force != 0U) || (state->output_level != level)) {
|
||||
state->output_level = level;
|
||||
instance->port.write(instance->port.context, (uint8_t)channel, level);
|
||||
}
|
||||
}
|
||||
|
||||
void LedIndicator_ConfigDefault(LedIndicator_Config *config)
|
||||
{
|
||||
if (config != NULL) {
|
||||
config->patterns = g_default_patterns;
|
||||
config->pattern_count = LED_INDICATOR_MODE_COUNT;
|
||||
}
|
||||
}
|
||||
|
||||
size_t LedIndicator_CopyDefaultPatterns(LedIndicator_Pattern *patterns, size_t capacity)
|
||||
{
|
||||
size_t i;
|
||||
size_t count = (size_t)LED_INDICATOR_MODE_COUNT;
|
||||
|
||||
if (patterns == NULL) {
|
||||
return 0U;
|
||||
}
|
||||
if (capacity < count) {
|
||||
count = capacity;
|
||||
}
|
||||
for (i = 0U; i < count; ++i) {
|
||||
patterns[i] = g_default_patterns[i];
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
uint8_t LedIndicator_ValidateConfig(const LedIndicator_Config *config)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if ((config == NULL) || (config->patterns == NULL) ||
|
||||
(config->pattern_count == 0U) ||
|
||||
(config->pattern_count > (size_t)LED_INDICATOR_MODE_COUNT)) {
|
||||
return 0U;
|
||||
}
|
||||
for (i = 0U; i < config->pattern_count; ++i) {
|
||||
if (pattern_valid(&config->patterns[i]) == 0U) {
|
||||
return 0U;
|
||||
}
|
||||
}
|
||||
return 1U;
|
||||
}
|
||||
|
||||
uint8_t LedIndicator_Init(LedIndicator *instance,
|
||||
LedIndicator_Channel *channels,
|
||||
size_t channel_count,
|
||||
const LedIndicator_Port *port,
|
||||
const LedIndicator_Config *config)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if ((instance == NULL) || (channels == NULL) || (channel_count == 0U) ||
|
||||
(channel_count > 256U) || (port == NULL) || (port->write == NULL) ||
|
||||
(LedIndicator_ValidateConfig(config) == 0U)) {
|
||||
return 0U;
|
||||
}
|
||||
|
||||
instance->port = *port;
|
||||
instance->patterns = config->patterns;
|
||||
instance->pattern_count = config->pattern_count;
|
||||
instance->channels = channels;
|
||||
instance->channel_count = channel_count;
|
||||
instance->initialized = 1U;
|
||||
|
||||
for (i = 0U; i < channel_count; ++i) {
|
||||
channels[i].mode = LED_INDICATOR_MODE_OFF;
|
||||
channels[i].started_ms = 0U;
|
||||
channels[i].output_level = 0U;
|
||||
channels[i].initialized = 1U;
|
||||
write_if_changed(instance, i, 0U, 1U);
|
||||
}
|
||||
return 1U;
|
||||
}
|
||||
|
||||
uint8_t LedIndicator_SetModeAt(LedIndicator *instance, size_t channel,
|
||||
LedIndicator_Mode mode, uint32_t now_ms)
|
||||
{
|
||||
if ((instance == NULL) || (instance->initialized == 0U) ||
|
||||
(channel >= instance->channel_count) || ((size_t)mode >= instance->pattern_count)) {
|
||||
return 0U;
|
||||
}
|
||||
if (instance->channels[channel].mode == mode) {
|
||||
return 1U;
|
||||
}
|
||||
return LedIndicator_RestartModeAt(instance, channel, mode, now_ms);
|
||||
}
|
||||
|
||||
uint8_t LedIndicator_RestartModeAt(LedIndicator *instance, size_t channel,
|
||||
LedIndicator_Mode mode, uint32_t now_ms)
|
||||
{
|
||||
LedIndicator_Channel *state;
|
||||
const LedIndicator_Pattern *pattern;
|
||||
|
||||
if ((instance == NULL) || (instance->initialized == 0U) ||
|
||||
(channel >= instance->channel_count) || ((size_t)mode >= instance->pattern_count)) {
|
||||
return 0U;
|
||||
}
|
||||
|
||||
state = &instance->channels[channel];
|
||||
state->mode = mode;
|
||||
state->started_ms = now_ms;
|
||||
pattern = &instance->patterns[(size_t)mode];
|
||||
write_if_changed(instance, channel, pattern_level(pattern, 0U), 0U);
|
||||
return 1U;
|
||||
}
|
||||
|
||||
uint8_t LedIndicator_SetMode(LedIndicator *instance, size_t channel,
|
||||
LedIndicator_Mode mode)
|
||||
{
|
||||
if ((instance == NULL) || (instance->port.now_ms == NULL)) {
|
||||
return 0U;
|
||||
}
|
||||
return LedIndicator_SetModeAt(instance, channel, mode,
|
||||
instance->port.now_ms(instance->port.context));
|
||||
}
|
||||
|
||||
uint8_t LedIndicator_RestartMode(LedIndicator *instance, size_t channel,
|
||||
LedIndicator_Mode mode)
|
||||
{
|
||||
if ((instance == NULL) || (instance->port.now_ms == NULL)) {
|
||||
return 0U;
|
||||
}
|
||||
return LedIndicator_RestartModeAt(instance, channel, mode,
|
||||
instance->port.now_ms(instance->port.context));
|
||||
}
|
||||
|
||||
void LedIndicator_ProcessAt(LedIndicator *instance, uint32_t now_ms)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if ((instance == NULL) || (instance->initialized == 0U)) {
|
||||
return;
|
||||
}
|
||||
for (i = 0U; i < instance->channel_count; ++i) {
|
||||
const LedIndicator_Channel *state = &instance->channels[i];
|
||||
const LedIndicator_Pattern *pattern = &instance->patterns[(size_t)state->mode];
|
||||
const uint32_t elapsed = now_ms - state->started_ms;
|
||||
write_if_changed(instance, i, pattern_level(pattern, elapsed), 0U);
|
||||
}
|
||||
}
|
||||
|
||||
void LedIndicator_Process(LedIndicator *instance)
|
||||
{
|
||||
if ((instance != NULL) && (instance->port.now_ms != NULL)) {
|
||||
LedIndicator_ProcessAt(instance, instance->port.now_ms(instance->port.context));
|
||||
}
|
||||
}
|
||||
|
||||
LedIndicator_Mode LedIndicator_GetMode(const LedIndicator *instance, size_t channel)
|
||||
{
|
||||
if ((instance == NULL) || (instance->initialized == 0U) ||
|
||||
(channel >= instance->channel_count)) {
|
||||
return LED_INDICATOR_MODE_OFF;
|
||||
}
|
||||
return instance->channels[channel].mode;
|
||||
}
|
||||
Reference in New Issue
Block a user