diff --git a/VortexEngine/src/Buttons/Buttons.cpp b/VortexEngine/src/Buttons/Buttons.cpp index ed9b3177cc..d1d4b9f1f6 100644 --- a/VortexEngine/src/Buttons/Buttons.cpp +++ b/VortexEngine/src/Buttons/Buttons.cpp @@ -26,7 +26,7 @@ Button Buttons::m_buttons[NUM_BUTTONS]; bool Buttons::init() { - // initialize the button on pins 9/10/11 + // initialize the button on pins 5/6/7 if (!m_buttons[0].init(5) || !m_buttons[1].init(6) || !m_buttons[2].init(7)) { diff --git a/VortexEngine/src/Menus/MainMenu.cpp b/VortexEngine/src/Menus/MainMenu.cpp index 30bc7dbd06..cf2246eef4 100644 --- a/VortexEngine/src/Menus/MainMenu.cpp +++ b/VortexEngine/src/Menus/MainMenu.cpp @@ -70,6 +70,11 @@ void MainMenu::open() m_isOpen = true; } +void MainMenu::close() +{ + m_isOpen = false; +} + bool MainMenu::isOpen() { return m_isOpen; diff --git a/VortexEngine/src/Menus/MainMenu.h b/VortexEngine/src/Menus/MainMenu.h index cb61340a02..5d819446b8 100644 --- a/VortexEngine/src/Menus/MainMenu.h +++ b/VortexEngine/src/Menus/MainMenu.h @@ -12,6 +12,7 @@ class MainMenu // open the main menu static void open(); + static void close(); static bool isOpen(); private: static void pressLeft(); diff --git a/VortexEngine/src/Menus/MenuList/EditorConnection.cpp b/VortexEngine/src/Menus/MenuList/EditorConnection.cpp index 5bc87c50a9..4afc4878bf 100644 --- a/VortexEngine/src/Menus/MenuList/EditorConnection.cpp +++ b/VortexEngine/src/Menus/MenuList/EditorConnection.cpp @@ -5,7 +5,9 @@ #include "../../Serial/Serial.h" #include "../../Storage/Storage.h" #include "../../Wireless/VLSender.h" +#include "../../Wireless/VLReceiver.h" #include "../../Time/TimeControl.h" +#include "../../Time/Timings.h" #include "../../Colors/Colorset.h" #include "../../Modes/Modes.h" #include "../../Modes/Mode.h" @@ -16,7 +18,8 @@ EditorConnection::EditorConnection(const RGBColor &col, bool advanced) : Menu(col, advanced), - m_state(STATE_DISCONNECTED) + m_state(STATE_DISCONNECTED), + m_timeOutStartTime(0) { } @@ -182,6 +185,16 @@ Menu::MenuAction EditorConnection::run() SerialComs::write(EDITOR_VERB_TRANSMIT_VL_ACK); m_state = STATE_IDLE; break; + case STATE_LISTEN_MODE_VL: + showReceiveModeVL(); + receiveModeVL(); + break; + case STATE_LISTEN_MODE_VL_DONE: + // done transmitting + m_receiveBuffer.clear(); + SerialComs::write(EDITOR_VERB_LISTEN_VL_ACK); + m_state = STATE_IDLE; + break; } return MENU_CONTINUE; } @@ -196,6 +209,57 @@ void EditorConnection::sendCurModeVL() m_state = STATE_TRANSMIT_MODE_VL; } +void EditorConnection::listenModeVL() +{ +#if VL_ENABLE_SENDER == 1 + // immediately load the mode and send it now + VLReceiver::beginReceiving(); +#endif + m_state = STATE_LISTEN_MODE_VL; +} + +void EditorConnection::receiveModeVL() +{ + // if reveiving new data set our last data time + if (VLReceiver::onNewData()) { + m_timeOutStartTime = Time::getCurtime(); + // if our last data was more than time out duration reset the recveiver + } else if (m_timeOutStartTime > 0 && (m_timeOutStartTime + MAX_TIMEOUT_DURATION) < Time::getCurtime()) { + VLReceiver::resetVLState(); + m_timeOutStartTime = 0; + return; + } + // check if the VLReceiver has a full packet available + if (!VLReceiver::dataReady()) { + // nothing available yet + return; + } + DEBUG_LOG("Mode ready to receive! Receiving..."); + // receive the VL mode into the current mode + if (!VLReceiver::receiveMode(&m_previewMode)) { + ERROR_LOG("Failed to receive mode"); + return; + } + DEBUG_LOGF("Success receiving mode: %u", m_previewMode.getPatternID()); + Modes::updateCurMode(&m_previewMode); + ByteStream modeBuffer; + m_previewMode.saveToBuffer(modeBuffer); + SerialComs::write(modeBuffer); + m_state = STATE_LISTEN_MODE_VL_DONE; +} + +void EditorConnection::showReceiveModeVL() +{ + if (VLReceiver::isReceiving()) { + // using uint32_t to avoid overflow, the result should be within 10 to 255 + //Leds::setAll(RGBColor(0, VLReceiver::percentReceived(), 0)); + Leds::setRange(LED_0, (LedPos)(VLReceiver::percentReceived() / 10), RGB_GREEN6); + Leds::setRange(LED_10, (LedPos)(LED_10 + (VLReceiver::percentReceived() / 10)), RGB_GREEN6); + } else { + Leds::setAll(RGB_WHITE0); + } +} + // handlers for clicks void EditorConnection::onShortClick() { @@ -321,5 +385,7 @@ void EditorConnection::handleCommand() m_state = STATE_CLEAR_DEMO; } else if (receiveMessage(EDITOR_VERB_TRANSMIT_VL)) { sendCurModeVL(); + } else if (receiveMessage(EDITOR_VERB_LISTEN_VL)) { + listenModeVL(); } } diff --git a/VortexEngine/src/Menus/MenuList/EditorConnection.h b/VortexEngine/src/Menus/MenuList/EditorConnection.h index 56235ee432..0be3555145 100644 --- a/VortexEngine/src/Menus/MenuList/EditorConnection.h +++ b/VortexEngine/src/Menus/MenuList/EditorConnection.h @@ -17,6 +17,7 @@ class EditorConnection : public Menu // broadcast the current preview mode over VL void sendCurModeVL(); + void listenModeVL(); // handlers for clicks void onShortClick() override; @@ -34,6 +35,8 @@ class EditorConnection : public Menu void handleCommand(); bool receiveMessage(const char *message); void clearDemo(); + void receiveModeVL(); + void showReceiveModeVL(); enum EditorConnectionState { // the editor is not connec @@ -66,12 +69,17 @@ class EditorConnection : public Menu // transmit the mode over visible light STATE_TRANSMIT_MODE_VL, STATE_TRANSMIT_MODE_VL_DONE, + + STATE_LISTEN_MODE_VL, + STATE_LISTEN_MODE_VL_DONE, }; // state of the editor EditorConnectionState m_state; // the data that is received ByteStream m_receiveBuffer; + // receiver timeout + uint32_t m_timeOutStartTime; }; #endif diff --git a/VortexEngine/src/Modes/Modes.cpp b/VortexEngine/src/Modes/Modes.cpp index d425254ad7..97553d2d2d 100644 --- a/VortexEngine/src/Modes/Modes.cpp +++ b/VortexEngine/src/Modes/Modes.cpp @@ -73,9 +73,9 @@ void Modes::play() nextModeSkipEmpty(); } // shortclick cycles to the next mode - if (g_pButtonM->onShortClick()) { - Menus::openMenuSelection(); - } + //if (g_pButtonM->onShortClick()) { + // Menus::openMenuSelection(); + //} // shortclick cycles to the next mode if (g_pButtonL->onShortClick()) { previousMode(); diff --git a/VortexEngine/src/VortexConfig.h b/VortexEngine/src/VortexConfig.h index 47aba8cd1e..e8c6a5960d 100644 --- a/VortexEngine/src/VortexConfig.h +++ b/VortexEngine/src/VortexConfig.h @@ -501,6 +501,11 @@ // the response from the device when it's done transmitting the mode #define EDITOR_VERB_TRANSMIT_VL_ACK "n" +// when the pc wants the chromadeck to listen for a mode from the duos +#define EDITOR_VERB_LISTEN_VL "o" +// and the response for when it's done fetching a duo mode +#define EDITOR_VERB_LISTEN_VL_ACK "p" + // =================================================================== // Manually Configured Sizes // diff --git a/VortexEngine/src/Wireless/IRConfig.h b/VortexEngine/src/Wireless/IRConfig.h index a7639d325e..e763b6b17d 100644 --- a/VortexEngine/src/Wireless/IRConfig.h +++ b/VortexEngine/src/Wireless/IRConfig.h @@ -5,8 +5,8 @@ // // Whether to enable the Infrared system as a whole // -#define IR_ENABLE_SENDER 0 -#define IR_ENABLE_RECEIVER 0 +#define IR_ENABLE_SENDER 1 +#define IR_ENABLE_RECEIVER 1 // the size of IR blocks in bits #define IR_DEFAULT_BLOCK_SIZE 32 diff --git a/VortexEngine/src/Wireless/VLReceiver.cpp b/VortexEngine/src/Wireless/VLReceiver.cpp index c163b1580f..aa6c9cab2d 100644 --- a/VortexEngine/src/Wireless/VLReceiver.cpp +++ b/VortexEngine/src/Wireless/VLReceiver.cpp @@ -20,6 +20,7 @@ uint32_t VLReceiver::m_previousBytes = 0; #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "driver/adc.h" +#include "esp_adc_cal.h" #include "esp_log.h" #include "esp_timer.h" @@ -27,29 +28,25 @@ uint32_t VLReceiver::m_previousBytes = 0; // ADC and timer configuration #define ADC_CHANNEL ADC1_CHANNEL_1 // Update this based on the actual ADC channel used -#define TIMER_INTERVAL_MICRO_SEC 10000 // Check every 10ms, adjust as needed for your application +#define ADC_ATTEN ADC_ATTEN_DB_0 +#define ADC_WIDTH ADC_WIDTH_BIT_12 +#define TIMER_INTERVAL_MICRO_SEC 1000 // Check every 10ms, adjust as needed for your application // Timer handle as a global variable for control in beginReceiving and endReceiving esp_timer_handle_t periodic_timer = nullptr; +esp_adc_cal_characteristics_t adc_chars; #define MIN_THRESHOLD 200 #define BASE_OFFSET 100 #define THRESHOLD_BEGIN (MIN_THRESHOLD + BASE_OFFSET) -// the sample count exponent, so 5 means 2^5 = 32 samples -// 0 NONE No accumulation > doesn't work -// 1 ACC2 2 results accumulated > doesn't work -// 2 ACC4 4 results accumulated > works okay -// 3 ACC8 8 results accumulated > works decent -// 4 ACC16 16 results accumulated > works very well -// 5 ACC32 32 results accumulated > works best -// 6 ACC64 64 results accumulated > doesn't work -#define SAMPLE_COUNT 5 // the threshold needs to start high then it will be automatically pulled down uint32_t threshold = THRESHOLD_BEGIN; void VLReceiver::adcCheckTimerCallback(void *arg) { static bool wasAboveThreshold = false; - uint32_t val = adc1_get_raw(ADC_CHANNEL); + uint32_t raw = adc1_get_raw(ADC_CHANNEL); + uint32_t val = esp_adc_cal_raw_to_voltage(raw, &adc_chars); + if (val > MIN_THRESHOLD && val < (threshold + BASE_OFFSET)) { threshold = val + BASE_OFFSET; } @@ -65,8 +62,10 @@ bool VLReceiver::init() { #ifdef VORTEX_EMBEDDED // Initialize ADC for GPIO1 (or appropriate pin connected to your light sensor) - adc1_config_width(ADC_WIDTH_BIT_12); - adc1_config_channel_atten(ADC_CHANNEL, ADC_ATTEN_DB_0); + adc1_config_width(ADC_WIDTH); + adc1_config_channel_atten(ADC_CHANNEL, ADC_ATTEN); + memset(&adc_chars, 0, sizeof(adc_chars)); + esp_adc_cal_characterize(ADC_UNIT_1, ADC_ATTEN, ADC_WIDTH, 0, &adc_chars); #endif return m_vlData.init(VL_RECV_BUF_SIZE); } @@ -134,16 +133,15 @@ bool VLReceiver::receiveMode(Mode *pMode) bool VLReceiver::beginReceiving() { #ifdef VORTEX_EMBEDDED - if (periodic_timer != nullptr) { + if (periodic_timer) { DEBUG_LOG("VL Reception already running."); return false; // Timer is already running } // Initialize timer for periodic ADC checks const esp_timer_create_args_t periodic_timer_args = { - .callback = (void (*)(void*))&VLReceiver::adcCheckTimerCallback, - .name = "adc_check_timer" + .callback = &VLReceiver::adcCheckTimerCallback, + .name = "adc_check_timer", }; - esp_timer_handle_t periodic_timer; ESP_ERROR_CHECK(esp_timer_create(&periodic_timer_args, &periodic_timer)); ESP_ERROR_CHECK(esp_timer_start_periodic(periodic_timer, TIMER_INTERVAL_MICRO_SEC)); #endif @@ -213,17 +211,17 @@ void VLReceiver::recvPCIHandler() // check previous time for validity if (!m_prevTime || m_prevTime > now) { m_prevTime = now; - DEBUG_LOG("Bad first time diff, resetting..."); + //DEBUG_LOG("Bad first time diff, resetting..."); resetVLState(); return; } - DEBUG_LOGF("Received: %u", m_pinState); + //DEBUG_LOGF("Received: %u", m_pinState); // calc time difference between previous change and now uint32_t diff = (uint32_t)(now - m_prevTime); // and update the previous changetime for next loop m_prevTime = now; // handle the bliank duration and process it - //handleVLTiming(diff); + handleVLTiming(diff); } // state machine that can be fed VL timings to parse them and interpret the intervals @@ -231,7 +229,7 @@ void VLReceiver::handleVLTiming(uint32_t diff) { // if the diff is too long or too short then it's not useful if ((diff > VL_HEADER_MARK_MAX && m_recvState < READING_DATA_MARK) || diff < VL_TIMING_MIN) { - DEBUG_LOGF("bad delay: %u, resetting...", diff); + //DEBUG_LOGF("bad delay: %u, resetting...", diff); resetVLState(); return; } @@ -240,7 +238,7 @@ void VLReceiver::handleVLTiming(uint32_t diff) if (diff >= VL_HEADER_SPACE_MIN && diff <= VL_HEADER_MARK_MAX) { m_recvState = WAITING_HEADER_SPACE; } else { - DEBUG_LOGF("Bad header mark %u, resetting...", diff); + //DEBUG_LOGF("Bad header mark %u, resetting...", diff); resetVLState(); } break; @@ -248,7 +246,7 @@ void VLReceiver::handleVLTiming(uint32_t diff) if (diff >= VL_HEADER_SPACE_MIN && diff <= VL_HEADER_MARK_MAX) { m_recvState = READING_DATA_MARK; } else { - DEBUG_LOGF("Bad header space %u, resetting...", diff); + //DEBUG_LOGF("Bad header space %u, resetting...", diff); resetVLState(); } break; @@ -262,7 +260,7 @@ void VLReceiver::handleVLTiming(uint32_t diff) m_recvState = READING_DATA_MARK; break; default: // ?? - DEBUG_LOGF("Bad receive state: %u", m_recvState); + //DEBUG_LOGF("Bad receive state: %u", m_recvState); break; } } @@ -273,7 +271,7 @@ void VLReceiver::resetVLState() m_recvState = WAITING_HEADER_MARK; // zero out the receive buffer and reset bit receiver position m_vlData.reset(); - DEBUG_LOG("VL State Reset"); + //DEBUG_LOG("VL State Reset"); } #endif diff --git a/VortexEngine/src/Wireless/VLReceiver.h b/VortexEngine/src/Wireless/VLReceiver.h index f9e0e39463..1d7d35628b 100644 --- a/VortexEngine/src/Wireless/VLReceiver.h +++ b/VortexEngine/src/Wireless/VLReceiver.h @@ -78,7 +78,7 @@ class VLReceiver static uint32_t m_previousBytes; #ifdef VORTEX_EMBEDDED - void adcCheckTimerCallback(void *arg); + static void adcCheckTimerCallback(void *arg); #endif #ifdef VORTEX_LIB