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

Improved indicator light library #87

Merged
merged 1 commit into from
Dec 29, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 34 additions & 18 deletions PlatformIO/lib/indicatorlight/IndicatorLight.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,50 +16,66 @@ void indicatorLedTask(void *param)
{
case OFF:
{
ledcWrite(0, 0);
ledcWrite(0, indicator_light->getInversePWM() ? indicator_light->limit : 0);
break;
}
case ON:
{
ledcWrite(0, 255);
ledcWrite(0, indicator_light->getInversePWM() ? indicator_light->limit - indicator_light->getMaxBrightness() : indicator_light->getMaxBrightness());
break;
}
case PULSING:
{
// do a nice pulsing effect
float angle = 0;
while (indicator_light->getState() == PULSING)
{
ledcWrite(0, 255 * (0.5 * cos(angle) + 0.5));
vTaskDelay(50 / portTICK_PERIOD_MS);
angle += 0.4 * M_PI;
int brightness = indicator_light->getMaxBrightness() * (0.5 * cos(indicator_light->getAngle()) + 0.5);
int pwm = indicator_light->getInversePWM() ? indicator_light->limit - brightness : brightness;
ledcWrite(0, pwm);
vTaskDelay(indicator_light->getStepDelayMS() / portTICK_PERIOD_MS);
}
break;
}
case BLINKING:
{
// do a nice pulsing effect
while (indicator_light->getState() == BLINKING)
{
int brightness = (indicator_light->getAngle() > indicator_light->getDutyAngle()) ? 0 : indicator_light->getMaxBrightness();
int pwm = indicator_light->getInversePWM() ? indicator_light->limit - brightness : brightness;
ledcWrite(0, pwm);
vTaskDelay(indicator_light->getStepDelayMS() / portTICK_PERIOD_MS);
}
break;
}
}
}
}
}

IndicatorLight::IndicatorLight(int gpio)
IndicatorLight::IndicatorLight(int gpio, bool _inversePWM, int _BITS) : BITS(_BITS), inversePWM(_inversePWM)
{
// use the build in LED as an indicator - we'll set it up as a pwm output so we can make it glow nicely
ledcSetup(0, 10000, 8);
//ledcAttachPin(2, 0);
ledcSetup(0, 10000, BITS);
ledcAttachPin(gpio, 0);
ledcWrite(0, 0);

// start off with the light off
ledcWrite(0, inversePWM? limit : 0);

m_state = OFF;
updateAnimation();
// set up the task for controlling the light
xTaskCreate(indicatorLedTask, "Indicator LED Task", 4096, this, 1, &m_taskHandle);
}

void IndicatorLight::setState(IndicatorState state)
{
m_state = state;
xTaskNotify(m_taskHandle, 1, eSetBits);
}

IndicatorState IndicatorLight::getState()
float IndicatorLight::getAngle()
{
return m_state;
}
float retval = angle;
angle += getStepAngle();
// keep angle from growing outside 2*M_PI
// as our steps are always integer divides of 2 * M_PI
// we can set the first step above 2 * M_PI to stepAngle
angle = (angle > 2 * M_PI) ? (angle - 2 * M_PI) : angle;
return retval;
}
80 changes: 72 additions & 8 deletions PlatformIO/lib/indicatorlight/IndicatorLight.h
Original file line number Diff line number Diff line change
@@ -1,23 +1,87 @@
#ifndef _indicator_light_h_
#define _indicator_light_h_
#pragma once
#include <math.h>

enum IndicatorState
{
OFF,
ON,
PULSING
PULSING,
BLINKING
};

