PingPong/Core/Src/Indicator.c
2024-09-30 00:26:00 +03:00

406 lines
14 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* Indicator.c
*
* Created on: Sep 26, 2024
* Author: DashyFox
*/
#include "Indicator.h"
#include "ShiftReg.h"
#include "SimpleTimer.h"
#include "Print.h"
#include <string.h>
const LedMap ledMap = {
// ALL - DOWN[0] TO UP[19]
{ { 0, 0b01000000 }, { 0, 0b00100000 }, { 0, 0b00010000 }, { 0,
0b00001000 }, { 0, 0b00000100 }, { 0, 0b00000010 }, { 0,
0b00000001 }, { 1, 0b00000001 }, { 1, 0b00000010 }, { 1,
0b00000100 },
{ 1, 0b01000000 }, { 1, 0b00100000 }, { 1, 0b00010000 },
{ 2, 0b00000001 }, { 2, 0b00000010 }, { 2, 0b00000100 }, { 2,
0b00001000 }, { 2, 0b00010000 }, { 2, 0b00100000 }, { 2,
0b01000000 }, },
// UP - DOWN[0] TO UP[9]
{ { 1, 0b01000000 }, { 1, 0b00100000 }, { 1, 0b00010000 }, { 2,
0b00000001 }, { 2, 0b00000010 }, { 2, 0b00000100 }, { 2,
0b00001000 }, { 2, 0b00010000 }, { 2, 0b00100000 }, { 2,
0b01000000 }, },
// DOWN - DOWN[0] TO UP[9]
{ { 0, 0b01000000 }, { 0, 0b00100000 }, { 0, 0b00010000 }, { 0,
0b00001000 }, { 0, 0b00000100 }, { 0, 0b00000010 }, { 0,
0b00000001 }, { 1, 0b00000001 }, { 1, 0b00000010 }, { 1,
0b00000100 }, },
// RED - DOWN[0] TO UP[5]
{ { 1, 0b00000001 }, { 1, 0b00000010 }, { 1, 0b00000100 },
{ 1, 0b01000000 }, { 1, 0b00100000 }, { 1, 0b00010000 }, } };
static uint8_t ledBuf[3] = { 0, 0, 0 };
typedef struct {
uint16_t period;
uint16_t count;
uint32_t timer;
} LedBlinkInfo;
typedef struct {
uint8_t start;
uint8_t end;
uint32_t ledCurrent;
uint8_t globalDir;
uint8_t dir;
void (*writeCallback)(uint8_t ledNum, uint8_t state);
} LedPingPongInfo;
static LedBlinkInfo ledBlinkInfo[NUMLEDS * INDICATORS_COUNT];
static LedPingPongInfo ledPingPongInfo;
static uint32_t idle_timer;
static void NULL_FUNC(){};
static void (*onLedIdle_Callback)() = NULL_FUNC;
//static void (*onDone_Callback)() = NULL_FUNC;
static void led_PingPong_start_(uint8_t fromLed, uint8_t toLed);
static void led_progressbar_(uint8_t fromLed, uint8_t toLed, uint8_t progress, void (*led_writeFunc)(uint8_t, uint8_t));
//void led_setOnDone(void (*callback)()){
// onDone_Callback = callback;
//}
//void led_resetOnDone(){
// onDone_Callback = NULL_FUNC;
//}
static long map(long x, long in_min, long in_max, long out_min, long out_max) {
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
static void blinkHandler() {
for (int i = 0; i < sizeof(ledBlinkInfo) / sizeof(ledBlinkInfo[0]); ++i) {
if (!ledBlinkInfo[i].count || !ledBlinkInfo[i].period) {
continue;
}
if (millis() - ledBlinkInfo[i].timer > ledBlinkInfo[i].period) {
ledBlinkInfo[i].timer = millis();
if(ledBlinkInfo[i].count != 0xFFFF){
led_write(i, (ledBlinkInfo[i].count & 1) != 1);
ledBlinkInfo[i].count--;
} else {
led_write(i, !led_getState(ledMap.ALL[i]));
}
}
}
}
void led_setIdleCallback(void(*callback)()){
onLedIdle_Callback = callback;
}
void led_resetIdleCallback(){
onLedIdle_Callback = NULL_FUNC;
}
void led_init() {
memset(ledBlinkInfo, 0x00, sizeof(ledBlinkInfo));
memset(&ledPingPongInfo, 0x00, sizeof(ledPingPongInfo));
ledPingPongInfo.writeCallback = led_write;
}
void led_show() {
idle_timer = millis();
SetShiftReg(ledBuf);
}
void led_tick() {
blinkHandler();
if(onLedIdle_Callback != NULL_FUNC && millis() - idle_timer > LED_IDLE_TIMEOUT){
onLedIdle_Callback();
led_resetIdleCallback();
}
}
void led_write(uint8_t number, uint8_t state) {
if(number >= sizeof(ledMap.ALL)/sizeof(ledMap.ALL[0]))
return;
LedMap_element led = ledMap.ALL[number];
if(led_getState(led) == state)
return;
if (state) {
ledBuf[led.byteIndx] |= led.offsetMask;
} else {
ledBuf[led.byteIndx] &= ~(led.offsetMask);
}
led_show();
}
uint8_t led_getState(LedMap_element led) {
return (ledBuf[led.byteIndx] & led.offsetMask) != 0;
}
void led_writeMirror(uint8_t number, uint8_t state) {
if (number >= 10) {
number = 9;
}
number+=10;
led_write(number, state);
led_write(19 - number, state);
}
void led_blink_num(uint8_t ledNum, uint16_t period, uint16_t count) {
if (ledNum >= sizeof(ledBlinkInfo) / sizeof(ledBlinkInfo[0]))
return;
if(count == 0xFFFF){
ledBlinkInfo[ledNum].count = count;
} else {
ledBlinkInfo[ledNum].count = count * 2;
}
ledBlinkInfo[ledNum].period = period;
ledBlinkInfo[ledNum].timer = 0; // run immediately
}
void led_blink(LedMap_element led, uint16_t period, uint16_t count) {
for (int i = 0; i < sizeof(ledMap.ALL) / sizeof(ledMap.ALL[0]); ++i) {
if (memcmp(&led, &ledMap.ALL[i], sizeof(LedMap_element)) == 0) {
led_blink_num(i, period, count);
return;
}
}
}
// Общая функция для управления прогрессбаром
void led_progressbar_(uint8_t fromLed, uint8_t toLed, uint8_t progress, void (*led_writeFunc)(uint8_t, uint8_t)) {
if (progress > 100) {
progress = 100;
}
// Проверка на выход за границы массива ledMap.ALL
if (fromLed >= sizeof(ledMap.ALL) / sizeof(ledMap.ALL[0])
|| toLed >= sizeof(ledMap.ALL) / sizeof(ledMap.ALL[0])) {
return;
}
// Инициализация переменных в зависимости от направления
int8_t dir;
uint8_t start;
uint8_t end;
uint8_t numLeds;
if (fromLed < toLed) {
start = fromLed;
end = toLed;
dir = 1; // Заполнение снизу вверх
} else {
start = toLed;
end = fromLed;
dir = -1; // Заполнение сверху вниз
}
// Количество светодиодов в прогрессбаре (включая последний светодиод)
numLeds = end - start + 1;
// Рассчитываем, сколько светодиодов нужно включить
uint8_t ledsToLight = map(progress, 0, 100, 0, numLeds);
// Корректировка включения для первого и последнего светодиода
if (progress > 0 && ledsToLight == 0) {
ledsToLight = 1; // Включаем первый светодиод при любом положительном прогрессе
}
if (progress == 100) {
ledsToLight = numLeds; // Включаем последний светодиод только при прогрессе 100%
}
print("progress ");
printNumber(progress);
print(" led ");
printNumber(ledsToLight);
print("\n");
for (int i = 0; i < numLeds; ++i) {
int ledIndex = fromLed + i * dir;
// Сброс счетчика мигания для включенных светодиодов
ledBlinkInfo[ledIndex].count = 0;
if (i < ledsToLight) {
// Включаем светодиод, если он не включен
if (!led_getState(ledMap.ALL[ledIndex])) {
led_writeFunc(ledIndex, 1); // Используем переданную функцию для включения
}
} else {
// Выключаем светодиод, если он включен
if (led_getState(ledMap.ALL[ledIndex])) {
led_writeFunc(ledIndex, 0); // Используем переданную функцию для выключения
}
}
}
}
// Оригинальная функция, использующая led_write
void led_progressbar(uint8_t fromLed, uint8_t toLed, uint8_t progress) {
led_progressbar_(fromLed, toLed, progress, led_write);
}
// Новая функция, использующая led_writeMirror
void led_progressbarMirror(uint8_t fromLed, uint8_t toLed, uint8_t progress) {
led_progressbar_(fromLed, toLed, progress, led_writeMirror);
}
void led_PingPong_startMirror(uint8_t fromLed, uint8_t toLed){
uint8_t half_ledMap_size = (sizeof(ledMap.ALL) / sizeof(ledMap.ALL[0]))/2;
if (fromLed >= half_ledMap_size
|| toLed >= half_ledMap_size) {
return;
}
ledPingPongInfo.writeCallback = led_writeMirror;
led_PingPong_start_(fromLed, toLed);
}
void led_PingPong_start(uint8_t fromLed, uint8_t toLed) {
if (fromLed >= sizeof(ledMap.ALL) / sizeof(ledMap.ALL[0])
|| toLed >= sizeof(ledMap.ALL) / sizeof(ledMap.ALL[0])) {
return;
}
ledPingPongInfo.writeCallback = led_write;
led_PingPong_start_(fromLed, toLed);
}
void led_PingPong_start_(uint8_t fromLed, uint8_t toLed){
if (fromLed < toLed) {
ledPingPongInfo.start = fromLed;
ledPingPongInfo.end = toLed;
ledPingPongInfo.globalDir = 1;
} else {
ledPingPongInfo.start = toLed;
ledPingPongInfo.end = fromLed;
ledPingPongInfo.globalDir = 0;
}
ledPingPongInfo.dir = 1;
ledPingPongInfo.ledCurrent = ledPingPongInfo.start;
for (uint8_t i = ledPingPongInfo.start; i <= ledPingPongInfo.end; i++) {
ledBlinkInfo[i].count = 0;
if (led_getState(ledMap.ALL[i]))
ledPingPongInfo.writeCallback(i, 0);
}
if(!led_getState(ledMap.ALL[ledPingPongInfo.start]))
ledPingPongInfo.writeCallback(ledPingPongInfo.start, 1);
}
void led_PingPong_next() {
// Проверка на выход за границы массива
uint8_t ledCount = sizeof(ledMap.ALL) / sizeof(ledMap.ALL[0]);
// Обработка движения "туда-обратно"
if (ledPingPongInfo.globalDir) {
// Двигаемся от начала к концу
if (ledPingPongInfo.dir) {
// Если не дошли до конца и не выходим за границы массива
if (ledPingPongInfo.ledCurrent + 1 < ledCount && ledPingPongInfo.ledCurrent + 1 <= ledPingPongInfo.end) {
// Включаем следующий светодиод и выключаем текущий
ledPingPongInfo.writeCallback(ledPingPongInfo.ledCurrent + 1, 1);
ledPingPongInfo.writeCallback(ledPingPongInfo.ledCurrent, 0);
ledPingPongInfo.ledCurrent++;
} else {
// Достигли конца — сразу меняем направление и двигаемся обратно
ledPingPongInfo.dir = 0;
ledPingPongInfo.ledCurrent--;
ledPingPongInfo.writeCallback(ledPingPongInfo.ledCurrent, 1);
ledPingPongInfo.writeCallback(ledPingPongInfo.ledCurrent + 1, 0);
}
} else {
// Двигаемся от конца к началу
if (ledPingPongInfo.ledCurrent > ledPingPongInfo.start) {
// Включаем предыдущий светодиод и выключаем текущий
ledPingPongInfo.writeCallback(ledPingPongInfo.ledCurrent - 1, 1);
ledPingPongInfo.writeCallback(ledPingPongInfo.ledCurrent, 0);
ledPingPongInfo.ledCurrent--;
} else {
// Достигли начала — сразу меняем направление и двигаемся вперед
ledPingPongInfo.dir = 1;
ledPingPongInfo.ledCurrent++;
ledPingPongInfo.writeCallback(ledPingPongInfo.ledCurrent, 1);
ledPingPongInfo.writeCallback(ledPingPongInfo.ledCurrent - 1, 0);
}
}
} else {
// Двигаемся от конца к началу (начальное обратное направление)
if (ledPingPongInfo.dir) {
// Если не дошли до начала и не выходим за границы массива
if (ledPingPongInfo.ledCurrent > ledPingPongInfo.start) {
// Включаем предыдущий светодиод и выключаем текущий
ledPingPongInfo.writeCallback(ledPingPongInfo.ledCurrent - 1, 1);
ledPingPongInfo.writeCallback(ledPingPongInfo.ledCurrent, 0);
ledPingPongInfo.ledCurrent--;
} else {
// Достигли начала — сразу меняем направление и двигаемся обратно
ledPingPongInfo.dir = 0;
ledPingPongInfo.ledCurrent++;
ledPingPongInfo.writeCallback(ledPingPongInfo.ledCurrent, 1);
ledPingPongInfo.writeCallback(ledPingPongInfo.ledCurrent - 1, 0);
}
} else {
// Двигаемся от начала к концу (обратное направление)
if (ledPingPongInfo.ledCurrent + 1 < ledCount && ledPingPongInfo.ledCurrent + 1 <= ledPingPongInfo.end) {
// Включаем следующий светодиод и выключаем текущий
ledPingPongInfo.writeCallback(ledPingPongInfo.ledCurrent + 1, 1);
ledPingPongInfo.writeCallback(ledPingPongInfo.ledCurrent, 0);
ledPingPongInfo.ledCurrent++;
} else {
// Достигли конца — сразу меняем направление и двигаемся обратно
ledPingPongInfo.dir = 1;
ledPingPongInfo.ledCurrent--;
ledPingPongInfo.writeCallback(ledPingPongInfo.ledCurrent, 1);
ledPingPongInfo.writeCallback(ledPingPongInfo.ledCurrent + 1, 0);
}
}
}
}
void led_showSpeed(uint8_t progressUP, uint8_t progressDOWN){
memset(ledBlinkInfo, 0x00, sizeof(ledBlinkInfo));
if (progressUP < 70 && progressUP)
progressUP = 70;
if (progressUP > 100) {
progressUP = map(progressUP, 100, 199, 0, 100);
led_progressbar(13, 19, progressUP);
led_progressbar(12, 10, 0);
} else if (progressUP < 100) {
progressUP = map((100 - progressUP), 0, 30, 0, 100);
led_progressbar(13, 19, 0);
led_progressbar(12, 10, progressUP);
} else {
led_progressbar(13, 19, 0);
led_progressbar(12, 10, 0);
}
if (progressDOWN < 70 && progressDOWN)
progressDOWN = 70;
if (progressDOWN > 100) {
progressDOWN = map(progressDOWN, 100, 199, 0, 100);
led_progressbar(7, 0, progressDOWN);
led_progressbar(9, 7, 0);
} else if (progressDOWN < 100) {
progressDOWN = map((100 - progressDOWN), 0, 30, 0, 100);
led_progressbar(7, 0, 0);
led_progressbar(9, 7, progressDOWN);
} else {
led_progressbar(7, 0, 0);
led_progressbar(9, 7, 0);
}
}
void led_clear() {
memset(ledBuf, 0x00, sizeof(ledBuf));
memset(ledBlinkInfo, 0x00, sizeof(ledBlinkInfo));
led_show();
}