diff --git a/ChunithmIO/ChunithmIO.ino b/ChunithmIO/ChunithmIO.ino index 65631d5..72ac4bc 100644 --- a/ChunithmIO/ChunithmIO.ino +++ b/ChunithmIO/ChunithmIO.ino @@ -1,77 +1,239 @@ #include #include -#define LEFT_PIN 5 -#define RIGHT_PIN 6 -#define NUM_LEDS 3 +#include + +#define LEFT_PIN 5 +#define RIGHT_PIN 6 +#define NUM_LEDS 3 CRGB left_leds[NUM_LEDS]; CRGB right_leds[NUM_LEDS]; +CRGB left_color = CRGB::Blue; +CRGB right_color = CRGB::Red; +float dead_color_ratio = 0.15; +CRGB left_color_dead = CRGB::Black; +CRGB right_color_dead = CRGB::Black; +int light_up_speed = 10; +int light_down_speed = 3; +byte led_mode = 0; +byte bg_mode = 1; +bool leDebug = false; + +void setBackgroundToRatiod() { + CHSV tmp_left_color_dead; + CHSV tmp_right_color_dead; + + tmp_left_color_dead = rgb2hsv_approximate(left_color); + tmp_left_color_dead.v = tmp_left_color_dead.v * dead_color_ratio; + left_color_dead = hsv2rgb_spectrum(tmp_left_color_dead); + + tmp_right_color_dead = rgb2hsv_approximate(right_color); + tmp_right_color_dead.v = tmp_right_color_dead.v * dead_color_ratio; + right_color_dead = hsv2rgb_spectrum(tmp_right_color_dead); +} + +void setBackgroundToBlack() { + left_color_dead = CRGB::Black; + right_color_dead = CRGB::Black; +} + +void setBackgroundToStatic() { + left_color_dead = left_color; + right_color_dead = right_color; +} + +void setLedsToCustom() { +} +void choosePreset(byte predef_led_mode); void setup() { - Keyboard.begin(); - FastLED.addLeds(left_leds, NUM_LEDS).setCorrection( TypicalLEDStrip ); - FastLED.addLeds(right_leds, NUM_LEDS).setCorrection( TypicalLEDStrip ); - FastLED.setBrightness(64); - delay(1000); - fill_solid(left_leds, NUM_LEDS, CRGB(0x7F,0,0x23)); - fill_solid(right_leds, NUM_LEDS, CRGB(0x7F,0,0x23)); - FastLED.show(); - pinMode(8, INPUT_PULLUP); - pinMode(9, INPUT_PULLUP); - pinMode(10, INPUT_PULLUP); - pinMode(11, INPUT_PULLUP); - pinMode(12, INPUT_PULLUP); - pinMode(13, INPUT_PULLUP); - delay(1000); + Keyboard.begin(); + //"service" button + pinMode(3, INPUT_PULLUP); + //sensors + pinMode(8, INPUT_PULLUP); + pinMode(9, INPUT_PULLUP); + pinMode(10, INPUT_PULLUP); + pinMode(14, INPUT_PULLUP); + pinMode(15, INPUT_PULLUP); + pinMode(16, INPUT_PULLUP); + + FastLED.addLeds(left_leds, NUM_LEDS).setCorrection(TypicalLEDStrip); + FastLED.addLeds(right_leds, NUM_LEDS).setCorrection(TypicalLEDStrip); + FastLED.setBrightness(96); + delay(1000); + fill_solid(left_leds, NUM_LEDS, CRGB::Red); + fill_solid(right_leds, NUM_LEDS, CRGB::Red); + FastLED.show(); + delay(1000); + fill_solid(left_leds, NUM_LEDS, CRGB::Lime); + fill_solid(right_leds, NUM_LEDS, CRGB::Lime); + FastLED.show(); + delay(1000); + fill_solid(left_leds, NUM_LEDS, CRGB::Blue); + fill_solid(right_leds, NUM_LEDS, CRGB::Blue); + FastLED.show(); + delay(1000); + if (digitalRead(3) == LOW) { + leDebug = !leDebug; + } + EEPROM.get(1, bg_mode); + EEPROM.get(2, led_mode); + choosePreset(led_mode); +} + +void choosePreset(byte predef_led_mode = 255) { + if (predef_led_mode == 255) { + led_mode = 0; + if (digitalRead(8)) { bitSet(led_mode, 0); } + if (digitalRead(14)) { bitSet(led_mode, 1); } + if (digitalRead(9)) { bitSet(led_mode, 2); } + } + else{ + led_mode = predef_led_mode; + } + + if (digitalRead(10) && !digitalRead(16)) { + bg_mode = 0; + } + if (!digitalRead(10) && digitalRead(16)) { + bg_mode = 1; + } + if (digitalRead(10) && digitalRead(16)) { + bg_mode = 2; + } + + switch (led_mode) { + default: + case 0: + // basic + left_color = CRGB::White; + right_color = CRGB::White; + break; + case 1: + // beat saber + left_color = CRGB::Red; + right_color = CRGB::Blue; + break; + case 2: + // sound voltex + left_color = CRGB::Aqua; + right_color = CRGB::DarkMagenta; + break; + case 3: + // paprykarz + left_color = CRGB::Yellow; + right_color = CRGB::Red; + break; + case 4: + // something reddish + left_color = CRGB::MediumVioletRed; + right_color = CRGB::MediumVioletRed; + break; + case 5: + // something greenish + left_color = CRGB::Lime; + right_color = CRGB::Lime; + break; + case 6: + // something blue-ish + left_color = CRGB::DeepSkyBlue; + right_color = CRGB::DeepSkyBlue; + break; + case 7: + // nothing + left_color = CRGB::Black; + right_color = CRGB::Black; + break; + } + switch (bg_mode) { + default: + case 1: + setBackgroundToRatiod(); + break; + case 0: + setBackgroundToBlack(); + break; + case 2: + setBackgroundToStatic(); + break; + } + updateLeds(); } +void updateLeds() { + if (digitalRead(8) == HIGH or digitalRead(14) == HIGH) { + left_leds[2] = CRGB(constrain(left_leds[2].r + light_up_speed, left_color_dead.r, left_color.r), constrain(left_leds[2].g + light_up_speed, left_color_dead.g, left_color.g), constrain(left_leds[2].b + light_up_speed, left_color_dead.b, left_color.b)); + right_leds[2] = CRGB(constrain(right_leds[2].r + light_up_speed, right_color_dead.r, right_color.r), constrain(right_leds[2].g + light_up_speed, right_color_dead.g, right_color.g), constrain(right_leds[2].b + light_up_speed, right_color_dead.b, right_color.b)); + FastLED.show(); + } else { + left_leds[2] = CRGB(constrain(left_leds[2].r - light_down_speed, left_color_dead.r, left_color.r), constrain(left_leds[2].g - light_down_speed, left_color_dead.g, left_color.g), constrain(left_leds[2].b - light_down_speed, left_color_dead.b, left_color.b)); + right_leds[2] = CRGB(constrain(right_leds[2].r - light_down_speed, right_color_dead.r, right_color.r), constrain(right_leds[2].g - light_down_speed, right_color_dead.g, right_color.g), constrain(right_leds[2].b - light_down_speed, right_color_dead.b, right_color.b)); + FastLED.show(); + } + + if (digitalRead(9) == HIGH or digitalRead(15) == HIGH) { + left_leds[1] = CRGB(constrain(left_leds[1].r + light_up_speed, left_color_dead.r, left_color.r), constrain(left_leds[1].g + light_up_speed, left_color_dead.g, left_color.g), constrain(left_leds[1].b + light_up_speed, left_color_dead.b, left_color.b)); + right_leds[1] = CRGB(constrain(right_leds[1].r + light_up_speed, right_color_dead.r, right_color.r), constrain(right_leds[1].g + light_up_speed, right_color_dead.g, right_color.g), constrain(right_leds[1].b + light_up_speed, right_color_dead.b, right_color.b)); + FastLED.show(); + } else { + left_leds[1] = CRGB(constrain(left_leds[1].r - light_down_speed, left_color_dead.r, left_color.r), constrain(left_leds[1].g - light_down_speed, left_color_dead.g, left_color.g), constrain(left_leds[1].b - light_down_speed, left_color_dead.b, left_color.b)); + right_leds[1] = CRGB(constrain(right_leds[1].r - light_down_speed, right_color_dead.r, right_color.r), constrain(right_leds[1].g - light_down_speed, right_color_dead.g, right_color.g), constrain(right_leds[1].b - light_down_speed, right_color_dead.b, right_color.b)); + FastLED.show(); + } + + if (digitalRead(10) == HIGH or digitalRead(16) == HIGH) { + left_leds[0] = CRGB(constrain(left_leds[0].r + light_up_speed, left_color_dead.r, left_color.r), constrain(left_leds[0].g + light_up_speed, left_color_dead.g, left_color.g), constrain(left_leds[0].b + light_up_speed, left_color_dead.b, left_color.b)); + right_leds[0] = CRGB(constrain(right_leds[0].r + light_up_speed, right_color_dead.r, right_color.r), constrain(right_leds[0].g + light_up_speed, right_color_dead.g, right_color.g), constrain(right_leds[0].b + light_up_speed, right_color_dead.b, right_color.b)); + FastLED.show(); + } else { + left_leds[0] = CRGB(constrain(left_leds[0].r - light_down_speed, left_color_dead.r, left_color.r), constrain(left_leds[0].g - light_down_speed, left_color_dead.g, left_color.g), constrain(left_leds[0].b - light_down_speed, left_color_dead.b, left_color.b)); + right_leds[0] = CRGB(constrain(right_leds[0].r - light_down_speed, right_color_dead.r, right_color.r), constrain(right_leds[0].g - light_down_speed, right_color_dead.g, right_color.g), constrain(right_leds[0].b - light_down_speed, right_color_dead.b, right_color.b)); + FastLED.show(); + } +} + + void loop() { - if (digitalRead(8) == HIGH) - { - Keyboard.press('a'); - } - else - { - Keyboard.release('a'); - } - if (digitalRead(11) == HIGH) - { - Keyboard.press('b'); - } - else - { - Keyboard.release('b'); - } - if (digitalRead(9) == HIGH) - { - Keyboard.press('c'); - } - else - { - Keyboard.release('c'); - } - if (digitalRead(12) == HIGH) - { - Keyboard.press('d'); - } - else - { - Keyboard.release('d'); - } - if (digitalRead(10) == HIGH) - { - Keyboard.press('e'); - } - else - { - Keyboard.release('e'); - } - if (digitalRead(13) == HIGH) - { - Keyboard.press('f'); - } - else - { - Keyboard.release('f'); - } + if (digitalRead(8) == HIGH) { + if (!leDebug) { Keyboard.press('a'); } + } else { + if (!leDebug) { Keyboard.release('a'); } + } + if (digitalRead(14) == HIGH) { + if (!leDebug) Keyboard.press('b'); + } else { + if (!leDebug) Keyboard.release('b'); + } + if (digitalRead(9) == HIGH) { + if (!leDebug) Keyboard.press('c'); + } else { + if (!leDebug) Keyboard.release('c'); + } + if (digitalRead(15) == HIGH) { + if (!leDebug) Keyboard.press('d'); + } else { + if (!leDebug) Keyboard.release('d'); + } + if (digitalRead(10) == HIGH) { + if (!leDebug) Keyboard.press('e'); + } else { + if (!leDebug) Keyboard.release('e'); + } + if (digitalRead(16) == HIGH) { + if (!leDebug) Keyboard.press('f'); + } else { + if (!leDebug) Keyboard.release('f'); + } + + + updateLeds(); + + while (digitalRead(3) == LOW) { + while (digitalRead(3) == LOW) { + choosePreset(); + } + EEPROM.put(1, bg_mode); + EEPROM.put(2, led_mode); + } } diff --git a/README.md b/README.md index a261580..29b00a9 100644 --- a/README.md +++ b/README.md @@ -1,63 +1,84 @@ -# ChunithmIO +# ChunithmIO Lightning Model -Use a Chunithm control panel on PC +Use a Chunithm control panel on PC! -# Overview +This fork adds reactive lightning to the air towers, and in the future maybe some on-boot preset settings selection. -The Chunithm panel is made of air towers and a touch slider. +Oh and the pinout is slightly changed from the upstream, to work with a Pro Micro board. -## Air towers +> [!WARNING] +> Due to the LED code here being so simple, you **must** have a relatively recent version of the FastLED library installed, otherwise, your air tower LEDs will flicker. I'm not sure which would be the minimum required, but **3.9.4** is proven to work. -The air towers are made of 6 photo interrupters and 2 led strips which can be interfaced with an arduino. See `ChunithmIO` for a firmware example which turns them into a keyboard device. +## Overview -## Touch slider +The Chunithm panel is made of air towers and a ground slider. -The touch slider is an rs232 device and can be connected directly to the PC for native use. This repo contains a python script to help verify correct wiring. See `slidertest` folder readme for more info. +### Air towers -# Advanced usage +The air towers are made of 6 photo interrupters and 2 LED strips which can be interfaced with an Arduino. See `ChunithmIO` for a firmware example which turns them into a keyboard device. -A better featured PCB is in the works allowing custom light effects, use of the touch slider as an HID compliant touchpad for use with android games, etc... more info coming soon. +In this example, each IR sensor responds 1:1 to a key, i.e. when covered, the key is pressed, and when uncovered, the key is released. Going from the bottom to the top the keys are `a`, `b`, `c`, `d`, `e`, `f`. Their keycodes are as follows -# pinout +``` +ir1=0x41 +ir2=0x42 +ir3=0x43 +ir4=0x44 +ir5=0x45 +ir6=0x46 +``` -Diagrams coming soon. +As each tower has 3 sensors and 3 emitters, so if you switch sides when wiring them up, the keys will get shuffled into the following order: `b`, `a`, `d`, `c`, `f`, `e`. -## slider +### Ground Slider -### YLP-03V (connects into an YLR-03V) +The Ground Slider is an RS232 device and can be connected directly to the PC for native use. This repo contains a python script to help verify correct wiring. See `slidertest` folder readme for more info. +It's the best to keep the slider connected to the `COM1` port. -This is the power input connector. Goes to a 12V wall PSU. +## Pinout -- Yellow is +12V. Goes to wall PSU +12V. -- Black is GND. Goes to wall PSU GND. -- Green is EARTH. Can be left disconnected. +If you are this deep, you will surely be fine without diagrams. Especially since everything is pretty self-explanatory and all pin holes in JST plugs are clearly **numbered**. -### SMR-04V (connects into an SMP-04V) +### Ground Slider + +#### YLP-03V (connects into an YLR-03V) + +This is the power input connector. Goes to a 12V source. You will most likely use a dedicated 12V wall adapter, but you can get creative here (e.g. get a Molex plug or a PD charger and trigger). + +- yellow - +12V +- black - GND +- green - earth (can be left disconnected) + +#### SMR-04V (connects into an SMP-04V) This is the serial input/output connector. Goes to your RS232 adapter. -- White is RX (db9 pin 2) -- Red is TX (db9 pin 3) -- Black is GND (db9 pin 5) +- white (RX) - DB9 pin 2 +- red (TX) - DB9 pin 3 +- black (GND) - DB9 pin 5 + +### Air towers + +#### YLP-15V (connects into an YLR-15V) -## air tower +This is the air strings (sensors) connector. -### YLP-15V (connects into an YLR-15V) +- 1 (red) - to Arduino +5V (may be marked `RAW` on the PCB), +- 2 to 7 (stripped grey) - to the other tower pins 2 to 7, +- 8 to 10 (stripped white) - to the Arduino GPIO 8, 9, and 10 (left tower) or 14, 15, and 16 (right tower), +- 11 and 12 (black) - to Arduino GND, +- 15 (green) - earth (can be left disconnected) -This is the air strings connector +#### YLP-06V (connects into an YLR-06V) -- 1 RED: to arduino +5V. -- 2 to 7 stripped grey: to the other tower pins 2 to 7. -- 8 to 10 stripped white: to the arduino gpio 8 9 10 (left tower) or 11 12 13 (right tower). -- 11 12 black: to arduino GND. -- 15 green: Can be left disconnected. +This is the LED strip connector. Needs a 12V source. Yes, **another 12V** line. But it can be connected in parallel with slider's 12V supply (keeping in mind the wire gauge and the rated power of your 12V source). -### YLP-06V (connects into an YLR-06V) +- yellow - +12V +- striped white - LED data - goes to Arduino GPIO 5 (blue - left tower) or 6 (orange - right tower). +- black GND - goes to power supply GND and Arduino GND (but they are probably common ground anyway) -This is the ledstrip connector. Needs a 12V wall PSU. +The LEDs are WS2811 in RGB order, with 9 LEDs per strip. They are, however, wired such that each WS2811 ID controls a group of 3 actual LEDs, so it's not possible to control each one separately. It comes out to 2 sensors per group of 3 LEDs. -- Yellow is +12V. Goes to wall PSU +12V. -- White with stripes is LED data. Goes to arduino gpio 5 (left tower) or 6 (right tower). -- Black is GND. Goes to wall PSU GND and arduino GND. +## Power considerations -Leds are ws2811 in RGB order, with 9 leds per strip. +According to rough calculations done on the Cons&Stuff Discord server, all LEDs in the whole panel assembly (slider + towers) could draw as much as 18W. However, such situation is highly unlikely, with 15W being suggested to have a reasonable margin already. And on top of that, people's experiences show that a 12W PSUs are fine. \ No newline at end of file