diff --git a/include/led_stub.h b/include/led_stub.h index b3cf338..eeab58e 100644 --- a/include/led_stub.h +++ b/include/led_stub.h @@ -27,7 +27,7 @@ class PixelStompMux; class DefaultLedStub : public LedStub { private: - static const uint8_t NUM_LEDS = 10; + static const uint8_t NUM_LEDS = 8; LedState led_states[NUM_LEDS]; bool initialized; diff --git a/include/pixel_stomp_mux.h b/include/pixel_stomp_mux.h index 905a57c..83f0164 100644 --- a/include/pixel_stomp_mux.h +++ b/include/pixel_stomp_mux.h @@ -1,22 +1,24 @@ #pragma once #include +#include class PixelStompMux { public: - static const uint8_t NUM_INPUTS = 10; - static const uint8_t NUM_OUTPUTS = 10; + static const uint8_t NUM_BUTTONS = 8; + static const uint8_t NUM_LEDS = 8; PixelStompMux(uint8_t dat_pin, uint8_t ld_pin, uint8_t clk_pin, uint8_t di_pin); void begin(); - uint16_t read_buttons(); + uint8_t read_buttons(); bool is_button_pressed(uint8_t index); - void write_leds(uint16_t led_state); - void set_led(uint8_t index, bool on); + void set_led_color(uint8_t index, uint8_t r, uint8_t g, uint8_t b); + void set_led_brightness(uint8_t brightness); void clear_all(); + void show(); void dump(); @@ -26,10 +28,9 @@ private: uint8_t pin_clk; uint8_t pin_di; - uint16_t last_button_state; - uint16_t current_led_state; + Adafruit_NeoPixel* strip; - void shift_out(uint16_t data, uint8_t bits); - uint16_t shift_in(uint8_t bits); - void pulse_pin(uint8_t pin, uint8_t level, uint16_t duration_us = 1); + uint8_t last_button_state; + + uint8_t shift_in_74hc165(); }; diff --git a/include/switch_stub.h b/include/switch_stub.h index 166fdfd..06df66e 100644 --- a/include/switch_stub.h +++ b/include/switch_stub.h @@ -25,7 +25,7 @@ class PixelStompMux; class DefaultSwitchStub : public SwitchStub { private: - static const uint8_t NUM_SWITCHES = 10; + static const uint8_t NUM_SWITCHES = 8; SwitchState switch_states[NUM_SWITCHES]; bool initialized; diff --git a/platformio.ini b/platformio.ini index 596ea06..55a86ec 100644 --- a/platformio.ini +++ b/platformio.ini @@ -8,6 +8,7 @@ framework = arduino lib_deps = adafruit/Adafruit TinyUSB Library@^2.0.0 + adafruit/Adafruit NeoPixel@^1.12.0 build_flags = -DARDUINO_USB_MODE=1 diff --git a/src/led_stub.cpp b/src/led_stub.cpp index 3ff7cd2..07c72ae 100644 --- a/src/led_stub.cpp +++ b/src/led_stub.cpp @@ -19,34 +19,47 @@ void DefaultLedStub::set_mux(PixelStompMux* mux) { } void DefaultLedStub::begin() { - Serial.println("[LED] Using PixelStomp MUX for LED output"); + Serial.println("[LED] Using WS2812C via PixelStomp MUX"); initialized = true; + if (!mux_ptr) { + Serial.println("[LED] ERROR: No MUX configured"); + return; + } + Serial.println("[LED] Startup animation..."); - for (int i = 0; i < NUM_LEDS; i++) { - if (mux_ptr) { - mux_ptr->set_led(i, true); + uint32_t colors[] = { + 0xFF0000, // Red + 0x00FF00, // Green + 0x0000FF, // Blue + 0xFFFF00, // Yellow + 0xFF00FF, // Magenta + 0x00FFFF, // Cyan + 0xFFFFFF, // White + }; + int num_colors = sizeof(colors) / sizeof(colors[0]); + + for (int c = 0; c < num_colors; c++) { + uint32_t color = colors[c]; + uint8_t r = (color >> 16) & 0xFF; + uint8_t g = (color >> 8) & 0xFF; + uint8_t b = color & 0xFF; + + for (int i = 0; i < NUM_LEDS; i++) { + mux_ptr->set_led_color(i, r, g, b); } - Serial.printf("[LED] LED %d ON\n", i); - delay(150); - } - - delay(300); - - for (int i = NUM_LEDS - 1; i >= 0; i--) { - if (mux_ptr) { - mux_ptr->set_led(i, false); - } - Serial.printf("[LED] LED %d OFF\n", i); - delay(100); + mux_ptr->show(); + Serial.printf("[LED] Colour %d: R=%d G=%d B=%d\n", c, r, g, b); + delay(200); } + clear_all(); Serial.println("[LED] Startup complete"); } void DefaultLedStub::set_led_state(uint8_t note, uint8_t channel, uint8_t velocity) { - if (!initialized) return; + if (!initialized || !mux_ptr) return; uint8_t led_index = note_to_index(note); @@ -57,9 +70,13 @@ void DefaultLedStub::set_led_state(uint8_t note, uint8_t channel, uint8_t veloci led_states[led_index].active = (velocity > 0); led_states[led_index].timestamp = millis(); - if (mux_ptr) { - mux_ptr->set_led(led_index, velocity > 0); + if (velocity > 0) { + uint8_t brightness = map(velocity, 1, 127, 30, 255); + mux_ptr->set_led_color(led_index, brightness, brightness, brightness); + } else { + mux_ptr->set_led_color(led_index, 0, 0, 0); } + mux_ptr->show(); Serial.printf("[LED] Note %d -> LED %d Ch %d Vel %d (%s)\n", note, led_index, channel, velocity, diff --git a/src/main.cpp b/src/main.cpp index 7258e99..6bdd5b5 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -31,45 +31,45 @@ void handle_serial_command(const String& cmd) { if (cmd == "dump" || cmd == "d") { mux.dump(); } else if (cmd == "ledon") { - for (int i = 0; i < 10; i++) { - mux.set_led(i, true); - delay(50); + for (int i = 0; i < 8; i++) { + mux.set_led_color(i, 255, 255, 255); } + mux.show(); Serial.println("[CMD] All LEDs ON"); } else if (cmd == "ledoff") { mux.clear_all(); } else if (cmd == "ledtest") { - for (int i = 0; i < 10; i++) { - mux.set_led(i, true); - delay(200); - mux.set_led(i, false); - delay(100); + uint32_t colors[] = {0xFF0000, 0x00FF00, 0x0000FF, 0xFFFF00, 0xFF00FF, 0x00FFFF}; + for (int c = 0; c < 6; c++) { + uint8_t r = (colors[c] >> 16) & 0xFF; + uint8_t g = (colors[c] >> 8) & 0xFF; + uint8_t b = colors[c] & 0xFF; + for (int i = 0; i < 8; i++) { + mux.set_led_color(i, r, g, b); + } + mux.show(); + delay(300); } + mux.clear_all(); Serial.println("[CMD] LED test complete"); } else if (cmd == "read") { - uint16_t raw = mux.read_buttons(); - Serial.printf("[CMD] Raw button state: 0x%03X (binary: ", raw); - for (int i = 9; i >= 0; i--) { + uint8_t raw = mux.read_buttons(); + Serial.printf("[CMD] Raw: 0x%02X (", raw); + for (int i = 7; i >= 0; i--) { Serial.print((raw >> i) & 1); } Serial.println(")"); - } else if (cmd == "probe") { - Serial.println("[CMD] Probing MUX pins..."); - Serial.printf(" DAT (GPIO %d) = %d\n", 9, digitalRead(9)); - Serial.printf(" LD (GPIO %d) = %d\n", 10, digitalRead(10)); - Serial.printf(" CLK (GPIO %d) = %d\n", 11, digitalRead(11)); - Serial.printf(" DI (GPIO %d) = %d\n", 12, digitalRead(12)); - - Serial.println(" Toggling LD pin..."); - for (int i = 0; i < 5; i++) { - digitalWrite(10, HIGH); - delayMicroseconds(100); - digitalWrite(10, LOW); - delayMicroseconds(100); - } - Serial.printf(" DI after LD toggle: %d\n", digitalRead(12)); + } else if (cmd == "red") { + for (int i = 0; i < 8; i++) mux.set_led_color(i, 255, 0, 0); + mux.show(); + } else if (cmd == "green") { + for (int i = 0; i < 8; i++) mux.set_led_color(i, 0, 255, 0); + mux.show(); + } else if (cmd == "blue") { + for (int i = 0; i < 8; i++) mux.set_led_color(i, 0, 0, 255); + mux.show(); } else { - Serial.println("[CMD] Commands: dump, ledon, ledoff, ledtest, read, probe"); + Serial.println("[CMD] Commands: dump, ledon, ledoff, ledtest, read, red, green, blue"); } } diff --git a/src/pixel_stomp_mux.cpp b/src/pixel_stomp_mux.cpp index 9cae4d3..4450bab 100644 --- a/src/pixel_stomp_mux.cpp +++ b/src/pixel_stomp_mux.cpp @@ -3,116 +3,85 @@ PixelStompMux::PixelStompMux(uint8_t dat, uint8_t ld, uint8_t clk, uint8_t di) : pin_dat(dat), pin_ld(ld), pin_clk(clk), pin_di(di), - last_button_state(0), current_led_state(0) { + strip(nullptr), last_button_state(0) { } void PixelStompMux::begin() { - pinMode(pin_dat, OUTPUT); pinMode(pin_ld, OUTPUT); pinMode(pin_clk, OUTPUT); pinMode(pin_di, INPUT_PULLUP); - digitalWrite(pin_dat, LOW); digitalWrite(pin_ld, LOW); digitalWrite(pin_clk, LOW); + strip = new Adafruit_NeoPixel(NUM_LEDS, pin_dat, NEO_GRB + NEO_KHZ800); + strip->begin(); + strip->setBrightness(50); + strip->clear(); + strip->show(); + Serial.printf("[MUX] Init DAT=%d LD=%d CLK=%d DI=%d\n", pin_dat, pin_ld, pin_clk, pin_di); - - Serial.println("[MUX] GPIO probe:"); - Serial.printf(" DI (GPIO %d) reads: %d (should be 1 with pullup)\n", - pin_di, digitalRead(pin_di)); - - for (int i = 0; i < 3; i++) { - digitalWrite(pin_clk, HIGH); - delayMicroseconds(10); - digitalWrite(pin_clk, LOW); - delayMicroseconds(10); - } - Serial.printf(" DI after 3 CLK pulses: %d\n", digitalRead(pin_di)); - - digitalWrite(pin_ld, HIGH); - delayMicroseconds(10); - digitalWrite(pin_ld, LOW); - delayMicroseconds(10); - Serial.printf(" DI after LD pulse: %d\n", digitalRead(pin_di)); + Serial.printf("[MUX] 74HC165 for %d buttons, WS2812C for %d LEDs\n", + NUM_BUTTONS, NUM_LEDS); } -uint16_t PixelStompMux::read_buttons() { - pulse_pin(pin_ld, HIGH); - delayMicroseconds(10); - pulse_pin(pin_ld, LOW); - delayMicroseconds(10); +uint8_t PixelStompMux::read_buttons() { + digitalWrite(pin_ld, HIGH); + delayMicroseconds(5); + digitalWrite(pin_ld, LOW); + delayMicroseconds(5); - uint16_t state = shift_in(NUM_INPUTS); - last_button_state = state; - - return state; + last_button_state = shift_in_74hc165(); + return last_button_state; } bool PixelStompMux::is_button_pressed(uint8_t index) { - if (index >= NUM_INPUTS) return false; - - uint16_t state = read_buttons(); + if (index >= NUM_BUTTONS) return false; + uint8_t state = read_buttons(); return !(state & (1 << index)); } -void PixelStompMux::write_leds(uint16_t led_state) { - current_led_state = led_state; - shift_out(led_state, NUM_OUTPUTS); - - pulse_pin(pin_ld, HIGH); - delayMicroseconds(10); - pulse_pin(pin_ld, LOW); +void PixelStompMux::set_led_color(uint8_t index, uint8_t r, uint8_t g, uint8_t b) { + if (index >= NUM_LEDS || !strip) return; + strip->setPixelColor(index, strip->Color(r, g, b)); } -void PixelStompMux::set_led(uint8_t index, bool on) { - if (index >= NUM_OUTPUTS) return; - - if (on) { - current_led_state |= (1 << index); - } else { - current_led_state &= ~(1 << index); - } - - write_leds(current_led_state); +void PixelStompMux::set_led_brightness(uint8_t brightness) { + if (strip) strip->setBrightness(brightness); } void PixelStompMux::clear_all() { - write_leds(0x0000); - Serial.println("[MUX] All LEDs off"); + if (strip) { + strip->clear(); + strip->show(); + } + Serial.println("[MUX] LEDs cleared"); +} + +void PixelStompMux::show() { + if (strip) strip->show(); } void PixelStompMux::dump() { - uint16_t buttons = read_buttons(); - Serial.printf("[MUX] Buttons: 0x%03X LEDs: 0x%03X\n", buttons, current_led_state); + uint8_t buttons = read_buttons(); + Serial.printf("[MUX] Buttons: 0x%02X (binary: ", buttons); + for (int i = 7; i >= 0; i--) { + Serial.print((buttons >> i) & 1); + } + Serial.println(")"); - for (int i = 0; i < NUM_INPUTS; i++) { + for (int i = 0; i < NUM_BUTTONS; i++) { bool pressed = !(buttons & (1 << i)); - bool led_on = current_led_state & (1 << i); - Serial.printf(" [%d] Button:%s LED:%s\n", i, - pressed ? "PRESS" : "off", - led_on ? "ON" : "off"); + Serial.printf(" [%d] %s\n", i, pressed ? "PRESS" : "off"); } } -void PixelStompMux::shift_out(uint16_t data, uint8_t bits) { - for (int i = bits - 1; i >= 0; i--) { - digitalWrite(pin_dat, (data >> i) & 1); - delayMicroseconds(1); - digitalWrite(pin_clk, HIGH); - delayMicroseconds(1); - digitalWrite(pin_clk, LOW); - delayMicroseconds(1); - } -} +uint8_t PixelStompMux::shift_in_74hc165() { + uint8_t data = 0; -uint16_t PixelStompMux::shift_in(uint8_t bits) { - uint16_t data = 0; - - for (int i = bits - 1; i >= 0; i--) { - bool bit = digitalRead(pin_di); - if (bit) { + for (int i = NUM_BUTTONS - 1; i >= 0; i--) { + if (digitalRead(pin_di)) { data |= (1 << i); } digitalWrite(pin_clk, HIGH); @@ -123,8 +92,3 @@ uint16_t PixelStompMux::shift_in(uint8_t bits) { return data; } - -void PixelStompMux::pulse_pin(uint8_t pin, uint8_t level, uint16_t duration_us) { - digitalWrite(pin, level); - delayMicroseconds(duration_us); -} diff --git a/src/switch_stub.cpp b/src/switch_stub.cpp index 2541990..3255f00 100644 --- a/src/switch_stub.cpp +++ b/src/switch_stub.cpp @@ -16,7 +16,7 @@ DefaultSwitchStub::DefaultSwitchStub() : initialized(false) { } void DefaultSwitchStub::begin() { - Serial.println("[SW] Using PixelStomp MUX for button input"); + Serial.println("[SW] Using 74HC165 via PixelStomp MUX"); initialized = true; }