Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue5194 external notification module refactor #5384

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
2 changes: 1 addition & 1 deletion protobufs
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please revert the protobuf change, this will generate merge conficts

249 changes: 128 additions & 121 deletions src/modules/ExternalNotificationModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,16 @@ extern unPhone unphone;
#endif

#if defined(HAS_NCP5623) || defined(RGBLED_RED) || defined(HAS_NEOPIXEL) || defined(UNPHONE)
#define HAS_LED
#endif

#ifdef HAS_LED
uint8_t red = 0;
uint8_t green = 0;
uint8_t blue = 0;
uint8_t colorState = 1;
uint8_t brightnessIndex = 0;
uint8_t brightnessValues[] = {0, 10, 20, 30, 50, 90, 160, 170}; // blue gets multiplied by 1.5
uint8_t alphaIndex = 0;
uint8_t alphaValues[] = {0, 15, 30, 45, 75, 135, 240, 255};
bool ascending = true;
#endif

Expand All @@ -68,6 +72,34 @@ bool ascending = true;

#define ASCII_BELL 0x07

<<<<<<< HEAD
struct ExternalNotificationModule::RGB {
constexpr RGB(uint8_t red, uint8_t green, uint8_t blue) : red{red}, green{green}, blue{blue} {}

#define SCALE_ALPHA(COLOR, ALPHA) (uint8_t)((((uint16_t)COLOR) * ALPHA) / (uint16_t)255)
constexpr RGB(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha)
: red{SCALE_ALPHA(red, alpha)}, green{SCALE_ALPHA(green, alpha)}, blue{SCALE_ALPHA(blue, alpha)}
{
}
#undef SCALE_ALPHA
=======
struct ExternalNotificationModule::Color {
constexpr Color(uint8_t red, uint8_t green,uint8_t blue)
: red{red}, green{green}, blue{blue}
{}

#define SCALE_ALPHA(COLOR, ALPHA) (uint8_t)((((uint16_t)COLOR) * ALPHA) / (uint16_t)255)
constexpr Color(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha)
: red{SCALE_ALPHA(red, alpha)}, green{SCALE_ALPHA(green, alpha)}, blue{SCALE_ALPHA(blue, alpha)}
{}
#undef SCALE_ALPHA
>>>>>>> 79093de8 (Fix compilation error due to `rgb` name conflict.)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You somehow checked in a conflicted file. there are merge marks that will bomb during compilation.

uint8_t red = 0;
uint8_t green = 0;
uint8_t blue = 0;
};

meshtastic_RTTTLConfig rtttlConfig;

ExternalNotificationModule *externalNotificationModule;
Expand All @@ -82,120 +114,85 @@ int32_t ExternalNotificationModule::runOnce()
{
if (!moduleConfig.external_notification.enabled) {
return INT32_MAX; // we don't need this thread here...
} else {
}

bool isPlaying = rtttl::isPlaying();
bool isPlaying = rtttl::isPlaying();
#ifdef HAS_I2S
isPlaying = rtttl::isPlaying() || audioThread->isPlaying();
#endif
if ((nagCycleCutoff < millis()) && !isPlaying) {
// let the song finish if we reach timeout
nagCycleCutoff = UINT32_MAX;
LOG_INFO("Turning off external notification: ");
for (int i = 0; i < 3; i++) {
setExternalState(i, false);
externalTurnedOn[i] = 0;
LOG_INFO("%d ", i);
}
LOG_INFO("");
isPlaying = rtttl::isPlaying() || audioThread->isPlaying();
#endif
if ((nagCycleCutoff < millis()) && !isPlaying) {
// let the song finish if we reach timeout
nagCycleCutoff = UINT32_MAX;
LOG_INFO("Turning off external notification: ");
for (int i = 0; i < 3; i++) {
setExternalState(i, false);
externalTurnedOn[i] = 0;
LOG_INFO("%d ", i);
}
LOG_INFO("");
#ifdef HAS_I2S
// GPIO0 is used as mclk for I2S audio and set to OUTPUT by the sound library
// T-Deck uses GPIO0 as trackball button, so restore the mode
// GPIO0 is used as mclk for I2S audio and set to OUTPUT by the sound library
// T-Deck uses GPIO0 as trackball button, so restore the mode
#if defined(T_DECK) || (defined(BUTTON_PIN) && BUTTON_PIN == 0)
pinMode(0, INPUT);
pinMode(0, INPUT);
#endif
#endif
isNagging = false;
return INT32_MAX; // save cycles till we're needed again
}
isNagging = false;
return INT32_MAX; // save cycles till we're needed again
}

// If the output is turned on, turn it back off after the given period of time.
if (isNagging) {
if (externalTurnedOn[0] + (moduleConfig.external_notification.output_ms ? moduleConfig.external_notification.output_ms
: EXT_NOTIFICATION_MODULE_OUTPUT_MS) <
millis()) {
setExternalState(0, !getExternal(0));
}
if (externalTurnedOn[1] + (moduleConfig.external_notification.output_ms ? moduleConfig.external_notification.output_ms
: EXT_NOTIFICATION_MODULE_OUTPUT_MS) <
millis()) {
setExternalState(1, !getExternal(1));
}
if (externalTurnedOn[2] + (moduleConfig.external_notification.output_ms ? moduleConfig.external_notification.output_ms
: EXT_NOTIFICATION_MODULE_OUTPUT_MS) <
millis()) {
LOG_DEBUG("EXTERNAL 2 %d compared to %d", externalTurnedOn[2]+moduleConfig.external_notification.output_ms, millis());
setExternalState(2, !getExternal(2));
}
#if defined(HAS_NCP5623) || defined(RGBLED_RED) || defined(HAS_NEOPIXEL) || defined(UNPHONE)
red = (colorState & 4) ? brightnessValues[brightnessIndex] : 0; // Red enabled on colorState = 4,5,6,7
green = (colorState & 2) ? brightnessValues[brightnessIndex] : 0; // Green enabled on colorState = 2,3,6,7
blue = (colorState & 1) ? (brightnessValues[brightnessIndex] * 1.5) : 0; // Blue enabled on colorState = 1,3,5,7
#ifdef HAS_NCP5623
if (rgb_found.type == ScanI2C::NCP5623) {
rgb.setColor(red, green, blue);
}
#endif
#ifdef RGBLED_CA
analogWrite(RGBLED_RED, 255 - red); // CA type needs reverse logic
analogWrite(RGBLED_GREEN, 255 - green);
analogWrite(RGBLED_BLUE, 255 - blue);
#elif defined(RGBLED_RED)
analogWrite(RGBLED_RED, red);
analogWrite(RGBLED_GREEN, green);
analogWrite(RGBLED_BLUE, blue);
#endif
#ifdef HAS_NEOPIXEL
pixels.fill(pixels.Color(red, green, blue), 0, NEOPIXEL_COUNT);
pixels.show();
#endif
#ifdef UNPHONE
unphone.rgb(red, green, blue);
#endif
if (ascending) { // fade in
brightnessIndex++;
if (brightnessIndex == (sizeof(brightnessValues) - 1)) {
ascending = false;
}
} else {
brightnessIndex--; // fade out
}
if (brightnessIndex == 0) {
ascending = true;
colorState++; // next color
if (colorState > 7) {
colorState = 1;
}
}
// If the output is turned on, turn it back off after the given period of time.
if (isNagging) {
if (externalTurnedOn[0] + (moduleConfig.external_notification.output_ms ? moduleConfig.external_notification.output_ms
: EXT_NOTIFICATION_MODULE_OUTPUT_MS) <
millis()) {
setExternalState(0, !getExternal(0));
}
if (externalTurnedOn[1] + (moduleConfig.external_notification.output_ms ? moduleConfig.external_notification.output_ms
: EXT_NOTIFICATION_MODULE_OUTPUT_MS) <
millis()) {
setExternalState(1, !getExternal(1));
}
if (externalTurnedOn[2] + (moduleConfig.external_notification.output_ms ? moduleConfig.external_notification.output_ms
: EXT_NOTIFICATION_MODULE_OUTPUT_MS) <
millis()) {
LOG_DEBUG("EXTERNAL 2 %d compared to %d", externalTurnedOn[2] + moduleConfig.external_notification.output_ms,
millis());
setExternalState(2, !getExternal(2));
}
#ifdef HAS_LED
red = (colorState & 4) ? 170 : 0; // Red enabled on colorState = 4,5,6,7
green = (colorState & 2) ? 170 : 0; // Green enabled on colorState = 2,3,6,7
blue = (colorState & 1) ? 255 : 0; // Blue enabled on colorState = 1,3,5,7
setLEDs({red, green, blue, alphaValues[alphaIndex]});
#endif

#ifdef T_WATCH_S3
drv.go();
drv.go();
#endif
}
}

// Play RTTTL over i2s audio interface if enabled as buzzer
// Play RTTTL over i2s audio interface if enabled as buzzer
#ifdef HAS_I2S
if (moduleConfig.external_notification.use_i2s_as_buzzer) {
if (audioThread->isPlaying()) {
// Continue playing
} else if (isNagging && (nagCycleCutoff >= millis())) {
audioThread->beginRttl(rtttlConfig.ringtone, strlen_P(rtttlConfig.ringtone));
}
if (moduleConfig.external_notification.use_i2s_as_buzzer) {
if (audioThread->isPlaying()) {
// Continue playing
} else if (isNagging && (nagCycleCutoff >= millis())) {
audioThread->beginRttl(rtttlConfig.ringtone, strlen_P(rtttlConfig.ringtone));
}
}
#endif
// now let the PWM buzzer play
if (moduleConfig.external_notification.use_pwm && config.device.buzzer_gpio) {
if (rtttl::isPlaying()) {
rtttl::play();
} else if (isNagging && (nagCycleCutoff >= millis())) {
// start the song again if we have time left
rtttl::begin(config.device.buzzer_gpio, rtttlConfig.ringtone);
}
// now let the PWM buzzer play
if (moduleConfig.external_notification.use_pwm && config.device.buzzer_gpio) {
if (rtttl::isPlaying()) {
rtttl::play();
} else if (isNagging && (nagCycleCutoff >= millis())) {
// start the song again if we have time left
rtttl::begin(config.device.buzzer_gpio, rtttlConfig.ringtone);
}

return EXT_NOTIFICATION_DEFAULT_THREAD_MS;
}

return EXT_NOTIFICATION_DEFAULT_THREAD_MS;
}

bool ExternalNotificationModule::wantPacket(const meshtastic_MeshPacket *p)
Expand Down Expand Up @@ -232,35 +229,15 @@ void ExternalNotificationModule::setExternalState(uint8_t index, bool on)
break;
}

#if defined(HAS_NCP5623) || defined(RGBLED_RED) || defined(HAS_NEOPIXEL) || defined(UNPHONE)
#ifdef HAS_LED
if (!on) {
red = 0;
green = 0;
blue = 0;
}
setLEDs({red, green, blue, 255});
#endif

#ifdef HAS_NCP5623
if (rgb_found.type == ScanI2C::NCP5623) {
rgb.setColor(red, green, blue);
}
#endif
#ifdef RGBLED_CA
analogWrite(RGBLED_RED, 255 - red); // CA type needs reverse logic
analogWrite(RGBLED_GREEN, 255 - green);
analogWrite(RGBLED_BLUE, 255 - blue);
#elif defined(RGBLED_RED)
analogWrite(RGBLED_RED, red);
analogWrite(RGBLED_GREEN, green);
analogWrite(RGBLED_BLUE, blue);
#endif
#ifdef HAS_NEOPIXEL
pixels.fill(pixels.Color(red, green, blue), 0, NEOPIXEL_COUNT);
pixels.show();
#endif
#ifdef UNPHONE
unphone.rgb(red, green, blue);
#endif
#ifdef T_WATCH_S3
if (on) {
drv.go();
Expand Down Expand Up @@ -290,6 +267,36 @@ void ExternalNotificationModule::stopNow()
#endif
}

void ExternalNotificationModule::setLEDs(const Color& color)
{

#ifdef HAS_LED
// LOG_DEBUG("setLEDs red=%d, green=%d, blue=%d", color.red, color.green, color.blue);

#ifdef HAS_NCP5623
if (rgb_found.type == ScanI2C::NCP5623) {
rgb.setColor(color.red, color.green, color.blue);
}
#endif
#ifdef RGBLED_CA
analogWrite(RGBLED_RED, 255 - color.red); // CA type needs reverse logic
analogWrite(RGBLED_GREEN, 255 - color.green);
analogWrite(RGBLED_BLUE, 255 - color.blue);
#elif defined(RGBLED_RED)
analogWrite(RGBLED_RED, color.red);
analogWrite(RGBLED_GREEN, color.green);
analogWrite(RGBLED_BLUE, color.blue);
#endif
#ifdef HAS_NEOPIXEL
pixels.fill(pixels.Color(color.red, color.green, color.blue), 0, NEOPIXEL_COUNT);
pixels.show();
#endif
#ifdef UNPHONE
unphone.rgb(color.red, color.green, color.blue);
#endif
#endif
}

ExternalNotificationModule::ExternalNotificationModule()
: SinglePortModule("ExternalNotificationModule", meshtastic_PortNum_TEXT_MESSAGE_APP),
concurrency::OSThread("ExternalNotification")
Expand Down
7 changes: 5 additions & 2 deletions src/modules/ExternalNotificationModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,6 @@ class ExternalNotificationModule : public SinglePortModule, private concurrency:
ExternalNotificationModule();

uint32_t nagCycleCutoff = 1;

void setExternalState(uint8_t index = 0, bool on = false);
bool getExternal(uint8_t index = 0);

void setMute(bool mute) { isMuted = mute; }
Expand All @@ -46,6 +44,11 @@ class ExternalNotificationModule : public SinglePortModule, private concurrency:
void handleSetRingtone(const char *from_msg);

protected:
void setExternalState(uint8_t index = 0, bool on = false);

struct Color;
void setLEDs(const Color& color);

/** Called to handle a particular incoming message
@return ProcessMessage::STOP if you've guaranteed you've handled this message and no other handlers should be considered for
it
Expand Down
Loading