class IndicatorLight
{
public:
const int BITS;
const int limit = (1 << BITS) - 1;
private:
IndicatorState m_state;
TaskHandle_t m_taskHandle;

int pulseMS = 2000;
const int stepDelayMS = 20; // 50 Hz update frequency
int steps;
float stepAngle;
bool inversePWM;
// current step angle
float angle = 0;
int maxBrightness = limit;


float duty = M_PI; // how long is the "on" part of the pulseMS length blinking cycle in as angle (M_PI = 50% duty).

void updateAnimation()
{

steps = pulseMS / stepDelayMS;
stepAngle = (2 * M_PI) / steps;

// adjust to next integer step according to new step width, avoids
// wrong animations
angle = ceilf(angle / stepAngle) * stepAngle;
}

public:
IndicatorLight(int gpio);
void setState(IndicatorState state);
IndicatorState getState();
};
/**
* @brief Construct a new Indicator Light object
*
* @param gpio which GPIO the led is connected to
* @param inversePWM set to true if LED is active at LOW output level
* @param _BITS number of bits for pwm controller, up to 16 is permitted, 12 is default
*/
IndicatorLight(int gpio, bool inversePWM = false, int _BITS = 12);

void setState(IndicatorState state)
{
m_state = state;
xTaskNotify(m_taskHandle, 1, eSetBits);
}


IndicatorState getState()
{
return m_state;
}

void setPulseTime(int pulseMS)
{
this->pulseMS = pulseMS;
updateAnimation();
}

float getStepAngle() { return stepAngle; }
int getStepDelayMS() { return stepDelayMS; };
bool getInversePWM() { return inversePWM; }

#endif
/**
* @brief Get the current animation angle step (1 animation cycle = 2 * PI), each call
* increments returned angle by stepAngle until a value > 2 * PI is reached, then it will start again.
*
* @return float
*/
float getAngle();
int getMaxBrightness() { return maxBrightness; }
void setMaxBrightness(int mb) { maxBrightness=mb;}
void setDutyPercent(float percentOn = 50) { duty = percentOn * (2*M_PI) /100.0; }
int getDutyAngle() { return duty; }
};
54 changes: 36 additions & 18 deletions PlatformIO/src/devices/AudioKit.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ class AudioKit : public Device
public:
AudioKit();
void init();
void updateColors(int colors);
void updateColors(StateColors colors);

void setReadMode();
void setWriteMode(int sampleRate, int bitDepth, int numChannels);
Expand All @@ -122,13 +122,13 @@ class AudioKit : public Device
void muteOutput(bool mute);

// ESP-Audio-Kit has speaker and headphone as outputs
// TODO
void ampOutput(int output);
void setVolume(uint16_t volume);

bool isHotwordDetected();

int numAmpOutConfigurations() { return 3; };
void updateBrightness(int brightness);

private:
void InitI2SSpeakerOrMic(int mode);
Expand All @@ -144,7 +144,7 @@ class AudioKit : public Device
bool is_mono_stream_stereo_out = false;
uint16_t key_listen;

IndicatorLight *indicator_light = new IndicatorLight(LED_STREAM);
IndicatorLight *indicator_light = new IndicatorLight(LED_STREAM, true);
};

AudioKit::AudioKit(){};
Expand Down Expand Up @@ -185,9 +185,7 @@ void AudioKit::init()
key_listen = is_es? ES_KEY_LISTEN: KEY_LISTEN;

// LEDs
pinMode(LED_WIFI, OUTPUT); // active low

digitalWrite(LED_STREAM, HIGH);
pinMode(LED_WIFI, OUTPUT); // active low
digitalWrite(LED_WIFI, HIGH);

