/* ENCODER MODULE Copyright (C) 2018-2019 by Xose PĂ©rez */ #if ENCODER_SUPPORT && (LIGHT_PROVIDER != LIGHT_PROVIDER_NONE) #include "libs/Encoder.h" #include struct encoder_t { Encoder * encoder; unsigned char button_pin; unsigned char button_logic; unsigned char button_mode; unsigned char mode; unsigned char channel1; // default unsigned char channel2; // only if button defined and pressed }; std::vector _encoders; unsigned long _encoder_min_delta = 1; void _encoderConfigure() { _encoder_min_delta = getSetting("encMinDelta", ENCODER_MINIMUM_DELTA).toInt(); if (!_encoder_min_delta) _encoder_min_delta = 1; // no need to reload objects right now if (_encoders.size()) return; // Clean previous encoders and re-add them for (auto& encoder : _encoders) { delete encoder.encoder; } _encoders.clear(); // TODO: encEnable // TODO: implement reloading without re-allocating objects #if (ENCODER1_PIN1 != GPIO_NONE) && (ENCODER1_PIN2 != GPIO_NONE) { _encoders.push_back({ new Encoder(ENCODER1_PIN1, ENCODER1_PIN2), ENCODER1_BUTTON_PIN, ENCODER1_BUTTON_LOGIC, ENCODER1_BUTTON_MODE, ENCODER1_MODE, ENCODER1_CHANNEL1, ENCODER1_CHANNEL2 }); } #endif #if (ENCODER2_PIN1 != GPIO_NONE) && (ENCODER2_PIN2 != GPIO_NONE) { _encoders.push_back({ new Encoder(ENCODER2_PIN1, ENCODER2_PIN2), ENCODER2_BUTTON_PIN, ENCODER2_BUTTON_LOGIC, ENCODER2_BUTTON_MODE, ENCODER2_MODE, ENCODER2_CHANNEL1, ENCODER2_CHANNEL2 }); } #endif #if (ENCODER3_PIN1 != GPIO_NONE) && (ENCODER3_PIN2 != GPIO_NONE) { _encoders.push_back({ new Encoder(ENCODER3_PIN1, ENCODER3_PIN2), ENCODER3_BUTTON_PIN, ENCODER3_BUTTON_LOGIC, ENCODER3_BUTTON_MODE, ENCODER3_MODE, ENCODER3_CHANNEL1, ENCODER3_CHANNEL2 }); } #endif #if (ENCODER4_PIN1 != GPIO_NONE) && (ENCODER4_PIN2 != GPIO_NONE) { _encoders.push_back({ new Encoder(ENCODER4_PIN1, ENCODER4_PIN2), ENCODER4_BUTTON_PIN, ENCODER4_BUTTON_LOGIC, ENCODER4_BUTTON_MODE, ENCODER4_MODE, ENCODER4_CHANNEL1, ENCODER4_CHANNEL2 }); } #endif #if (ENCODER5_PIN1 != GPIO_NONE) && (ENCODER5_PIN2 != GPIO_NONE) { _encoders.push_back({ new Encoder(ENCODER5_PIN1, ENCODER5_PIN2), ENCODER5_BUTTON_PIN, ENCODER5_BUTTON_LOGIC, ENCODER5_BUTTON_MODE, ENCODER5_MODE, ENCODER5_CHANNEL1, ENCODER5_CHANNEL2 }); } #endif // TODO: manage buttons through debounceevent? for (auto& encoder : _encoders) { if (GPIO_NONE != encoder.button_pin) { pinMode(encoder.button_pin, encoder.button_mode); } } } void _encoderLoop() { // for each encoder, read delta (read()) and map button action for (auto& encoder : _encoders) { const auto delta = encoder.encoder->read(); encoder.encoder->write(0); if ((0 == delta) || (_encoder_min_delta > abs(delta))) continue; if (encoder.button_pin == GPIO_NONE) { // if there is no button, the encoder drives CHANNEL1 lightChannelStep(encoder.channel1, delta); } else { // otherwise, use button based on encoder mode bool pressed = (digitalRead(encoder.button_pin) != encoder.button_logic); if (ENCODER_MODE_CHANNEL == encoder.mode) { // the button controls what channel we are changing lightChannelStep(pressed ? encoder.channel2 : encoder.channel1, delta); } if (ENCODER_MODE_RATIO == encoder.mode) { // the button controls if we are changing the channel ratio or the overall brightness if (pressed) { lightChannelStep(encoder.channel1, delta); lightChannelStep(encoder.channel2, -delta); } else { lightBrightnessStep(delta); } } } lightUpdate(true, true); } } // ----------------------------------------------------------------------------- void encoderSetup() { // Configure encoders _encoderConfigure(); // Main callbacks espurnaRegisterLoop(_encoderLoop); espurnaRegisterReload(_encoderConfigure); DEBUG_MSG_P(PSTR("[ENCODER] Number of encoders: %u\n"), _encoders.size()); } #endif // ENCODER_SUPPORT && (LIGHT_PROVIDER != LIGHT_PROVIDER_NONE)