#ifndef BUZZER_H #define BUZZER_H #include "ESP8266lib/net/UDP.h" #include "ESP8266lib/net/IP.h" #include "ESP8266lib/net/MAC.h" #include "ESP8266lib/net/WiFiRaw.h" #include "ESP8266lib/io/IO.h" #include "Fader.h" #include "FadeOnce.h" #include "Rainbow.h" #include "RainbowBeat.h" #define FIRMWARE_NR 10 #define CODE(a, b, c, d) (a << 24 | b << 16 | c << 8 | d) enum LEDMode { OFF, FIXED_COLOR, RAINBOW_COLOR, FADE_BETWEEN_COLOR, FADE_ONCE, STROBO_COLOR, RAINBOW_BEAT, }; class Buzzer; extern Buzzer buzzer; class Buzzer { private: static constexpr const char* NAME = "Buzzer"; UDP udp; IP server = IP(); WS2812B<1> leds; LEDMode ledMode; WiFiRaw::MACAddress myMac; FadeBetween fadeBetween; FadeOnce fadeOnce; Rainbow rainbow; RainbowBeat rainbowBeat; public: /** ctor */ Buzzer() { debugMod(NAME, "ctor()"); udp.bind(localPort); udp.setRecvCallback(&Buzzer::onUDP); ledMode = LEDMode::FIXED_COLOR; myMac = WiFiRaw::getMyMAC(); // buzzer interrupt (Pin D2) GPIO4_INPUT_SET; GPIO4_INPUT_PULLUP_SET; // interrupt //ETS_GPIO_INTR_DISABLE(); //ETS_GPIO_INTR_ATTACH(isrRoutine, this); //gpio_pin_intr_state_set(GPIO_ID_PIN(4), GPIO_PIN_INTR_ANYEDGE); //ETS_GPIO_INTR_ENABLE(); } /** send a heartbeat packet */ void sendHeartbeat() { const uint16_t vcc = ADC::getVcc(); os_printf("send: heartbeat, Vcc: %d\n", vcc); char data[5+6+2+3]; os_memcpy(&data[0], "*PING", 5); os_memcpy(&data[5], myMac.asPtr(), 6); data[11] = '_'; data[12] = FIRMWARE_NR; data[13] = '_'; data[14] = (vcc >> 8) & 0xFF; data[15] = (vcc >> 0) & 0xFF; udp.send(remoteIP, remotePort, data, sizeof(data)); } /** send a buzzer packet */ void sendBuzzer() { char data[5+12]; os_memcpy(&data[0], "*BUZZ", 5); os_memcpy(&data[5], myMac.asPtr(), 12); udp.send(remoteIP, remotePort, data, 5+12); os_printf("send: buzzer\n"); } /** incoming UDP data */ void onUDP(const char* data, uint16_t len) { if (len < 2) {return;} if (data[0] == '*') { debugMod(NAME, "got command"); checkCode(&data[1]); } } void update() { static int cnt = 0; ++cnt; // every 3 seconds if (cnt % 3000 == 0) { buzzer.sendHeartbeat(); } // every 20 milliseconds if (cnt % 20 == 0) { updateLED(); } // block the buzzer for some time after buzzering static int block = 0; if (block > 0) { --block; if (block == 0) {onUnBuzzer();} } // check buzzer-state if (cnt % 20 == 0) { // buzzer currently blocked if (block > 0) {return;} static uint8_t lastVal = 1; const uint8_t curVal = GPIO4_IN; if (curVal < lastVal) { block = 1000; onBuzzer(); } lastVal = curVal; } } // buzzer button pressed void onBuzzer() { sendBuzzer(); internalLED(true); //setOff(); } void onUnBuzzer() { internalLED(false); //os_printf("free\n"); //setRainbow(); //setFade(255,0,0, 0,0,255); //setFade(180,0,16, 16,190,16); } /** wemos D1 mini only */ void internalLED(bool on) { GPIO2_OUTPUT_SET; if (on) { // LED is inverted GPIO2_L; } else { GPIO2_H; } } private: /** check the command-code behind the given char-string */ void checkCode(const char* buf) { // convert the buffer's first 4 bytes to a uint32_t for faster comparison const uint32_t code = CODE(buf[0], buf[1], buf[2], buf[3]); switch(code) { case CODE('S', 'T', 'R', 'O'): setStrobo(buf[4], buf[5], buf[6]); break; case CODE('O', 'F', 'F', ' '): setOff(); break; case CODE('S', 'R', 'G', 'B'): setRGB(buf[4], buf[5], buf[6]); break; case CODE('R', 'A', 'I', 'N'): setRainbow(); break; case CODE('F', 'A', 'D', 'E'): setFade(buf[4], buf[5], buf[6], buf[7], buf[8], buf[9]); break; case CODE('F', 'L', 'S', 'H'): setFlash(buf[4], buf[5], buf[6], buf[7], buf[8], buf[9], buf[10]); break; case CODE('R', 'A', 'I', 'R'): setRainbowBeatRestart(); break; case CODE('R', 'A', 'I', 'B'): setRainbowBeatBeat(buf[4]); break; case CODE('R', 'A', 'I', 'S'): setRainbowBeatShift(buf[4]); break; default: break; } } /** upadte the current LED output (for animations) */ void updateLED() { // fading LED color? if (ledMode == LEDMode::RAINBOW_COLOR) { rainbow.update(); leds.setColor(0, rainbow.getCurrent()); leds.flush(); } else if (ledMode == LEDMode::STROBO_COLOR) { leds.setEnabled(0, !leds.isEnabled(0)); leds.flush(); } else if (ledMode == LEDMode::FADE_BETWEEN_COLOR) { fadeBetween.update(); leds.setColor(0, fadeBetween.getCurrent()); leds.flush(); } else if (ledMode == LEDMode::FADE_ONCE) { fadeOnce.update(); leds.setColor(0, fadeOnce.getCurrent()); leds.flush(); } else if (ledMode == LEDMode::RAINBOW_BEAT) { rainbowBeat.update(); leds.setColor(0, rainbowBeat.getCurrent()); leds.flush(); } } public: /** disable LED */ void setOff() { os_printf("setOff()\n"); ledMode = LEDMode::OFF; leds.getColor(0).setRGB(0,0,255); // for testing leds.setEnabled(0, false); leds.flush(); } /** set a fixed RGB color */ void setRGB(const uint8_t r, const uint8_t g, const uint8_t b) { //debugMod(NAME, "setting LEDS to fixed RGB color"); os_printf("setRGB(%d,%d,%d)\n", r, g, b); ledMode = LEDMode::FIXED_COLOR; leds.getColor(0).setRGB(r,g,b); leds.setEnabled(0, true); leds.flush(); } /** set strobo mode */ void setStrobo(const uint8_t r, const uint8_t g, const uint8_t b) { ledMode = LEDMode::STROBO_COLOR; leds.getColor(0).setRGB(r,g,b); leds.setEnabled(0, true); leds.flush(); } /** set LED rainbow fading */ void setRainbow() { os_printf("setRainbow()\n"); rainbow.restart(); ledMode = LEDMode::RAINBOW_COLOR; leds.setEnabled(0, true); leds.flush(); } /** set LED fading between two colors */ void setFade(const uint8_t r1, const uint8_t g1, const uint8_t b1, const uint8_t r2, const uint8_t g2, const uint8_t b2) { os_printf("setFade((%d,%d,%d)(%d,%d,%d))\n", r1,g1,b1, r2,g2,b2); fadeBetween.setColor1(Color::fromRGB(r1, g1, b1)); fadeBetween.setColor2(Color::fromRGB(r2, g2, b2)); fadeBetween.restart(); ledMode = LEDMode::FADE_BETWEEN_COLOR; leds.setEnabled(0, true); } /** shortly flash the led and fade back to black */ void setFlash(const uint8_t r1, const uint8_t g1, const uint8_t b1, const uint8_t r2, const uint8_t g2, const uint8_t b2, const int ms) { fadeOnce.setColor(Color::fromRGB(r1,g1,b1), Color::fromRGB(r2,g2,b2)); fadeOnce.setFadeDuration(ms); ledMode = LEDMode::FADE_ONCE; leds.setEnabled(0, true); } /** reset the rainbow-beats HUE to 0 */ void setRainbowBeatRestart() { rainbowBeat.restart(); ledMode = LEDMode::RAINBOW_BEAT; leds.setEnabled(0, true); } /** show a beat */ void setRainbowBeatBeat(const int ms) { rainbowBeat.flash(ms); ledMode = LEDMode::RAINBOW_BEAT; leds.setEnabled(0, true); } /** show a beat */ void setRainbowBeatShift(const int increment) { rainbowBeat.shift(increment); ledMode = LEDMode::RAINBOW_BEAT; leds.setEnabled(0, true); } public: /** udp callback */ static void onUDP(void*, char* data, unsigned short len) { debugMod(NAME, "got udp data"); buzzer.onUDP(data, len); } }; #endif // BUZZER_H