// Enable amplifier
Expand All @@ -208,31 +206,46 @@ void AudioKit::init()
*
* @param colors used to indicate state to display, see device.h (enum LedColorState) for values
*/
void AudioKit::updateColors(int colors)
void AudioKit::updateColors(StateColors colors)
{
// turn off LEDs
/// digitalWrite(LED_STREAM, HIGH);
indicator_light->setState(PULSING);

digitalWrite(LED_WIFI, HIGH);

switch (colors)
{
case COLORS_HOTWORD:
/// digitalWrite(LED_STREAM, LOW);
// very slow pulsing of LED
indicator_light->setPulseTime(4000);
indicator_light->setState(PULSING);
break;
case COLORS_WIFI_CONNECTED:
// LED_WIFI is turned off already
// quick flashing of LED
indicator_light->setDutyPercent(50);
indicator_light->setPulseTime(1000);
indicator_light->setState(BLINKING);
break;
case COLORS_WIFI_DISCONNECTED:
digitalWrite(LED_WIFI, LOW);
break;
// slower flashing of LED
indicator_light->setDutyPercent(25);
indicator_light->setPulseTime(2000);
indicator_light->setState(BLINKING);
break;
case COLORS_IDLE:
// all LEDs are turned off already
// all lights are off
indicator_light->setState(OFF);
break;
case COLORS_ERROR:
// very quick blinking of LED
indicator_light->setDutyPercent(25);
indicator_light->setPulseTime(500);
indicator_light->setState(BLINKING);
break;
case COLORS_OTA:
// very quick pulsing of LED
indicator_light->setPulseTime(500);
indicator_light->setState(PULSING);
break;
case COLORS_TTS:
indicator_light->setState(ON);
break;

}
};

Expand Down Expand Up @@ -476,3 +489,8 @@ void AudioKit::ampOutput(int ampOut)
ac.SetVolumeHeadphone(mute[1]? 0 : vol);
}
}

void AudioKit::updateBrightness(int brightness)
{
indicator_light->setMaxBrightness((brightness*indicator_light->limit)/100);
}
37 changes: 34 additions & 3 deletions PlatformIO/src/devices/Inmp441Max98357a.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,10 @@ class Inmp441Max98357a : public Device
bool readAudio(uint8_t *data, size_t size);
void setWriteMode(int sampleRate, int bitDepth, int numChannels);
void writeAudio(uint8_t *data, size_t size, size_t *bytes_written);
IndicatorLight *indicator_light = new IndicatorLight(LED_FLASH);
IndicatorLight* indicator_light = new IndicatorLight(LED_FLASH);

int numAmpOutConfigurations() { return 1; };
void updateBrightness(int brightness);

private:
char* i2s_read_buff = (char*) calloc(I2S_READ_LEN, sizeof(char));
Expand Down Expand Up @@ -126,19 +127,44 @@ void Inmp441Max98357a::init() {

void Inmp441Max98357a::updateColors(int colors)
{
indicator_light->setState(OFF);
switch (colors)
{
case COLORS_HOTWORD:
// very slow pulsing of LED
indicator_light->setPulseTime(4000);
indicator_light->setState(PULSING);
break;
case COLORS_WIFI_CONNECTED:
// quick flashing of LED
indicator_light->setDutyPercent(50);
indicator_light->setPulseTime(1000);
indicator_light->setState(BLINKING);
break;
case COLORS_WIFI_DISCONNECTED:
break;
// slower flashing of LED
indicator_light->setDutyPercent(25);
indicator_light->setPulseTime(2000);
indicator_light->setState(BLINKING);
break;
case COLORS_IDLE:
// all lights are off
indicator_light->setState(OFF);
break;
case COLORS_ERROR:
// very quick blinking of LED
indicator_light->setDutyPercent(25);
indicator_light->setPulseTime(500);
indicator_light->setState(BLINKING);
break;
case COLORS_OTA:
// very quick pulsing of LED
indicator_light->setPulseTime(500);
indicator_light->setState(PULSING);
break;
case COLORS_TTS:
indicator_light->setState(ON);
break;

}
};

Expand Down Expand Up @@ -169,3 +195,8 @@ bool Inmp441Max98357a::readAudio(uint8_t *data, size_t size) {
}
return true;
}

void Inmp441Max98357a::updateBrightness(int brightness)
{
indicator_light->setMaxBrightness((brightness*indicator_light->limit)/100);
}