/* * Indicator.c * * Created on: Sep 26, 2024 * Author: DashyFox */ #include "Indicator.h" #include "ShiftReg.h" #include "SimpleTimer.h" #include "Print.h" #include 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(); }