diff --git a/espmusicmouse/host_driver/host_driver.py b/espmusicmouse/host_driver/host_driver.py index 5327ed2..10efdb8 100644 --- a/espmusicmouse/host_driver/host_driver.py +++ b/espmusicmouse/host_driver/host_driver.py @@ -1,7 +1,5 @@ import asyncio -import serial_asyncio from enum import Enum -from dataclasses import dataclass import struct from led_cmds import * @@ -23,10 +21,12 @@ class MessageHostToFw(Enum): LED_WHEEL_EFFECT_RANDOM_TWO_COLOR_INTERPOLATION = 3 -outgoingMsgMap = { +outgoing_msg_map = { EffectStaticConfig: 0, EffectAlexaSwipeConfig: 1, EffectCircularConfig: 2, + EffectRandomTwoColorInterpolationConfig: 3, + EffectSwipeAndChange: 4, } @@ -42,17 +42,21 @@ incomingMsgMap = {0: RfidTokenRead} class MusicMouseProtocol(asyncio.Protocol): + def __init__(self): + super() + self._msg_callback = None + + def register_message_callback(self, cb): + self._msg_callback = cb + def connection_made(self, transport): self.transport = transport self.in_buff = bytes() def send_message(self, message): msg_content = message.as_bytes() - print("Sending message content", len(msg_content)) - header = struct.pack(" bytes: - return struct.pack(" bytes: return struct.pack( @@ -64,25 +69,34 @@ class EffectAlexaSwipeConfig: @dataclass class EffectRandomTwoColorInterpolationConfig: - cycle_durations_ms: int - start_with_existing: bool - num_segments: int - hue1_random: bool - hue2_random: bool - color1: ColorHSV - color2: ColorHSV + cycle_durations_ms: int = 6000 + start_with_existing: bool = True + num_segments: int = 3 + hue1_random: bool = False + hue2_random: bool = False + color1: ColorHSV = ColorHSV(240, 1, 1) + color2: ColorHSV = ColorHSV(192, 1, 1) def as_bytes(self) -> bytes: return struct.pack(" bytes: return struct.pack(" bytes: + return self.swipe.as_bytes() + self.change.as_bytes() \ No newline at end of file diff --git a/espmusicmouse/host_driver/main.py b/espmusicmouse/host_driver/main.py new file mode 100644 index 0000000..a66ebba --- /dev/null +++ b/espmusicmouse/host_driver/main.py @@ -0,0 +1,47 @@ +import asyncio +import serial_asyncio +from led_cmds import (ColorRGBW, ColorHSV, EffectStaticConfig, + EffectRandomTwoColorInterpolationConfig, EffectAlexaSwipeConfig, + EffectSwipeAndChange) +from host_driver import MusicMouseProtocol, RfidTokenRead + +rfid_token_map = { + bytes.fromhex("0000000000"): "None", + bytes.fromhex("88041174e9"): "Elephant", + bytes.fromhex("8804ce7230"): "Fox", + bytes.fromhex("88040d71f0"): "Owl", +} + + +def on_firmware_msg(protocol, message): + print("Got message", message) + if isinstance(message, RfidTokenRead) and message.id in rfid_token_map: + if rfid_token_map[message.id] == "Elephant": + print("Elephant") + eff = EffectStaticConfig(ColorRGBW(0, 0, 1, 0)) + protocol.send_message(eff) + elif rfid_token_map[message.id] == "Fox": + print("Fox") + eff = EffectRandomTwoColorInterpolationConfig() + protocol.send_message(eff) + elif rfid_token_map[message.id] == "Owl": + print("Owl") + eff = EffectSwipeAndChange() + eff.swipe.primary_color = ColorRGBW(1, 1, 0, 0) + protocol.send_message(eff) + elif rfid_token_map[message.id] == "None": + eff = EffectAlexaSwipeConfig() + eff.forward = False + print("Nothing") + protocol.send_message(eff) + + +loop = asyncio.get_event_loop() +coro = serial_asyncio.create_serial_connection(loop, + MusicMouseProtocol, + '/dev/ttyUSB0', + baudrate=115200) +transport, protocol = loop.run_until_complete(coro) +protocol.register_message_callback(on_firmware_msg) +loop.run_forever() +loop.close() \ No newline at end of file diff --git a/espmusicmouse/lib/ledtl/effects/AlexaSwipe.h b/espmusicmouse/lib/ledtl/effects/AlexaSwipe.h index 38b20a0..f063e9e 100644 --- a/espmusicmouse/lib/ledtl/effects/AlexaSwipe.h +++ b/espmusicmouse/lib/ledtl/effects/AlexaSwipe.h @@ -6,6 +6,7 @@ #include "helpers/ColorConversions.h" #include "helpers/BellCurve.h" +#pragma pack(push, 1) struct EffectAlexaSwipeConfig { float primaryColorWidth; // in degrees @@ -17,6 +18,7 @@ struct EffectAlexaSwipeConfig ColorRGBW primaryColor; ColorRGBW secondaryColor; }; +#pragma pack(pop) template class EffectAlexaSwipe @@ -38,7 +40,8 @@ public: speed_(cfg.swipeSpeed / 360 / 1000 * NUM_LEDS * DELAY_MS), startPosition_(cfg.startPosition / 360.0f * NUM_LEDS), primaryColor_(rgb2hsv(cfg.primaryColor)), - secondaryColor_(rgb2hsv(cfg.secondaryColor)) + secondaryColor_(rgb2hsv(cfg.secondaryColor)), + finished_(false) { if (cfg.forward) { @@ -52,6 +55,8 @@ public: } } + bool finished() { return finished_; } + int operator()() { clear(ledStrip_); @@ -72,8 +77,13 @@ public: } } currentPosition_ += direction_ * speed_; - currentPosition_ = std::min(currentPosition_, float(NUM_LEDS) / 2.0f + bellCurveWidth_ / 2); - currentPosition_ = std::max(currentPosition_, 0.0f); + const auto maxPosition = float(NUM_LEDS) / 2.0f + bellCurveWidth_ / 2; + const auto minPosition = 0.0f; + currentPosition_ = std::min(currentPosition_, maxPosition); + currentPosition_ = std::max(currentPosition_, minPosition); + if (currentPosition_ <= minPosition || currentPosition_ >= maxPosition) + finished_ = true; + return DELAY_MS; } @@ -119,6 +129,8 @@ private: const ColorHSV primaryColor_; const ColorHSV secondaryColor_; float direction_; + + bool finished_; }; // Traits diff --git a/espmusicmouse/lib/ledtl/effects/Circular.h b/espmusicmouse/lib/ledtl/effects/Circular.h index aa484cb..4a7e4e3 100644 --- a/espmusicmouse/lib/ledtl/effects/Circular.h +++ b/espmusicmouse/lib/ledtl/effects/Circular.h @@ -4,12 +4,14 @@ #include "helpers/ColorRGBW.h" #include "helpers/BellCurve.h" +#pragma pack(push, 1) struct EffectCircularConfig { float speed; // in degrees per second float width; // width in degrees ColorRGBW color; }; +#pragma pack(pop) template class EffectCircular diff --git a/espmusicmouse/lib/ledtl/effects/Common.h b/espmusicmouse/lib/ledtl/effects/Common.h index d721432..9c3ec2b 100644 --- a/espmusicmouse/lib/ledtl/effects/Common.h +++ b/espmusicmouse/lib/ledtl/effects/Common.h @@ -5,7 +5,8 @@ enum class EffectId STATIC, CIRCULAR, ALEXA_SWIPE, - RANDOM_TWO_COLOR_INTERPOLATION + RANDOM_TWO_COLOR_INTERPOLATION, + SWIPE_AND_CHANGE, // combination of ALEXA_SWIPE and RANDOM_TWO_COLOR_INTERPOLATION }; template diff --git a/espmusicmouse/lib/ledtl/effects/RandomTwoColorInterpolation.h b/espmusicmouse/lib/ledtl/effects/RandomTwoColorInterpolation.h index 9611272..bc5116f 100644 --- a/espmusicmouse/lib/ledtl/effects/RandomTwoColorInterpolation.h +++ b/espmusicmouse/lib/ledtl/effects/RandomTwoColorInterpolation.h @@ -6,6 +6,7 @@ #include "helpers/ColorHSV.h" #include "helpers/ColorConversions.h" +#pragma pack(push, 1) struct EffectRandomTwoColorInterpolationConfig { int32_t cycleDurationMs; @@ -18,6 +19,7 @@ struct EffectRandomTwoColorInterpolationConfig ColorHSV color1; ColorHSV color2; }; +#pragma pack(pop) template class EffectRandomTwoColorInterpolation @@ -43,6 +45,13 @@ public: randomizeColors(nextColors_); } + void begin() + { + if (config_.startWithExisting) + for (int i = 0; i < NUM_LEDS; ++i) + currentColors_[i] = rgb2hsv(getLedRGBW(ledStrip_, i)); + } + int operator()() { for (int i = 0; i < NUM_LEDS; ++i) diff --git a/espmusicmouse/lib/ledtl/effects/SwipeAndChange.h b/espmusicmouse/lib/ledtl/effects/SwipeAndChange.h new file mode 100644 index 0000000..b68665a --- /dev/null +++ b/espmusicmouse/lib/ledtl/effects/SwipeAndChange.h @@ -0,0 +1,64 @@ +#pragma once + +#include "effects/Common.h" +#include "effects/AlexaSwipe.h" +#include "effects/RandomTwoColorInterpolation.h" + +#pragma pack(push, 1) +struct EffectSwipeAndChangeConfig +{ + EffectAlexaSwipeConfig swipeCfg; + EffectRandomTwoColorInterpolationConfig changeCfg; +}; +#pragma pack(pop) + +template +class EffectSwipeAndChange +{ +public: + EffectSwipeAndChange(const EffectSwipeAndChangeConfig &cfg, TLedStrip &ledStrip) + : effect1_(cfg.swipeCfg, ledStrip), + effect2_(cfg.changeCfg, ledStrip), + effectRunning_(0) + { + } + + int operator()() + { + if (!effect1_.finished()) + { + return effect1_(); + } + else + { + if (effectRunning_ == 0) + effect2_.begin(); + effectRunning_ = 1; + return effect2_(); + } + } + +private: + EffectAlexaSwipe effect1_; + EffectRandomTwoColorInterpolation effect2_; + int effectRunning_; +}; + +// Traits +template <> +struct EffectIdToConfig +{ + using type = EffectSwipeAndChangeConfig; +}; + +template <> +struct EffectConfigToId +{ + static constexpr auto id = EffectId::SWIPE_AND_CHANGE; +}; + +template +struct EffectIdToClass +{ + using type = EffectSwipeAndChange; +}; \ No newline at end of file diff --git a/espmusicmouse/lib/ledtl/helpers/ColorConversions.h b/espmusicmouse/lib/ledtl/helpers/ColorConversions.h index 7327105..da753cf 100644 --- a/espmusicmouse/lib/ledtl/helpers/ColorConversions.h +++ b/espmusicmouse/lib/ledtl/helpers/ColorConversions.h @@ -39,7 +39,7 @@ inline ColorHSV rgb2hsv(const ColorRGBW &in) out.h = 0.0f; //NAN; // its now undefined return out; } - if (r >= max) // > is bogus, just keeps compilor happy + if (r >= max) // > is bogus, just keeps compiler happy out.h = (g - b) / delta; // between yellow & magenta else if (g >= max) out.h = 2.0f + (b - r) / delta; // between cyan & yellow diff --git a/espmusicmouse/src/Messages.h b/espmusicmouse/src/Messages.h index 89d3789..713a098 100644 --- a/espmusicmouse/src/Messages.h +++ b/espmusicmouse/src/Messages.h @@ -2,12 +2,11 @@ #include "effects/Static.h" #include "effects/AlexaSwipe.h" #include "effects/RandomTwoColorInterpolation.h" +#include "effects/SwipeAndChange.h" #include "Arduino.h" #include -#pragma pack(push, 1) - constexpr uint32_t MAGIC_TOKEN_HOST_TO_FW = 0x1d6379e3; constexpr uint32_t MAGIC_TOKEN_FW_TO_HOST = 0x10c65631; @@ -41,7 +40,8 @@ enum class MessageHostToFw : uint8_t LED_WHEEL_EFFECT_STATIC = 0, LED_WHEEL_EFFECT_ALEXA_SWIPE = 1, LED_WHEEL_EFFECT_CIRCULAR = 2, - LED_WHEEL_EFFECT_RANDOM_TWO_COLOR_INTERPOLATION = 3 + LED_WHEEL_EFFECT_RANDOM_TWO_COLOR_INTERPOLATION = 3, + LED_WHEEL_EFFECT_SWIPE_AND_CHANGE = 4 }; template <> @@ -68,7 +68,11 @@ struct ClassToMessageType static constexpr auto msgType = MessageHostToFw::LED_WHEEL_EFFECT_RANDOM_TWO_COLOR_INTERPOLATION; }; -#pragma pack(pop) +template <> +struct ClassToMessageType +{ + static constexpr auto msgType = MessageHostToFw::LED_WHEEL_EFFECT_SWIPE_AND_CHANGE; +}; //---------------------------------------------------------------------------------------------------- @@ -111,13 +115,11 @@ inline void handleIncomingMessagesFromHost(LedTask *ledTask) Serial.readBytes(msgBuffer, msgSize); if (msgType == MessageHostToFw::LED_WHEEL_EFFECT_STATIC) { - Serial.println("Static color"); auto cfg = reinterpret_cast(msgBuffer); ledTask->startEffect(*cfg); } else if (msgType == MessageHostToFw::LED_WHEEL_EFFECT_ALEXA_SWIPE) { - Serial.println("Alexa swipe"); auto cfg = reinterpret_cast(msgBuffer); ledTask->startEffect(*cfg); } @@ -131,6 +133,11 @@ inline void handleIncomingMessagesFromHost(LedTask *ledTask) auto cfg = reinterpret_cast(msgBuffer); ledTask->startEffect(*cfg); } + else if (msgType == MessageHostToFw::LED_WHEEL_EFFECT_SWIPE_AND_CHANGE) + { + auto cfg = reinterpret_cast(msgBuffer); + ledTask->startEffect(*cfg); + } else Serial.println("Unknown message type"); } diff --git a/espmusicmouse/src/TaskLed.h b/espmusicmouse/src/TaskLed.h index 5230aeb..b78b499 100644 --- a/espmusicmouse/src/TaskLed.h +++ b/espmusicmouse/src/TaskLed.h @@ -75,10 +75,11 @@ void _led_task_func(void *params) TLedStrip &ledStrip = *(task->ledStrip_); // clang-format off - if (dispatchEffectId(id, effectFunction, ledStrip, msgBuffer, effectStorage)) { Serial.println("Parsed circular");} - else if (dispatchEffectId(id, effectFunction, ledStrip, msgBuffer, effectStorage)) { Serial.println("Parsed static");} - else if (dispatchEffectId(id, effectFunction, ledStrip, msgBuffer, effectStorage)) { Serial.println("Alexa swipe");} - else if (dispatchEffectId(id, effectFunction, ledStrip, msgBuffer, effectStorage)) { Serial.println("random color ip");} + if (dispatchEffectId(id, effectFunction, ledStrip, msgBuffer, effectStorage)) {} + else if (dispatchEffectId(id, effectFunction, ledStrip, msgBuffer, effectStorage)) {} + else if (dispatchEffectId(id, effectFunction, ledStrip, msgBuffer, effectStorage)) {} + else if (dispatchEffectId(id, effectFunction, ledStrip, msgBuffer, effectStorage)) {} + else if (dispatchEffectId(id, effectFunction, ledStrip, msgBuffer, effectStorage)) {} // clang-format on timeoutMsForEffect = 0; diff --git a/espmusicmouse/src/main.cpp b/espmusicmouse/src/main.cpp index dba588a..cb6b196 100644 --- a/espmusicmouse/src/main.cpp +++ b/espmusicmouse/src/main.cpp @@ -15,111 +15,70 @@ #include "TaskLed.h" -MFRC522 rfid; // Instance of the class - +// -------------------------------------------------- RFID Reader ---------------------------------------- +MFRC522 rfid; MFRC522::MIFARE_Key key; -//LedStrip led(46, 23); -LedStripRGBW<51> ledStrip; -Esp32DriverRGBW ledDriver; - -LedTask ledTask; - -bool fox; -void tag_handler(uint8_t *sn) +void tagHandler(uint8_t *sn) { - // serial number is always 5 bytes long if (sn != nullptr) - { - - Serial.printf("Tag: %#x %#x %#x %#x %#x\n", - sn[0], sn[1], sn[2], sn[3], sn[4]); sendMessageToHost(MsgRfidTokenRead{{sn[0], sn[1], sn[2], sn[3], sn[4]}}); - if (sn[4] == 0x30) - { - Serial.println("Fuchs"); - fox = true; - //ledTask.startEffect(EffectCircularConfig{2 * 360, 180, ColorRGBW{0, 0, 255, 0}}); - ledTask.startEffect(EffectAlexaSwipeConfig{20, 30, 3 * 360, 3, 180, true, ColorRGBW{0, 255, 0, 0}, ColorRGBW{0, 0, 255, 0}}); - delay(1000); - ledTask.startEffect(EffectRandomTwoColorInterpolationConfig{6000, true, 6, false, false, rgb2hsv(ColorRGBW{128, 0, 0, 0}), - rgb2hsv(ColorRGBW{0, 0, 128, 0})}); - } - if (sn[4] == 0xf0) - { - Serial.println("Eule"); - fox = false; - ledTask.startEffect(EffectCircularConfig{360, 180, ColorRGBW{0, 0, 255, 0}}); - } - if (sn[4] == 0xe9) - { - Serial.println("Elephant"); - fox = true; - ledTask.startEffect(EffectAlexaSwipeConfig{20, 30, 3 * 360, 3, 180, true, ColorRGBW{0, 0, 255, 0}, ColorRGBW{0, 200, 255, 0}}); - delay(1000); - ledTask.startEffect(EffectRandomTwoColorInterpolationConfig{6000, true, 3, false, false, rgb2hsv(ColorRGBW{0, 0, 255, 0}), - rgb2hsv(ColorRGBW{0, 200, 255, 0})}); - } - } else - { - Serial.println("Nichts"); - if (fox) - { - fox = false; - ledTask.startEffect(EffectAlexaSwipeConfig{20, 30, 3 * 360, 3, 180, false, ColorRGBW{0, 255, 0, 0}, ColorRGBW{0, 0, 255, 0}}); - } - else - ledTask.startEffect(EffectStaticConfig{ColorRGBW{0, 0, 0, 0}}); - } - //led.transmit(); + sendMessageToHost(MsgRfidTokenRead{{0, 0, 0, 0, 0}}); } -QueueHandle_t event_queue; -rotary_encoder_info_t info; -void setup() +void setupRfidReader() { - Serial.begin(115200); - - //led.begin(); - ledDriver.begin(23, 0); - const rc522_start_args_t start_args = { 21, // MISO 5, // MOSI 18, // SCK 19, // SDA VSPI_HOST, - &tag_handler, + &tagHandler, 125, // scan_interval_ms 8 * 1024, // stacksize 4 // task priority }; rc522_start(start_args); +} +// -------------------------------------------------- Rotary Enc ---------------------------------------- +QueueHandle_t eventQueueRotaryEncoder; +rotary_encoder_info_t info; + +void setupRotaryEncoder() +{ ESP_ERROR_CHECK(gpio_install_isr_service(0)); ESP_ERROR_CHECK(rotary_encoder_init(&info, GPIO_NUM_26, GPIO_NUM_27)); ESP_ERROR_CHECK(rotary_encoder_enable_half_steps(&info, false)); - event_queue = rotary_encoder_create_queue(); - ESP_ERROR_CHECK(rotary_encoder_set_queue(&info, event_queue)); - - //button leds - //pinMode(33, OUTPUT); - //digitalWrite(33, HIGH); - //pinMode(12, OUTPUT); - //digitalWrite(12, HIGH); - - //// button in - //pinMode(25, INPUT_PULLUP); - //pinMode(14, INPUT_PULLUP); - //pinMode(13, INPUT_PULLUP); - ledTask.begin(ledStrip, ledDriver); - ledTask.startEffect(EffectStaticConfig{ColorRGBW{0, 0, 0, 0}}); + eventQueueRotaryEncoder = rotary_encoder_create_queue(); + ESP_ERROR_CHECK(rotary_encoder_set_queue(&info, eventQueueRotaryEncoder)); } -bool btn2state = true; +// -------------------------------------------------- Led circle ---------------------------------------- +LedStripRGBW<51> ledStripCircle; +Esp32DriverRGBW ledDriverCircle; +LedTask ledTaskCircle; + +void setupLedCircle() +{ + ledDriverCircle.begin(23, 0); + ledTaskCircle.begin(ledStripCircle, ledDriverCircle); + ledTaskCircle.startEffect(EffectStaticConfig{ColorRGBW{0, 0, 0, 0}}); +} + +//------------------------------------------------------------------------------------------------------- + +void setup() +{ + Serial.begin(115200); + setupRfidReader(); + setupRotaryEncoder(); + setupLedCircle(); +} void loop() { - handleIncomingMessagesFromHost(&ledTask); + handleIncomingMessagesFromHost(&ledTaskCircle); } \ No newline at end of file