add ULP LP example / update Matter example
This commit is contained in:
@@ -32,6 +32,7 @@ jobs:
|
||||
- "examples/espidf-storage-sdcard"
|
||||
- "examples/espidf-ulp"
|
||||
- "examples/espidf-ulp-riscv"
|
||||
- "espidf-ulp-lp"
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
@@ -1,3 +1,68 @@
|
||||
## Arduino/IDF Matter Light example
|
||||
|
||||
The needed Matter component is added via the IDF component manager -> `idf_component.yml`.
|
||||
| Supported Targets | ESP32-S3 | ESP32-C3 | ESP32-C6 |
|
||||
| ----------------- | -------- | -------- | -------- |
|
||||
|
||||
|
||||
# Managed Component Light
|
||||
|
||||
This example is configured by default to work with the ESP32-S3, which has the RGB LED GPIO set as pin 48 and the BOOT button on GPIO 0.
|
||||
|
||||
This example creates a Color Temperature Light device using the esp_matter component downloaded from the [Espressif Component Registry](https://components.espressif.com/) instead of an extra component locally, so the example can work without setting up the esp-matter environment.
|
||||
|
||||
See the [docs](https://docs.espressif.com/projects/esp-matter/en/latest/esp32/developing.html) for more information about building and flashing the firmware.
|
||||
|
||||
The code is based on the Arduino API and uses Arduino as an IDF Component.
|
||||
|
||||
## How to use it
|
||||
|
||||
Once the device runs for the first time, it must be commissioned to the Matter Fabric of the available Matter Environment.
|
||||
Possible Matter Environments are:
|
||||
- Amazon Alexa
|
||||
- Google Home Assistant (*)
|
||||
- Apple Home
|
||||
- Open Source Home Assistant
|
||||
|
||||
(*) Google Home Assistant requires the user to set up a Matter Light using the [Google Home Developer Console](https://developers.home.google.com/codelabs/matter-device#2). It is necessary to create a Matter Light device with VID = 0xFFF1 and PID = 0x8000. Otherwise, the Light won't show up in the GHA APP. This action is necessary because the Firmware uses Testing credentials and Google requires the user to create the testing device before using it.
|
||||
|
||||
There is no QR Code to be used when the Smartphone APP wants to add the Matter Device.
|
||||
Please enter the code manually: `34970112332`
|
||||
|
||||
The devboard has a built-in LED that will be used as the Matter Light.
|
||||
The default setting of the code uses pin 48 for the ESP32-S3.
|
||||
Please change it in `main/matter_accessory_driver.h` or in the `sdkconfig.defaults.<SOC>` file.
|
||||
|
||||
## LED Status and Factory Mode
|
||||
|
||||
The WS2812b built-in LED will turn purple as soon as the device is flashed and runs for the first time.
|
||||
The purple color indicates that the Matter Accessory has not been commissioned yet.
|
||||
After using a Matter provider Smartphone APP to add a Matter device to your Home Application, it may turn orange to indicate that it has no WiFi connection.
|
||||
|
||||
Once it connects to the WiFi network, the LED will turn white to indicate that Matter is working and the device is connected to the Matter Environment.
|
||||
Please note that Matter over WiFi using an ESP32 device will connect to a 2.4GHz WiFi SSID, therefore the Commissioner APP Smartphone shall be connected to this SSID.
|
||||
|
||||
The Matter and WiFi configuration will be stored in NVS to ensure that it will connect to the Matter Fabric and WiFi Network again once it is reset.
|
||||
|
||||
The Matter Smartphone APP will control the light state (ON/OFF), temperature (Warm/Cold White), and brightness.
|
||||
|
||||
## On Board Light toggle button
|
||||
|
||||
The built-in BOOT button will toggle On/Off and replicate the new state to the Matter Environment, making it visible in the Matter Smartphone APP as well.
|
||||
|
||||
## Returning to the Factory State
|
||||
|
||||
Holding the BOOT button pressed for more than 10 seconds and then releasing it will erase all Matter and WiFi configuration, forcing it to reset to factory state. After that, the device needs to be commissioned again. Previous setups done in the Smartphone APP won't work again; therefore, the virtual device shall be removed from the APP.
|
||||
|
||||
## Building the Application using WiFi and Matter
|
||||
|
||||
Use ESP-IDF 5.1.4 from https://github.com/espressif/esp-idf/tree/release/v5.1
|
||||
This example has been tested with Arduino Core 3.0.4
|
||||
|
||||
There is a configuration file for these SoC: esp32s3, esp32c3, esp32c6.
|
||||
Those are the tested devices that have a WS2812 RGB LED and can run BLE, WiFi and Matter.
|
||||
|
||||
In case it is necessary to change the Button Pin or the REG LED Pin, please use the `menuconfig` and change the Menu Option `Light Matter Accessory`
|
||||
|
||||
## Using OpenThread with Matter
|
||||
|
||||
This is possible with the ESP32-C6.
|
||||
It is neessasy to have a Thread Border Routed in the Matter Environment. Check you matter hardware provider.
|
||||
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
menu "Light Matter Accessory"
|
||||
menu "On Board Light ON/OFF Button"
|
||||
config BUTTON_PIN
|
||||
int
|
||||
prompt "Button 1 GPIO"
|
||||
default ENV_GPIO_BOOT_BUTTON
|
||||
range -1 ENV_GPIO_IN_RANGE_MAX
|
||||
help
|
||||
The GPIO pin for button that will be used to turn on/off the Matter Light. It shall be connected to a push button. It can use the BOOT button of the development board.
|
||||
endmenu
|
||||
|
||||
|
||||
menu "LEDs"
|
||||
config WS2812_PIN
|
||||
int
|
||||
prompt "WS2812 RGB LED GPIO"
|
||||
default ENV_GPIO_RGB_LED
|
||||
range -1 ENV_GPIO_OUT_RANGE_MAX
|
||||
help
|
||||
The GPIO pin for the Matter Light that will be driven by RMT. It shall be connected to one single WS2812 RGB LED.
|
||||
endmenu
|
||||
|
||||
# TARGET CONFIGURATION
|
||||
if IDF_TARGET_ESP32C3
|
||||
config ENV_GPIO_RANGE_MIN
|
||||
int
|
||||
default 0
|
||||
|
||||
config ENV_GPIO_RANGE_MAX
|
||||
int
|
||||
default 19
|
||||
# GPIOs 20/21 are always used by UART in examples
|
||||
|
||||
config ENV_GPIO_IN_RANGE_MAX
|
||||
int
|
||||
default ENV_GPIO_RANGE_MAX
|
||||
|
||||
config ENV_GPIO_OUT_RANGE_MAX
|
||||
int
|
||||
default ENV_GPIO_RANGE_MAX
|
||||
|
||||
config ENV_GPIO_BOOT_BUTTON
|
||||
int
|
||||
default 9
|
||||
|
||||
config ENV_GPIO_RGB_LED
|
||||
int
|
||||
default 8
|
||||
endif
|
||||
if IDF_TARGET_ESP32C6
|
||||
config ENV_GPIO_RANGE_MIN
|
||||
int
|
||||
default 0
|
||||
|
||||
config ENV_GPIO_RANGE_MAX
|
||||
int
|
||||
default 30
|
||||
# GPIOs 16/17 are always used by UART in examples
|
||||
|
||||
config ENV_GPIO_IN_RANGE_MAX
|
||||
int
|
||||
default ENV_GPIO_RANGE_MAX
|
||||
|
||||
config ENV_GPIO_OUT_RANGE_MAX
|
||||
int
|
||||
default ENV_GPIO_RANGE_MAX
|
||||
|
||||
config ENV_GPIO_BOOT_BUTTON
|
||||
int
|
||||
default 9
|
||||
|
||||
config ENV_GPIO_RGB_LED
|
||||
int
|
||||
default 8
|
||||
endif
|
||||
if IDF_TARGET_ESP32S3
|
||||
config ENV_GPIO_RANGE_MIN
|
||||
int
|
||||
default 0
|
||||
|
||||
config ENV_GPIO_RANGE_MAX
|
||||
int
|
||||
default 48
|
||||
|
||||
config ENV_GPIO_IN_RANGE_MAX
|
||||
int
|
||||
default ENV_GPIO_RANGE_MAX
|
||||
|
||||
config ENV_GPIO_OUT_RANGE_MAX
|
||||
int
|
||||
default ENV_GPIO_RANGE_MAX
|
||||
|
||||
config ENV_GPIO_BOOT_BUTTON
|
||||
int
|
||||
default 0
|
||||
|
||||
config ENV_GPIO_RGB_LED
|
||||
int
|
||||
default 48
|
||||
endif
|
||||
|
||||
endmenu
|
||||
@@ -1,251 +1,247 @@
|
||||
/*
|
||||
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||
|
||||
Unless required by applicable law or agreed to in writing, this
|
||||
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
||||
This will implement the onboard WS2812b LED as a LED indicator
|
||||
It can be used to indicate some state or status of the device
|
||||
The LED can be controlled using RGB, HSV or color temperature, brightness
|
||||
|
||||
In this example, the LED Indicator class is used as the Matter light accessory
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
#include "builtinLED.h"
|
||||
|
||||
typedef struct {
|
||||
uint16_t hue;
|
||||
uint8_t saturation;
|
||||
} HS_color_t;
|
||||
|
||||
static const HS_color_t temperatureTable[] = {
|
||||
{4, 100}, {8, 100}, {11, 100}, {14, 100}, {16, 100}, {18, 100}, {20, 100}, {22, 100}, {24, 100}, {25, 100},
|
||||
{27, 100}, {28, 100}, {30, 100}, {31, 100}, {31, 95}, {30, 89}, {30, 85}, {29, 80}, {29, 76}, {29, 73},
|
||||
{29, 69}, {28, 66}, {28, 63}, {28, 60}, {28, 57}, {28, 54}, {28, 52}, {27, 49}, {27, 47}, {27, 45},
|
||||
{27, 43}, {27, 41}, {27, 39}, {27, 37}, {27, 35}, {27, 33}, {27, 31}, {27, 30}, {27, 28}, {27, 26},
|
||||
{27, 25}, {27, 23}, {27, 22}, {27, 21}, {27, 19}, {27, 18}, {27, 17}, {27, 15}, {28, 14}, {28, 13},
|
||||
{28, 12}, {29, 10}, {29, 9}, {30, 8}, {31, 7}, {32, 6}, {34, 5}, {36, 4}, {41, 3}, {49, 2},
|
||||
{0, 0}, {294, 2}, {265, 3}, {251, 4}, {242, 5}, {237, 6}, {233, 7}, {231, 8}, {229, 9}, {228, 10},
|
||||
{227, 11}, {226, 11}, {226, 12}, {225, 13}, {225, 13}, {224, 14}, {224, 14}, {224, 15}, {224, 15}, {223, 16},
|
||||
{223, 16}, {223, 17}, {223, 17}, {223, 17}, {222, 18}, {222, 18}, {222, 19}, {222, 19}, {222, 19}, {222, 19},
|
||||
{222, 20}, {222, 20}, {222, 20}, {222, 21}, {222, 21}
|
||||
};
|
||||
|
||||
/* step brightness table: gamma = 2.3 */
|
||||
static const uint8_t gamma_table[MAX_PROGRESS] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2,
|
||||
2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5,
|
||||
5, 5, 6, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10,
|
||||
10, 10, 11, 11, 12, 12, 13, 13, 13, 14, 14, 15, 15, 16, 16, 17,
|
||||
17, 18, 18, 19, 19, 20, 20, 21, 22, 22, 23, 23, 24, 25, 25, 26,
|
||||
26, 27, 28, 28, 29, 30, 30, 31, 32, 33, 33, 34, 35, 36, 36, 37,
|
||||
38, 39, 40, 40, 41, 42, 43, 44, 45, 45, 46, 47, 48, 49, 50, 51,
|
||||
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67,
|
||||
68, 69, 70, 71, 72, 74, 75, 76, 77, 78, 79, 81, 82, 83, 84, 86,
|
||||
87, 88, 89, 91, 92, 93, 95, 96, 97, 99, 100, 101, 103, 104, 105, 107,
|
||||
108, 110, 111, 112, 114, 115, 117, 118, 120, 121, 123, 124, 126, 128, 129, 131,
|
||||
132, 134, 135, 137, 139, 140, 142, 144, 145, 147, 149, 150, 152, 154, 156, 157,
|
||||
159, 161, 163, 164, 166, 168, 170, 172, 174, 175, 177, 179, 181, 183, 185, 187,
|
||||
189, 191, 193, 195, 197, 199, 201, 203, 205, 207, 209, 211, 213, 215, 217, 219,
|
||||
221, 223, 226, 228, 230, 232, 234, 236, 239, 241, 243, 245, 248, 250, 252, 255,
|
||||
};
|
||||
|
||||
BuiltInLED::BuiltInLED() {
|
||||
pin_number = (uint8_t) -1; // no pin number
|
||||
state = false; // LED is off
|
||||
hsv_color.value = 0; // black color
|
||||
}
|
||||
|
||||
BuiltInLED::~BuiltInLED(){
|
||||
end();
|
||||
}
|
||||
|
||||
led_indicator_color_hsv_t BuiltInLED::rgb2hsv(led_indicator_color_rgb_t rgb) {
|
||||
led_indicator_color_hsv_t hsv;
|
||||
uint8_t minRGB, maxRGB;
|
||||
uint8_t delta;
|
||||
|
||||
minRGB = rgb.r < rgb.g ? (rgb.r < rgb.b ? rgb.r : rgb.b) : (rgb.g < rgb.b ? rgb.g : rgb.b);
|
||||
maxRGB = rgb.r > rgb.g ? (rgb.r > rgb.b ? rgb.r : rgb.b) : (rgb.g > rgb.b ? rgb.g : rgb.b);
|
||||
hsv.value = 0;
|
||||
hsv.v = maxRGB;
|
||||
delta = maxRGB - minRGB;
|
||||
|
||||
if (delta == 0) {
|
||||
hsv.h = 0;
|
||||
hsv.s = 0;
|
||||
} else {
|
||||
hsv.s = delta * 255 / maxRGB;
|
||||
|
||||
if (rgb.r == maxRGB) {
|
||||
hsv.h = (60 * (rgb.g - rgb.b) / delta + 360) % 360;
|
||||
} else if (rgb.g == maxRGB) {
|
||||
hsv.h = (60 * (rgb.b - rgb.r) / delta + 120);
|
||||
} else {
|
||||
hsv.h = (60 * (rgb.r - rgb.g) / delta + 240);
|
||||
}
|
||||
}
|
||||
return hsv;
|
||||
}
|
||||
|
||||
led_indicator_color_rgb_t BuiltInLED::hsv2rgb(led_indicator_color_hsv_t hsv) {
|
||||
led_indicator_color_rgb_t rgb;
|
||||
uint8_t rgb_max = hsv.v;
|
||||
uint8_t rgb_min = rgb_max * (255 - hsv.s) / 255.0f;
|
||||
|
||||
uint8_t i = hsv.h / 60;
|
||||
uint8_t diff = hsv.h % 60;
|
||||
|
||||
// RGB adjustment amount by hue
|
||||
uint8_t rgb_adj = (rgb_max - rgb_min) * diff / 60;
|
||||
rgb.value = 0;
|
||||
switch (i) {
|
||||
case 0:
|
||||
rgb.r = rgb_max;
|
||||
rgb.g = rgb_min + rgb_adj;
|
||||
rgb.b = rgb_min;
|
||||
break;
|
||||
case 1:
|
||||
rgb.r = rgb_max - rgb_adj;
|
||||
rgb.g = rgb_max;
|
||||
rgb.b = rgb_min;
|
||||
break;
|
||||
case 2:
|
||||
rgb.r = rgb_min;
|
||||
rgb.g = rgb_max;
|
||||
rgb.b = rgb_min + rgb_adj;
|
||||
break;
|
||||
case 3:
|
||||
rgb.r = rgb_min;
|
||||
rgb.g = rgb_max - rgb_adj;
|
||||
rgb.b = rgb_max;
|
||||
break;
|
||||
case 4:
|
||||
rgb.r = rgb_min + rgb_adj;
|
||||
rgb.g = rgb_min;
|
||||
rgb.b = rgb_max;
|
||||
break;
|
||||
default:
|
||||
rgb.r = rgb_max;
|
||||
rgb.g = rgb_min;
|
||||
rgb.b = rgb_max - rgb_adj;
|
||||
break;
|
||||
}
|
||||
|
||||
// gamma correction
|
||||
rgb.r = gamma_table[rgb.r];
|
||||
rgb.g = gamma_table[rgb.g];
|
||||
rgb.b = gamma_table[rgb.b];
|
||||
return rgb;
|
||||
}
|
||||
|
||||
void BuiltInLED::begin(uint8_t pin){
|
||||
if (pin < NUM_DIGITAL_PINS) {
|
||||
pin_number = pin;
|
||||
write();
|
||||
} else {
|
||||
log_e("Invalid pin (%d) number", pin);
|
||||
}
|
||||
}
|
||||
void BuiltInLED::end(){
|
||||
state = false;
|
||||
write();
|
||||
if (pin_number < NUM_DIGITAL_PINS) {
|
||||
if (!rmtDeinit(pin_number)) {
|
||||
log_e("Failed to deinitialize RMT");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BuiltInLED::on(){
|
||||
state = true;
|
||||
}
|
||||
|
||||
void BuiltInLED::off(){
|
||||
state = false;
|
||||
}
|
||||
|
||||
void BuiltInLED::toggle(){
|
||||
state = !state;
|
||||
}
|
||||
|
||||
bool BuiltInLED::getState(){
|
||||
return state;
|
||||
}
|
||||
|
||||
bool BuiltInLED::write(){
|
||||
led_indicator_color_rgb_t rgb_color = getRGB();
|
||||
log_d("Writing to pin %d with state = %s", pin_number, state ? "ON" : "OFF");
|
||||
log_d("HSV: %d, %d, %d", hsv_color.h, hsv_color.s, hsv_color.v);
|
||||
log_d("RGB: %d, %d, %d", rgb_color.r, rgb_color.g, rgb_color.b);
|
||||
if(pin_number < NUM_DIGITAL_PINS){
|
||||
if (state) {
|
||||
rgbLedWrite(pin_number, rgb_color.r, rgb_color.g, rgb_color.b);
|
||||
} else {
|
||||
rgbLedWrite(pin_number, 0, 0, 0);
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
log_e("Invalid pin (%d) number", pin_number);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void BuiltInLED::setBrightness(uint8_t brightness){
|
||||
hsv_color.v = brightness;
|
||||
}
|
||||
|
||||
uint8_t BuiltInLED::getBrightness(){
|
||||
return hsv_color.v;
|
||||
}
|
||||
|
||||
void BuiltInLED::setHSV(led_indicator_color_hsv_t hsv){
|
||||
if (hsv.h > MAX_HUE) {
|
||||
hsv.h = MAX_HUE;
|
||||
}
|
||||
hsv_color.value = hsv.value;
|
||||
}
|
||||
|
||||
led_indicator_color_hsv_t BuiltInLED::getHSV(){
|
||||
return hsv_color;
|
||||
}
|
||||
|
||||
void BuiltInLED::setRGB(led_indicator_color_rgb_t rgb_color){
|
||||
hsv_color = rgb2hsv(rgb_color);
|
||||
}
|
||||
|
||||
led_indicator_color_rgb_t BuiltInLED::getRGB(){
|
||||
return hsv2rgb(hsv_color);
|
||||
}
|
||||
|
||||
void BuiltInLED::setTemperature(uint32_t temperature){
|
||||
uint16_t hue;
|
||||
uint8_t saturation;
|
||||
|
||||
log_d("Requested Temperature: %ld", temperature);
|
||||
//hsv_color.v = gamma_table[((temperature >> 25) & 0x7F)];
|
||||
temperature &= 0xFFFFFF;
|
||||
if (temperature < 600) {
|
||||
hue = 0;
|
||||
saturation = 100;
|
||||
} else {
|
||||
if (temperature > 10000) {
|
||||
hue = 222;
|
||||
saturation = 21 + (temperature - 10000) * 41 / 990000;
|
||||
} else {
|
||||
temperature -= 600;
|
||||
temperature /= 100;
|
||||
hue = temperatureTable[temperature].hue;
|
||||
saturation = temperatureTable[temperature].saturation;
|
||||
}
|
||||
}
|
||||
saturation = (saturation * 255) / 100;
|
||||
// brightness is not changed
|
||||
hsv_color.h = hue;
|
||||
hsv_color.s = saturation;
|
||||
log_d("Calculated Temperature: %ld, Hue: %d, Saturation: %d, Brightness: %d", temperature, hue, saturation, hsv_color.v);
|
||||
}
|
||||
|
||||
/*
|
||||
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||
Unless required by applicable law or agreed to in writing, this
|
||||
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied.
|
||||
This will implement the onboard WS2812b LED as a LED indicator
|
||||
It can be used to indicate some state or status of the device
|
||||
The LED can be controlled using RGB, HSV or color temperature, brightness
|
||||
|
||||
In this example, the LED Indicator class is used as the Matter light accessory
|
||||
*/
|
||||
|
||||
#include "builtinLED.h"
|
||||
|
||||
typedef struct {
|
||||
uint16_t hue;
|
||||
uint8_t saturation;
|
||||
} HS_color_t;
|
||||
|
||||
static const HS_color_t temperatureTable[] = {
|
||||
{4, 100}, {8, 100}, {11, 100}, {14, 100}, {16, 100}, {18, 100}, {20, 100}, {22, 100}, {24, 100}, {25, 100},
|
||||
{27, 100}, {28, 100}, {30, 100}, {31, 100}, {31, 95}, {30, 89}, {30, 85}, {29, 80}, {29, 76}, {29, 73},
|
||||
{29, 69}, {28, 66}, {28, 63}, {28, 60}, {28, 57}, {28, 54}, {28, 52}, {27, 49}, {27, 47}, {27, 45},
|
||||
{27, 43}, {27, 41}, {27, 39}, {27, 37}, {27, 35}, {27, 33}, {27, 31}, {27, 30}, {27, 28}, {27, 26},
|
||||
{27, 25}, {27, 23}, {27, 22}, {27, 21}, {27, 19}, {27, 18}, {27, 17}, {27, 15}, {28, 14}, {28, 13},
|
||||
{28, 12}, {29, 10}, {29, 9}, {30, 8}, {31, 7}, {32, 6}, {34, 5}, {36, 4}, {41, 3}, {49, 2},
|
||||
{0, 0}, {294, 2}, {265, 3}, {251, 4}, {242, 5}, {237, 6}, {233, 7}, {231, 8}, {229, 9}, {228, 10},
|
||||
{227, 11}, {226, 11}, {226, 12}, {225, 13}, {225, 13}, {224, 14}, {224, 14}, {224, 15}, {224, 15}, {223, 16},
|
||||
{223, 16}, {223, 17}, {223, 17}, {223, 17}, {222, 18}, {222, 18}, {222, 19}, {222, 19}, {222, 19}, {222, 19},
|
||||
{222, 20}, {222, 20}, {222, 20}, {222, 21}, {222, 21}
|
||||
};
|
||||
|
||||
/* step brightness table: gamma = 2.3 */
|
||||
static const uint8_t gamma_table[MAX_PROGRESS] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2,
|
||||
2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5,
|
||||
5, 5, 6, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10,
|
||||
10, 10, 11, 11, 12, 12, 13, 13, 13, 14, 14, 15, 15, 16, 16, 17,
|
||||
17, 18, 18, 19, 19, 20, 20, 21, 22, 22, 23, 23, 24, 25, 25, 26,
|
||||
26, 27, 28, 28, 29, 30, 30, 31, 32, 33, 33, 34, 35, 36, 36, 37,
|
||||
38, 39, 40, 40, 41, 42, 43, 44, 45, 45, 46, 47, 48, 49, 50, 51,
|
||||
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67,
|
||||
68, 69, 70, 71, 72, 74, 75, 76, 77, 78, 79, 81, 82, 83, 84, 86,
|
||||
87, 88, 89, 91, 92, 93, 95, 96, 97, 99, 100, 101, 103, 104, 105, 107,
|
||||
108, 110, 111, 112, 114, 115, 117, 118, 120, 121, 123, 124, 126, 128, 129, 131,
|
||||
132, 134, 135, 137, 139, 140, 142, 144, 145, 147, 149, 150, 152, 154, 156, 157,
|
||||
159, 161, 163, 164, 166, 168, 170, 172, 174, 175, 177, 179, 181, 183, 185, 187,
|
||||
189, 191, 193, 195, 197, 199, 201, 203, 205, 207, 209, 211, 213, 215, 217, 219,
|
||||
221, 223, 226, 228, 230, 232, 234, 236, 239, 241, 243, 245, 248, 250, 252, 255,
|
||||
};
|
||||
|
||||
BuiltInLED::BuiltInLED() {
|
||||
pin_number = (uint8_t) -1; // no pin number
|
||||
state = false; // LED is off
|
||||
hsv_color.value = 0; // black color
|
||||
}
|
||||
|
||||
BuiltInLED::~BuiltInLED(){
|
||||
end();
|
||||
}
|
||||
|
||||
led_indicator_color_hsv_t BuiltInLED::rgb2hsv(led_indicator_color_rgb_t rgb) {
|
||||
led_indicator_color_hsv_t hsv;
|
||||
uint8_t minRGB, maxRGB;
|
||||
uint8_t delta;
|
||||
|
||||
minRGB = rgb.r < rgb.g ? (rgb.r < rgb.b ? rgb.r : rgb.b) : (rgb.g < rgb.b ? rgb.g : rgb.b);
|
||||
maxRGB = rgb.r > rgb.g ? (rgb.r > rgb.b ? rgb.r : rgb.b) : (rgb.g > rgb.b ? rgb.g : rgb.b);
|
||||
hsv.value = 0;
|
||||
hsv.v = maxRGB;
|
||||
delta = maxRGB - minRGB;
|
||||
|
||||
if (delta == 0) {
|
||||
hsv.h = 0;
|
||||
hsv.s = 0;
|
||||
} else {
|
||||
hsv.s = delta * 255 / maxRGB;
|
||||
|
||||
if (rgb.r == maxRGB) {
|
||||
hsv.h = (60 * (rgb.g - rgb.b) / delta + 360) % 360;
|
||||
} else if (rgb.g == maxRGB) {
|
||||
hsv.h = (60 * (rgb.b - rgb.r) / delta + 120);
|
||||
} else {
|
||||
hsv.h = (60 * (rgb.r - rgb.g) / delta + 240);
|
||||
}
|
||||
}
|
||||
return hsv;
|
||||
}
|
||||
|
||||
led_indicator_color_rgb_t BuiltInLED::hsv2rgb(led_indicator_color_hsv_t hsv) {
|
||||
led_indicator_color_rgb_t rgb;
|
||||
uint8_t rgb_max = hsv.v;
|
||||
uint8_t rgb_min = rgb_max * (255 - hsv.s) / 255.0f;
|
||||
|
||||
uint8_t i = hsv.h / 60;
|
||||
uint8_t diff = hsv.h % 60;
|
||||
|
||||
// RGB adjustment amount by hue
|
||||
uint8_t rgb_adj = (rgb_max - rgb_min) * diff / 60;
|
||||
rgb.value = 0;
|
||||
switch (i) {
|
||||
case 0:
|
||||
rgb.r = rgb_max;
|
||||
rgb.g = rgb_min + rgb_adj;
|
||||
rgb.b = rgb_min;
|
||||
break;
|
||||
case 1:
|
||||
rgb.r = rgb_max - rgb_adj;
|
||||
rgb.g = rgb_max;
|
||||
rgb.b = rgb_min;
|
||||
break;
|
||||
case 2:
|
||||
rgb.r = rgb_min;
|
||||
rgb.g = rgb_max;
|
||||
rgb.b = rgb_min + rgb_adj;
|
||||
break;
|
||||
case 3:
|
||||
rgb.r = rgb_min;
|
||||
rgb.g = rgb_max - rgb_adj;
|
||||
rgb.b = rgb_max;
|
||||
break;
|
||||
case 4:
|
||||
rgb.r = rgb_min + rgb_adj;
|
||||
rgb.g = rgb_min;
|
||||
rgb.b = rgb_max;
|
||||
break;
|
||||
default:
|
||||
rgb.r = rgb_max;
|
||||
rgb.g = rgb_min;
|
||||
rgb.b = rgb_max - rgb_adj;
|
||||
break;
|
||||
}
|
||||
|
||||
// gamma correction
|
||||
rgb.r = gamma_table[rgb.r];
|
||||
rgb.g = gamma_table[rgb.g];
|
||||
rgb.b = gamma_table[rgb.b];
|
||||
return rgb;
|
||||
}
|
||||
|
||||
void BuiltInLED::begin(uint8_t pin){
|
||||
if (pin < NUM_DIGITAL_PINS) {
|
||||
pin_number = pin;
|
||||
log_i("Initializing pin %d", pin);
|
||||
} else {
|
||||
log_e("Invalid pin (%d) number", pin);
|
||||
}
|
||||
}
|
||||
void BuiltInLED::end(){
|
||||
state = false;
|
||||
write(); // turn off the LED
|
||||
if (pin_number < NUM_DIGITAL_PINS) {
|
||||
if (!rmtDeinit(pin_number)) {
|
||||
log_e("Failed to deinitialize RMT");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BuiltInLED::on(){
|
||||
state = true;
|
||||
}
|
||||
|
||||
void BuiltInLED::off(){
|
||||
state = false;
|
||||
}
|
||||
|
||||
void BuiltInLED::toggle(){
|
||||
state = !state;
|
||||
}
|
||||
|
||||
bool BuiltInLED::getState(){
|
||||
return state;
|
||||
}
|
||||
|
||||
bool BuiltInLED::write(){
|
||||
led_indicator_color_rgb_t rgb_color = getRGB();
|
||||
log_d("Writing to pin %d with state = %s", pin_number, state ? "ON" : "OFF");
|
||||
log_d("HSV: %d, %d, %d", hsv_color.h, hsv_color.s, hsv_color.v);
|
||||
log_d("RGB: %d, %d, %d", rgb_color.r, rgb_color.g, rgb_color.b);
|
||||
if(pin_number < NUM_DIGITAL_PINS){
|
||||
if (state) {
|
||||
rgbLedWrite(pin_number, rgb_color.r, rgb_color.g, rgb_color.b);
|
||||
} else {
|
||||
rgbLedWrite(pin_number, 0, 0, 0);
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
log_e("Invalid pin (%d) number", pin_number);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void BuiltInLED::setBrightness(uint8_t brightness){
|
||||
hsv_color.v = brightness;
|
||||
}
|
||||
|
||||
uint8_t BuiltInLED::getBrightness(){
|
||||
return hsv_color.v;
|
||||
}
|
||||
|
||||
void BuiltInLED::setHSV(led_indicator_color_hsv_t hsv){
|
||||
if (hsv.h > MAX_HUE) {
|
||||
hsv.h = MAX_HUE;
|
||||
}
|
||||
hsv_color.value = hsv.value;
|
||||
}
|
||||
|
||||
led_indicator_color_hsv_t BuiltInLED::getHSV(){
|
||||
return hsv_color;
|
||||
}
|
||||
|
||||
void BuiltInLED::setRGB(led_indicator_color_rgb_t rgb_color){
|
||||
hsv_color = rgb2hsv(rgb_color);
|
||||
}
|
||||
|
||||
led_indicator_color_rgb_t BuiltInLED::getRGB(){
|
||||
return hsv2rgb(hsv_color);
|
||||
}
|
||||
|
||||
void BuiltInLED::setTemperature(uint32_t temperature){
|
||||
uint16_t hue;
|
||||
uint8_t saturation;
|
||||
|
||||
log_d("Requested Temperature: %ld", temperature);
|
||||
//hsv_color.v = gamma_table[((temperature >> 25) & 0x7F)];
|
||||
temperature &= 0xFFFFFF;
|
||||
if (temperature < 600) {
|
||||
hue = 0;
|
||||
saturation = 100;
|
||||
} else {
|
||||
if (temperature > 10000) {
|
||||
hue = 222;
|
||||
saturation = 21 + (temperature - 10000) * 41 / 990000;
|
||||
} else {
|
||||
temperature -= 600;
|
||||
temperature /= 100;
|
||||
hue = temperatureTable[temperature].hue;
|
||||
saturation = temperatureTable[temperature].saturation;
|
||||
}
|
||||
}
|
||||
saturation = (saturation * 255) / 100;
|
||||
// brightness is not changed
|
||||
hsv_color.h = hue;
|
||||
hsv_color.s = saturation;
|
||||
log_d("Calculated Temperature: %ld, Hue: %d, Saturation: %d, Brightness: %d", temperature, hue, saturation, hsv_color.v);
|
||||
}
|
||||
@@ -1,76 +1,74 @@
|
||||
/*
|
||||
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||
|
||||
Unless required by applicable law or agreed to in writing, this
|
||||
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
||||
This will implement the onboard WS2812b LED as a LED indicator
|
||||
It can be used to indicate some state or status of the device
|
||||
The LED can be controlled using RGB, HSV or color temperature, brightness
|
||||
|
||||
In this example, the BuiltInLED class is used as the Matter light accessory
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#define MAX_HUE 360
|
||||
#define MAX_SATURATION 255
|
||||
#define MAX_BRIGHTNESS 255
|
||||
#define MAX_PROGRESS 256
|
||||
|
||||
typedef struct {
|
||||
union {
|
||||
struct {
|
||||
uint32_t v: 8; /*!< Brightness/Value of the LED. 0-255 */
|
||||
uint32_t s: 8; /*!< Saturation of the LED. 0-255 */
|
||||
uint32_t h: 9; /*!< Hue of the LED. 0-360 */
|
||||
};
|
||||
uint32_t value; /*!< IHSV value of the LED. */
|
||||
};
|
||||
} led_indicator_color_hsv_t;
|
||||
|
||||
typedef struct {
|
||||
union {
|
||||
struct {
|
||||
uint32_t r: 8; /*!< Red component of the LED color. Range: 0-255. */
|
||||
uint32_t g: 8; /*!< Green component of the LED color. Range: 0-255. */
|
||||
uint32_t b: 8; /*!< Blue component of the LED color. Range: 0-255. */
|
||||
};
|
||||
uint32_t value; /*!< Combined RGB value of the LED color. */
|
||||
};
|
||||
} led_indicator_color_rgb_t;
|
||||
|
||||
class BuiltInLED {
|
||||
private:
|
||||
uint8_t pin_number;
|
||||
bool state;
|
||||
led_indicator_color_hsv_t hsv_color;
|
||||
|
||||
public:
|
||||
BuiltInLED();
|
||||
~BuiltInLED();
|
||||
|
||||
static led_indicator_color_hsv_t rgb2hsv(led_indicator_color_rgb_t rgb_value);
|
||||
static led_indicator_color_rgb_t hsv2rgb(led_indicator_color_hsv_t hsv);
|
||||
|
||||
void begin(uint8_t pin);
|
||||
void end();
|
||||
|
||||
void on();
|
||||
void off();
|
||||
void toggle();
|
||||
bool getState();
|
||||
|
||||
bool write();
|
||||
|
||||
void setBrightness(uint8_t brightness);
|
||||
uint8_t getBrightness();
|
||||
void setHSV(led_indicator_color_hsv_t hsv);
|
||||
led_indicator_color_hsv_t getHSV();
|
||||
void setRGB(led_indicator_color_rgb_t color);
|
||||
led_indicator_color_rgb_t getRGB();
|
||||
void setTemperature(uint32_t temperature);
|
||||
};
|
||||
/*
|
||||
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||
Unless required by applicable law or agreed to in writing, this
|
||||
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied.
|
||||
This will implement the onboard WS2812b LED as a LED indicator
|
||||
It can be used to indicate some state or status of the device
|
||||
The LED can be controlled using RGB, HSV or color temperature, brightness
|
||||
|
||||
In this example, the BuiltInLED class is used as the Matter light accessory
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#define MAX_HUE 360
|
||||
#define MAX_SATURATION 255
|
||||
#define MAX_BRIGHTNESS 255
|
||||
#define MAX_PROGRESS 256
|
||||
|
||||
typedef struct {
|
||||
union {
|
||||
struct {
|
||||
uint32_t v: 8; /*!< Brightness/Value of the LED. 0-255 */
|
||||
uint32_t s: 8; /*!< Saturation of the LED. 0-255 */
|
||||
uint32_t h: 9; /*!< Hue of the LED. 0-360 */
|
||||
};
|
||||
uint32_t value; /*!< IHSV value of the LED. */
|
||||
};
|
||||
} led_indicator_color_hsv_t;
|
||||
|
||||
typedef struct {
|
||||
union {
|
||||
struct {
|
||||
uint32_t r: 8; /*!< Red component of the LED color. Range: 0-255. */
|
||||
uint32_t g: 8; /*!< Green component of the LED color. Range: 0-255. */
|
||||
uint32_t b: 8; /*!< Blue component of the LED color. Range: 0-255. */
|
||||
};
|
||||
uint32_t value; /*!< Combined RGB value of the LED color. */
|
||||
};
|
||||
} led_indicator_color_rgb_t;
|
||||
|
||||
class BuiltInLED {
|
||||
private:
|
||||
uint8_t pin_number;
|
||||
bool state;
|
||||
led_indicator_color_hsv_t hsv_color;
|
||||
|
||||
public:
|
||||
BuiltInLED();
|
||||
~BuiltInLED();
|
||||
|
||||
static led_indicator_color_hsv_t rgb2hsv(led_indicator_color_rgb_t rgb_value);
|
||||
static led_indicator_color_rgb_t hsv2rgb(led_indicator_color_hsv_t hsv);
|
||||
|
||||
void begin(uint8_t pin);
|
||||
void end();
|
||||
|
||||
void on();
|
||||
void off();
|
||||
void toggle();
|
||||
bool getState();
|
||||
|
||||
bool write();
|
||||
|
||||
void setBrightness(uint8_t brightness);
|
||||
uint8_t getBrightness();
|
||||
void setHSV(led_indicator_color_hsv_t hsv);
|
||||
led_indicator_color_hsv_t getHSV();
|
||||
void setRGB(led_indicator_color_rgb_t color);
|
||||
led_indicator_color_rgb_t getRGB();
|
||||
void setTemperature(uint32_t temperature);
|
||||
};
|
||||
@@ -1,6 +1,5 @@
|
||||
/*
|
||||
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||
|
||||
Unless required by applicable law or agreed to in writing, this
|
||||
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied.
|
||||
@@ -11,9 +10,6 @@
|
||||
#include "builtinLED.h"
|
||||
#include "matter_accessory_driver.h"
|
||||
|
||||
// set your board WS2812b pin here (e.g. 48 is the default pin for the ESP32-S3 devkit)
|
||||
#define WS2812_PIN 48
|
||||
|
||||
/* Do any conversions/remapping for the actual value here */
|
||||
esp_err_t light_accessory_set_power(void *led, uint8_t val)
|
||||
{
|
||||
@@ -95,7 +91,5 @@ app_driver_handle_t light_accessory_init()
|
||||
|
||||
const uint8_t pin = WS2812_PIN; // set your board WS2812b pin here
|
||||
builtinLED.begin(pin);
|
||||
builtinLED.setHSV({DEFAULT_HUE, DEFAULT_SATURATION, DEFAULT_BRIGHTNESS});
|
||||
builtinLED.write();
|
||||
return (app_driver_handle_t) &builtinLED;
|
||||
}
|
||||
|
||||
@@ -1,28 +1,47 @@
|
||||
#include <esp_err.h>
|
||||
|
||||
/** Standard max values (used for remapping attributes) */
|
||||
#define STANDARD_BRIGHTNESS 255
|
||||
#define STANDARD_HUE 360
|
||||
#define STANDARD_SATURATION 255
|
||||
#define STANDARD_TEMPERATURE_FACTOR 1000000
|
||||
|
||||
/** Matter max values (used for remapping attributes) */
|
||||
#define MATTER_BRIGHTNESS 254
|
||||
#define MATTER_HUE 254
|
||||
#define MATTER_SATURATION 254
|
||||
#define MATTER_TEMPERATURE_FACTOR 1000000
|
||||
|
||||
/** Default attribute values used during initialization */
|
||||
#define DEFAULT_POWER true
|
||||
#define DEFAULT_BRIGHTNESS 64
|
||||
#define DEFAULT_HUE 128
|
||||
#define DEFAULT_SATURATION 254
|
||||
|
||||
typedef void *app_driver_handle_t;
|
||||
|
||||
esp_err_t light_accessory_set_power(void *led, uint8_t val);
|
||||
esp_err_t light_accessory_set_brightness(void *led, uint8_t val);
|
||||
esp_err_t light_accessory_set_hue(void *led, uint8_t val);
|
||||
esp_err_t light_accessory_set_saturation(void *led, uint8_t val);
|
||||
esp_err_t light_accessory_set_temperature(void *led, uint16_t val);
|
||||
app_driver_handle_t light_accessory_init();
|
||||
#include <esp_err.h>
|
||||
#include <sdkconfig.h>
|
||||
|
||||
// set your board WS2812b pin here (e.g. 48 is the default pin for the ESP32-S3 devkit)
|
||||
#ifndef CONFIG_WS2812_PIN
|
||||
#define WS2812_PIN 48 // ESP32-S3 DevKitC built-in LED
|
||||
#else
|
||||
#define WS2812_PIN CONFIG_WS2812_PIN // From sdkconfig.defaults.<soc>
|
||||
#endif
|
||||
|
||||
#ifndef RGB_BUILTIN
|
||||
#define RGB_BUILTIN WS2812_PIN
|
||||
#endif
|
||||
|
||||
// Set your board button pin here (e.g. 0 is the default pin for the ESP32-S3 devkit)
|
||||
#ifndef CONFIG_BUTTON_PIN
|
||||
#define BUTTON_PIN 0 // ESP32-S3 DevKitC built-in button
|
||||
#else
|
||||
#define BUTTON_PIN CONFIG_BUTTON_PIN // From sdkconfig.defaults.<soc>
|
||||
#endif
|
||||
|
||||
/** Standard max values (used for remapping attributes) */
|
||||
#define STANDARD_BRIGHTNESS 255
|
||||
#define STANDARD_HUE 360
|
||||
#define STANDARD_SATURATION 255
|
||||
#define STANDARD_TEMPERATURE_FACTOR 1000000
|
||||
|
||||
/** Matter max values (used for remapping attributes) */
|
||||
#define MATTER_BRIGHTNESS 254
|
||||
#define MATTER_HUE 254
|
||||
#define MATTER_SATURATION 254
|
||||
#define MATTER_TEMPERATURE_FACTOR 1000000
|
||||
|
||||
/** Default attribute values used during initialization */
|
||||
#define DEFAULT_POWER true
|
||||
#define DEFAULT_BRIGHTNESS 64
|
||||
#define DEFAULT_HUE 128
|
||||
#define DEFAULT_SATURATION 254
|
||||
|
||||
typedef void *app_driver_handle_t;
|
||||
|
||||
esp_err_t light_accessory_set_power(void *led, uint8_t val);
|
||||
esp_err_t light_accessory_set_brightness(void *led, uint8_t val);
|
||||
esp_err_t light_accessory_set_hue(void *led, uint8_t val);
|
||||
esp_err_t light_accessory_set_saturation(void *led, uint8_t val);
|
||||
esp_err_t light_accessory_set_temperature(void *led, uint16_t val);
|
||||
app_driver_handle_t light_accessory_init();
|
||||
@@ -1,6 +1,5 @@
|
||||
/*
|
||||
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||
|
||||
Unless required by applicable law or agreed to in writing, this
|
||||
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied.
|
||||
@@ -37,6 +36,9 @@
|
||||
}
|
||||
#endif
|
||||
|
||||
// set your board button pin here
|
||||
const uint8_t button_gpio = BUTTON_PIN; // GPIO BOOT Button
|
||||
|
||||
uint16_t light_endpoint_id = 0;
|
||||
|
||||
using namespace esp_matter;
|
||||
@@ -54,11 +56,29 @@ static const char *s_decryption_key = decryption_key_start;
|
||||
static const uint16_t s_decryption_key_len = decryption_key_end - decryption_key_start;
|
||||
#endif // CONFIG_ENABLE_ENCRYPTED_OTA
|
||||
|
||||
bool isAccessoryCommissioned() {
|
||||
return chip::Server::GetInstance().GetFabricTable().FabricCount() > 0;
|
||||
}
|
||||
|
||||
#if CHIP_DEVICE_CONFIG_ENABLE_WIFI_STATION
|
||||
bool isWifiConnected() {
|
||||
return chip::DeviceLayer::ConnectivityMgr().IsWiFiStationConnected();
|
||||
}
|
||||
#endif
|
||||
|
||||
#if CHIP_DEVICE_CONFIG_ENABLE_THREAD
|
||||
bool isThreadConnected() {
|
||||
return chip::DeviceLayer::ConnectivityMgr().IsThreadAttached();
|
||||
}
|
||||
#endif
|
||||
|
||||
static void app_event_cb(const ChipDeviceEvent *event, intptr_t arg)
|
||||
{
|
||||
switch (event->Type) {
|
||||
case chip::DeviceLayer::DeviceEventType::kInterfaceIpAddressChanged:
|
||||
log_i("Interface IP Address changed");
|
||||
log_i("Interface %s Address changed",
|
||||
event->InterfaceIpAddressChanged.Type == chip::DeviceLayer::InterfaceIpChangeType::kIpV4_Assigned ?
|
||||
"IPv4" : "IPV6" );
|
||||
break;
|
||||
|
||||
case chip::DeviceLayer::DeviceEventType::kCommissioningComplete:
|
||||
@@ -129,40 +149,6 @@ static void app_event_cb(const ChipDeviceEvent *event, intptr_t arg)
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t button_time_stamp = 0;
|
||||
static void button_driver_down_cb()
|
||||
{
|
||||
button_time_stamp = millis();
|
||||
}
|
||||
|
||||
|
||||
static void button_driver_up_cb()
|
||||
{
|
||||
uint32_t time_diff = millis() - button_time_stamp;
|
||||
// Factory reset is triggered if the button is pressed for more than 3 seconds
|
||||
if (time_diff > 3000) {
|
||||
log_i("Factory reset triggered. Light will retored to factory settings.");
|
||||
esp_matter::factory_reset();
|
||||
return;
|
||||
}
|
||||
|
||||
// Toggle button is pressed - toggle the light
|
||||
log_i("Toggle button pressed");
|
||||
uint16_t endpoint_id = light_endpoint_id;
|
||||
uint32_t cluster_id = OnOff::Id;
|
||||
uint32_t attribute_id = OnOff::Attributes::OnOff::Id;
|
||||
|
||||
node_t *node = node::get();
|
||||
endpoint_t *endpoint = endpoint::get(node, endpoint_id);
|
||||
cluster_t *cluster = cluster::get(endpoint, cluster_id);
|
||||
attribute_t *attribute = attribute::get(cluster, attribute_id);
|
||||
|
||||
esp_matter_attr_val_t val = esp_matter_invalid(NULL);
|
||||
attribute::get_val(attribute, &val);
|
||||
val.val.b = !val.val.b;
|
||||
attribute::update(endpoint_id, cluster_id, attribute_id, &val);
|
||||
}
|
||||
|
||||
esp_err_t matter_light_attribute_update(app_driver_handle_t driver_handle, uint16_t endpoint_id, uint32_t cluster_id,
|
||||
uint32_t attribute_id, esp_matter_attr_val_t *val)
|
||||
{
|
||||
@@ -241,10 +227,7 @@ esp_err_t matter_light_set_defaults(uint16_t endpoint_id)
|
||||
void button_driver_init()
|
||||
{
|
||||
/* Initialize button */
|
||||
uint8_t pin = 0; // set your board button pin here
|
||||
pinMode(pin, INPUT_PULLUP);
|
||||
attachInterrupt(digitalPinToInterrupt(pin), button_driver_down_cb, FALLING); // pressed
|
||||
attachInterrupt(digitalPinToInterrupt(pin), button_driver_up_cb, RISING); // released
|
||||
pinMode(button_gpio, INPUT_PULLUP);
|
||||
}
|
||||
|
||||
// This callback is called for every attribute update. The callback implementation shall
|
||||
@@ -277,9 +260,6 @@ void setup()
|
||||
{
|
||||
esp_err_t err = ESP_OK;
|
||||
|
||||
/* Initialize the ESP NVS layer */
|
||||
//nvs_flash_init();
|
||||
|
||||
/* Initialize driver */
|
||||
app_driver_handle_t light_handle = light_accessory_init();
|
||||
button_driver_init();
|
||||
@@ -309,7 +289,7 @@ void setup()
|
||||
log_e("Failed to create extended color light endpoint");
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
light_endpoint_id = endpoint::get_id(endpoint);
|
||||
log_i("Light created with endpoint_id %d", light_endpoint_id);
|
||||
|
||||
@@ -343,9 +323,6 @@ void setup()
|
||||
abort();
|
||||
}
|
||||
|
||||
/* Starting driver with default values */
|
||||
matter_light_set_defaults(light_endpoint_id);
|
||||
|
||||
#if CONFIG_ENABLE_ENCRYPTED_OTA
|
||||
err = esp_matter_ota_requestor_encrypted_init(s_decryption_key, s_decryption_key_len);
|
||||
if (err != ESP_OK) {
|
||||
@@ -365,5 +342,80 @@ void setup()
|
||||
}
|
||||
|
||||
void loop() {
|
||||
delay(1000);
|
||||
static uint32_t button_time_stamp = 0;
|
||||
static bool button_state = false;
|
||||
static bool started = false;
|
||||
|
||||
if(!isAccessoryCommissioned()) {
|
||||
log_w("Accessory not commissioned yet. Waiting for commissioning.");
|
||||
#ifdef RGB_BUILTIN
|
||||
rgbLedWrite(RGB_BUILTIN, 48, 0, 20); // Purple indicates accessory not commissioned
|
||||
#endif
|
||||
delay(5000);
|
||||
return;
|
||||
}
|
||||
|
||||
#if CHIP_DEVICE_CONFIG_ENABLE_WIFI_STATION
|
||||
if (!isWifiConnected()) {
|
||||
log_w("Wi-Fi not connected yet. Waiting for connection.");
|
||||
#ifdef RGB_BUILTIN
|
||||
rgbLedWrite(RGB_BUILTIN, 48, 20, 0); // Orange indicates accessory not connected to Wi-Fi
|
||||
#endif
|
||||
delay(5000);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if CHIP_DEVICE_CONFIG_ENABLE_THREAD
|
||||
if (!isThreadConnected()) {
|
||||
log_w("Thread not connected yet. Waiting for connection.");
|
||||
#ifdef RGB_BUILTIN
|
||||
rgbLedWrite(RGB_BUILTIN, 0, 20, 48); // Blue indicates accessory not connected to Trhead
|
||||
#endif
|
||||
delay(5000);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Once all network connections are established, the accessory is ready for use
|
||||
// Run it only once
|
||||
if (!started) {
|
||||
log_i("Accessory is commissioned and connected to Wi-Fi. Ready for use.");
|
||||
started = true;
|
||||
// Starting driver with default values
|
||||
matter_light_set_defaults(light_endpoint_id);
|
||||
}
|
||||
|
||||
// Check if the button is pressed and toggle the light right away
|
||||
if (digitalRead(button_gpio) == LOW && !button_state) {
|
||||
// deals with button debounce
|
||||
button_time_stamp = millis(); // record the time while the button is pressed.
|
||||
button_state = true; // pressed.
|
||||
|
||||
// Toggle button is pressed - toggle the light
|
||||
log_i("Toggle button pressed");
|
||||
|
||||
endpoint_t *endpoint = endpoint::get(node::get(), light_endpoint_id);
|
||||
cluster_t *cluster = cluster::get(endpoint, OnOff::Id);
|
||||
attribute_t *attribute = attribute::get(cluster, OnOff::Attributes::OnOff::Id);
|
||||
|
||||
esp_matter_attr_val_t val = esp_matter_invalid(NULL);
|
||||
attribute::get_val(attribute, &val);
|
||||
val.val.b = !val.val.b;
|
||||
attribute::update(light_endpoint_id, OnOff::Id, OnOff::Attributes::OnOff::Id, &val);
|
||||
}
|
||||
|
||||
// Check if the button is released and handle the factory reset
|
||||
uint32_t time_diff = millis() - button_time_stamp;
|
||||
if (button_state && time_diff > 100 && digitalRead(button_gpio) == HIGH) {
|
||||
button_state = false; // released. It can be pressed again after 100ms debounce.
|
||||
|
||||
// Factory reset is triggered if the button is pressed for more than 10 seconds
|
||||
if (time_diff > 10000) {
|
||||
log_i("Factory reset triggered. Light will retored to factory settings.");
|
||||
esp_matter::factory_reset();
|
||||
}
|
||||
}
|
||||
|
||||
delay(50); // WDT is happier with a delay
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
# Name, Type, SubType, Offset, Size, Flags
|
||||
# Note: Firmware partition offset needs to be 64K aligned, initial 36K (9 sectors) are reserved for bootloader and partition table
|
||||
esp_secure_cert, 0x3F, ,0xd000, 0x2000, encrypted
|
||||
nvs, data, nvs, 0x10000, 0xC000,
|
||||
nvs_keys, data, nvs_keys,, 0x1000, encrypted
|
||||
|
||||
|
@@ -7,6 +7,8 @@
|
||||
;
|
||||
; Please visit documentation for the other options and examples
|
||||
; https://docs.platformio.org/page/projectconf.html
|
||||
|
||||
|
||||
[platformio]
|
||||
src_dir = main
|
||||
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
CONFIG_IDF_TARGET="esp32c6"
|
||||
|
||||
# Arduino Settings
|
||||
CONFIG_FREERTOS_HZ=1000
|
||||
CONFIG_AUTOSTART_ARDUINO=y
|
||||
|
||||
# Log Levels
|
||||
# Boot Messages - Log level
|
||||
CONFIG_BOOTLOADER_LOG_LEVEL_ERROR=y
|
||||
# Arduino Log Level
|
||||
CONFIG_ARDUHAL_LOG_DEFAULT_LEVEL_INFO=y
|
||||
# IDF Log Level
|
||||
CONFIG_LOG_DEFAULT_LEVEL_ERROR=y
|
||||
|
||||
# Default to 921600 baud when flashing and monitoring device
|
||||
CONFIG_ESPTOOLPY_BAUD_921600B=y
|
||||
CONFIG_ESPTOOLPY_BAUD=921600
|
||||
CONFIG_ESPTOOLPY_COMPRESSED=y
|
||||
CONFIG_ESPTOOLPY_MONITOR_BAUD_115200B=y
|
||||
CONFIG_ESPTOOLPY_MONITOR_BAUD=115200
|
||||
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
|
||||
|
||||
# libsodium
|
||||
CONFIG_LIBSODIUM_USE_MBEDTLS_SHA=y
|
||||
|
||||
# NIMBLE
|
||||
CONFIG_BT_ENABLED=y
|
||||
CONFIG_BT_NIMBLE_ENABLED=y
|
||||
CONFIG_BT_NIMBLE_EXT_ADV=n
|
||||
CONFIG_BT_NIMBLE_HCI_EVT_BUF_SIZE=70
|
||||
CONFIG_USE_BLE_ONLY_FOR_COMMISSIONING=n
|
||||
|
||||
# FreeRTOS should use legacy API
|
||||
CONFIG_FREERTOS_ENABLE_BACKWARD_COMPATIBILITY=y
|
||||
|
||||
# Enable OpenThread
|
||||
CONFIG_OPENTHREAD_ENABLED=y
|
||||
CONFIG_OPENTHREAD_SRP_CLIENT=y
|
||||
CONFIG_OPENTHREAD_DNS_CLIENT=y
|
||||
CONFIG_OPENTHREAD_LOG_LEVEL_DYNAMIC=n
|
||||
CONFIG_OPENTHREAD_LOG_LEVEL_NOTE=y
|
||||
CONFIG_OPENTHREAD_CLI=n
|
||||
|
||||
# Disable lwip ipv6 autoconfig
|
||||
CONFIG_LWIP_IPV6_AUTOCONFIG=n
|
||||
|
||||
# Use a custom partition table
|
||||
CONFIG_PARTITION_TABLE_CUSTOM=y
|
||||
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
|
||||
|
||||
# LwIP config for OpenThread
|
||||
CONFIG_LWIP_IPV6_NUM_ADDRESSES=8
|
||||
CONFIG_LWIP_MULTICAST_PING=y
|
||||
|
||||
# MDNS platform
|
||||
CONFIG_USE_MINIMAL_MDNS=n
|
||||
CONFIG_ENABLE_EXTENDED_DISCOVERY=y
|
||||
|
||||
# Enable OTA Requestor
|
||||
CONFIG_ENABLE_OTA_REQUESTOR=n
|
||||
|
||||
# Disable STA and AP for ESP32C6
|
||||
CONFIG_ENABLE_WIFI_STATION=n
|
||||
CONFIG_ENABLE_WIFI_AP=n
|
||||
|
||||
# Enable chip shell
|
||||
CONFIG_ENABLE_CHIP_SHELL=n
|
||||
|
||||
# Disable persist subscriptions
|
||||
CONFIG_ENABLE_PERSIST_SUBSCRIPTIONS=n
|
||||
|
||||
# MRP configs
|
||||
CONFIG_MRP_LOCAL_ACTIVE_RETRY_INTERVAL_FOR_THREAD=5000
|
||||
CONFIG_MRP_LOCAL_IDLE_RETRY_INTERVAL_FOR_THREAD=5000
|
||||
CONFIG_MRP_RETRY_INTERVAL_SENDER_BOOST_FOR_THREAD=5000
|
||||
CONFIG_MRP_MAX_RETRANS=3
|
||||
|
||||
# Enable HKDF in mbedtls
|
||||
CONFIG_MBEDTLS_HKDF_C=y
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
CONFIG_IDF_TARGET="esp32c3"
|
||||
|
||||
# Arduino Settings
|
||||
CONFIG_FREERTOS_HZ=1000
|
||||
CONFIG_AUTOSTART_ARDUINO=y
|
||||
|
||||
# Log Levels
|
||||
# Boot Messages - Log level
|
||||
CONFIG_BOOTLOADER_LOG_LEVEL_ERROR=y
|
||||
# Arduino Log Level
|
||||
CONFIG_ARDUHAL_LOG_DEFAULT_LEVEL_INFO=y
|
||||
# IDF Log Level
|
||||
CONFIG_LOG_DEFAULT_LEVEL_ERROR=y
|
||||
|
||||
# Default to 921600 baud when flashing and monitoring device
|
||||
CONFIG_ESPTOOLPY_BAUD_921600B=y
|
||||
CONFIG_ESPTOOLPY_BAUD=921600
|
||||
CONFIG_ESPTOOLPY_COMPRESSED=y
|
||||
CONFIG_ESPTOOLPY_MONITOR_BAUD_115200B=y
|
||||
CONFIG_ESPTOOLPY_MONITOR_BAUD=115200
|
||||
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
|
||||
|
||||
#enable BT
|
||||
CONFIG_BT_ENABLED=y
|
||||
CONFIG_BT_NIMBLE_ENABLED=y
|
||||
|
||||
#disable BT connection reattempt
|
||||
CONFIG_BT_NIMBLE_ENABLE_CONN_REATTEMPT=n
|
||||
|
||||
#enable lwip ipv6 autoconfig
|
||||
CONFIG_LWIP_IPV6_AUTOCONFIG=y
|
||||
|
||||
# Use a custom partition table
|
||||
CONFIG_PARTITION_TABLE_CUSTOM=y
|
||||
CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"
|
||||
CONFIG_PARTITION_TABLE_OFFSET=0xC000
|
||||
|
||||
# Disable chip shell
|
||||
CONFIG_ENABLE_CHIP_SHELL=n
|
||||
|
||||
# Enable OTA Requestor
|
||||
CONFIG_ENABLE_OTA_REQUESTOR=n
|
||||
|
||||
#enable lwIP route hooks
|
||||
CONFIG_LWIP_HOOK_IP6_ROUTE_DEFAULT=y
|
||||
CONFIG_LWIP_HOOK_ND6_GET_GW_DEFAULT=y
|
||||
|
||||
# disable softap by default
|
||||
CONFIG_ESP_WIFI_SOFTAP_SUPPORT=n
|
||||
CONFIG_ENABLE_WIFI_STATION=y
|
||||
CONFIG_ENABLE_WIFI_AP=n
|
||||
|
||||
# Disable DS Peripheral
|
||||
CONFIG_ESP_SECURE_CERT_DS_PERIPHERAL=n
|
||||
|
||||
# Use compact attribute storage mode
|
||||
CONFIG_ESP_MATTER_NVS_USE_COMPACT_ATTR_STORAGE=y
|
||||
|
||||
# Enable HKDF in mbedtls
|
||||
CONFIG_MBEDTLS_HKDF_C=y
|
||||
|
||||
# Increase LwIP IPv6 address number to 6 (MAX_FABRIC + 1)
|
||||
# unique local addresses for fabrics(MAX_FABRIC), a link local address(1)
|
||||
CONFIG_LWIP_IPV6_NUM_ADDRESSES=6
|
||||
@@ -0,0 +1,79 @@
|
||||
CONFIG_IDF_TARGET="esp32c6"
|
||||
|
||||
# Arduino Settings
|
||||
CONFIG_FREERTOS_HZ=1000
|
||||
CONFIG_AUTOSTART_ARDUINO=y
|
||||
|
||||
# Log Levels
|
||||
# Boot Messages - Log level
|
||||
CONFIG_BOOTLOADER_LOG_LEVEL_ERROR=y
|
||||
# Arduino Log Level
|
||||
CONFIG_ARDUHAL_LOG_DEFAULT_LEVEL_INFO=y
|
||||
# IDF Log Level
|
||||
CONFIG_LOG_DEFAULT_LEVEL_ERROR=y
|
||||
|
||||
# Default to 921600 baud when flashing and monitoring device
|
||||
CONFIG_ESPTOOLPY_BAUD_921600B=y
|
||||
CONFIG_ESPTOOLPY_BAUD=921600
|
||||
CONFIG_ESPTOOLPY_COMPRESSED=y
|
||||
CONFIG_ESPTOOLPY_MONITOR_BAUD_115200B=y
|
||||
CONFIG_ESPTOOLPY_MONITOR_BAUD=115200
|
||||
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
|
||||
|
||||
#enable BT
|
||||
CONFIG_BT_ENABLED=y
|
||||
CONFIG_BT_NIMBLE_ENABLED=y
|
||||
|
||||
#disable BT connection reattempt
|
||||
CONFIG_BT_NIMBLE_ENABLE_CONN_REATTEMPT=n
|
||||
|
||||
#enable lwip ipv6 autoconfig
|
||||
CONFIG_LWIP_IPV6_AUTOCONFIG=y
|
||||
|
||||
# Use a custom partition table
|
||||
CONFIG_PARTITION_TABLE_CUSTOM=y
|
||||
CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"
|
||||
CONFIG_PARTITION_TABLE_OFFSET=0xC000
|
||||
|
||||
# Disable chip shell
|
||||
CONFIG_ENABLE_CHIP_SHELL=n
|
||||
|
||||
# Enable OTA Requestor
|
||||
CONFIG_ENABLE_OTA_REQUESTOR=n
|
||||
|
||||
#enable lwIP route hooks
|
||||
CONFIG_LWIP_HOOK_IP6_ROUTE_DEFAULT=y
|
||||
CONFIG_LWIP_HOOK_ND6_GET_GW_DEFAULT=y
|
||||
|
||||
# disable softap by default
|
||||
CONFIG_ESP_WIFI_SOFTAP_SUPPORT=n
|
||||
CONFIG_ENABLE_WIFI_STATION=y
|
||||
CONFIG_ENABLE_WIFI_AP=n
|
||||
|
||||
# Disable DS Peripheral
|
||||
CONFIG_ESP_SECURE_CERT_DS_PERIPHERAL=n
|
||||
|
||||
# Use compact attribute storage mode
|
||||
CONFIG_ESP_MATTER_NVS_USE_COMPACT_ATTR_STORAGE=y
|
||||
|
||||
# Enable HKDF in mbedtls
|
||||
CONFIG_MBEDTLS_HKDF_C=y
|
||||
|
||||
# Increase LwIP IPv6 address number to 6 (MAX_FABRIC + 1)
|
||||
# unique local addresses for fabrics(MAX_FABRIC), a link local address(1)
|
||||
CONFIG_LWIP_IPV6_NUM_ADDRESSES=6
|
||||
|
||||
# libsodium
|
||||
CONFIG_LIBSODIUM_USE_MBEDTLS_SHA=y
|
||||
|
||||
# NIMBLE
|
||||
CONFIG_BT_NIMBLE_EXT_ADV=n
|
||||
CONFIG_BT_NIMBLE_HCI_EVT_BUF_SIZE=70
|
||||
CONFIG_USE_BLE_ONLY_FOR_COMMISSIONING=y
|
||||
|
||||
# FreeRTOS should use legacy API
|
||||
CONFIG_FREERTOS_ENABLE_BACKWARD_COMPATIBILITY=y
|
||||
|
||||
# Use minimal mDNS
|
||||
CONFIG_USE_MINIMAL_MDNS=y
|
||||
CONFIG_ENABLE_EXTENDED_DISCOVERY=y
|
||||
@@ -0,0 +1,64 @@
|
||||
CONFIG_IDF_TARGET="esp32s3"
|
||||
|
||||
# Arduino Settings
|
||||
CONFIG_FREERTOS_HZ=1000
|
||||
CONFIG_AUTOSTART_ARDUINO=y
|
||||
|
||||
# Log Levels
|
||||
# Boot Messages - Log level
|
||||
CONFIG_BOOTLOADER_LOG_LEVEL_ERROR=y
|
||||
# Arduino Log Level
|
||||
CONFIG_ARDUHAL_LOG_DEFAULT_LEVEL_INFO=y
|
||||
# IDF Log Level
|
||||
CONFIG_LOG_DEFAULT_LEVEL_ERROR=y
|
||||
|
||||
# Default to 921600 baud when flashing and monitoring device
|
||||
CONFIG_ESPTOOLPY_BAUD_921600B=y
|
||||
CONFIG_ESPTOOLPY_BAUD=921600
|
||||
CONFIG_ESPTOOLPY_COMPRESSED=y
|
||||
CONFIG_ESPTOOLPY_MONITOR_BAUD_115200B=y
|
||||
CONFIG_ESPTOOLPY_MONITOR_BAUD=115200
|
||||
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
|
||||
|
||||
#enable BT
|
||||
CONFIG_BT_ENABLED=y
|
||||
CONFIG_BT_NIMBLE_ENABLED=y
|
||||
|
||||
#disable BT connection reattempt
|
||||
CONFIG_BT_NIMBLE_ENABLE_CONN_REATTEMPT=n
|
||||
|
||||
#enable lwip ipv6 autoconfig
|
||||
CONFIG_LWIP_IPV6_AUTOCONFIG=y
|
||||
|
||||
# Use a custom partition table
|
||||
CONFIG_PARTITION_TABLE_CUSTOM=y
|
||||
CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"
|
||||
CONFIG_PARTITION_TABLE_OFFSET=0xC000
|
||||
|
||||
# Disable chip shell
|
||||
CONFIG_ENABLE_CHIP_SHELL=n
|
||||
|
||||
# Enable OTA Requestor
|
||||
CONFIG_ENABLE_OTA_REQUESTOR=n
|
||||
|
||||
#enable lwIP route hooks
|
||||
CONFIG_LWIP_HOOK_IP6_ROUTE_DEFAULT=y
|
||||
CONFIG_LWIP_HOOK_ND6_GET_GW_DEFAULT=y
|
||||
|
||||
# disable softap by default
|
||||
CONFIG_ESP_WIFI_SOFTAP_SUPPORT=n
|
||||
CONFIG_ENABLE_WIFI_STATION=y
|
||||
CONFIG_ENABLE_WIFI_AP=n
|
||||
|
||||
# Disable DS Peripheral
|
||||
CONFIG_ESP_SECURE_CERT_DS_PERIPHERAL=n
|
||||
|
||||
# Use compact attribute storage mode
|
||||
CONFIG_ESP_MATTER_NVS_USE_COMPACT_ATTR_STORAGE=y
|
||||
|
||||
# Enable HKDF in mbedtls
|
||||
CONFIG_MBEDTLS_HKDF_C=y
|
||||
|
||||
# Increase LwIP IPv6 address number to 6 (MAX_FABRIC + 1)
|
||||
# unique local addresses for fabrics(MAX_FABRIC), a link local address(1)
|
||||
CONFIG_LWIP_IPV6_NUM_ADDRESSES=6
|
||||
@@ -0,0 +1,4 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(lp_core_pulse_counter)
|
||||
@@ -0,0 +1,51 @@
|
||||
| Supported Targets | ESP32-C6 |
|
||||
| ----------------- | -------- |
|
||||
|
||||
This example demonstrates how to program the ULP Core coprocessor to count pulses on an IO while the main CPUs are either running some other code or are in deep sleep. See the README.md file in the upper level 'examples' directory for more information about examples.
|
||||
|
||||
At runtime, the main code running on the ESP (found in lp_core_pulse_counter_example_main.c) loads ULP program into the `RTC_SLOW_MEM` memory region using `ulp_lp_core_load_binary` function. Main code configures the ULP program by setting up values of some variables and then starts it using `ulp_lp_core_run`. Once the ULP program is started, it monitors the IO pin for pulses.
|
||||
|
||||
When the ULP program finds an edge in the input signal, it performs debouncing and increments the variable maintaining the total edge count. Once the edge count reaches certain value, ULP triggers wake up from deep sleep. Note that the ULP program keeps running and monitoring the input signal even when the SoC is woken up.
|
||||
|
||||
### Hardware Required
|
||||
|
||||
To run this example, you should have a development board based on any of the chips listed in the supported targets table at the top and a host machine with a serial input connection.
|
||||
|
||||
#### Pin Assignment:
|
||||
|
||||
**Note:** The following pin assignments are used by default.
|
||||
|
||||
|
||||
| | Uart Tx | Pulse Count Input |
|
||||
| ----------------------- | ------- | ----------------- |
|
||||
| ESP32-C6 | GPIO5 | GPIO6 |
|
||||
| Host machine | Rx | N/A |
|
||||
|
||||
|
||||
## Example Output
|
||||
|
||||
The log output from the serial monitor connected to the main core should indicate that the LP core and the LP UART peripheral have been successfully initialized. The main CPU would then enter deep sleep mode.
|
||||
|
||||
```bash
|
||||
Using pin 6 as pulse counter input
|
||||
ULP will wake up processor after every 10 pulses
|
||||
Not a ULP wakeup, initializing it!
|
||||
Entering in deep sleep
|
||||
...
|
||||
rst:0x5 (SLEEP_WAKEUP),boot:0xc (SPI_FAST_FLASH_BOOT)
|
||||
...
|
||||
ULP woke up the main CPU!
|
||||
Pulse count: 11
|
||||
Entering in deep sleep
|
||||
```
|
||||
|
||||
The log output from the serial monitor connected to the LP core should display output as below -
|
||||
|
||||
```bash
|
||||
LP Core pulse counter started
|
||||
Pulse count: 10, wake-up main CPU
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
(For any technical queries, please open an [issue](https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you as soon as possible.)
|
||||
@@ -0,0 +1,13 @@
|
||||
; PlatformIO Project Configuration File
|
||||
;
|
||||
; Build options: build flags, source filter, extra scripting
|
||||
; Upload options: custom port, speed and extra flags
|
||||
; Library options: dependencies, extra library storages
|
||||
;
|
||||
; Please visit documentation for the other options and examples
|
||||
; http://docs.platformio.org/page/projectconf.html
|
||||
|
||||
[env:esp32-c6]
|
||||
platform = espressif32
|
||||
framework = espidf
|
||||
board = esp32-c6-devkitc-1
|
||||
@@ -0,0 +1,30 @@
|
||||
# SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
import logging
|
||||
|
||||
import pytest
|
||||
from pytest_embedded import Dut
|
||||
|
||||
|
||||
@pytest.mark.esp32c6
|
||||
@pytest.mark.esp32p4
|
||||
@pytest.mark.generic
|
||||
def test_lp_core_pcnt(dut: Dut) -> None:
|
||||
|
||||
res = dut.expect(r'ULP will wake up processor after every (\d+) pulses')
|
||||
wakeup_limit = res.group(1).decode('utf-8')
|
||||
assert (int(wakeup_limit) > 0)
|
||||
logging.info(f'Wake-up limit: {wakeup_limit} pulses')
|
||||
|
||||
dut.expect_exact('Not a ULP wakeup, initializing it!')
|
||||
dut.expect_exact('Entering in deep sleep')
|
||||
|
||||
dut.expect_exact('ULP woke up the main CPU!')
|
||||
|
||||
res = dut.expect(r'Pulse count: (\d+)')
|
||||
pulse_count = res.group(1).decode('utf-8')
|
||||
logging.info(f'Pulse count: {pulse_count}')
|
||||
|
||||
# Check that pulse count is correct, we could have gotten pulses between triggering
|
||||
# the wakeup signal and printing the count, but it should at be equal to or greater
|
||||
assert (int(pulse_count) >= int(wakeup_limit))
|
||||
@@ -0,0 +1,13 @@
|
||||
#
|
||||
# Ultra Low Power (ULP) Co-processor
|
||||
#
|
||||
CONFIG_ULP_COPROC_ENABLED=y
|
||||
CONFIG_ULP_COPROC_TYPE_LP_CORE=y
|
||||
CONFIG_ULP_COPROC_RESERVE_MEM=8128
|
||||
CONFIG_ULP_SHARED_MEM=0x10
|
||||
|
||||
# Set log level to Warning to produce clean output
|
||||
CONFIG_BOOTLOADER_LOG_LEVEL_WARN=y
|
||||
CONFIG_BOOTLOADER_LOG_LEVEL=2
|
||||
CONFIG_LOG_DEFAULT_LEVEL_WARN=y
|
||||
CONFIG_LOG_DEFAULT_LEVEL=2
|
||||
@@ -0,0 +1,23 @@
|
||||
idf_component_register(SRCS "lp_core_pulse_counter_example_main.c"
|
||||
INCLUDE_DIRS ".")
|
||||
|
||||
#
|
||||
# ULP support additions to component CMakeLists.txt.
|
||||
#
|
||||
# 1. The ULP app name must be unique (if multiple components use ULP).
|
||||
set(ulp_app_name ulp_main)
|
||||
#
|
||||
# 2. Specify all C and Assembly source files.
|
||||
# Files should be placed into a separate directory (in this case, ulp/),
|
||||
# which should not be added to COMPONENT_SRCS.
|
||||
set(ulp_sources "../ulp/main.c")
|
||||
|
||||
#
|
||||
# 3. List all the component source files which include automatically
|
||||
# generated ULP export file, ${ulp_app_name}.h:
|
||||
set(ulp_exp_dep_srcs "lp_core_pulse_counter_example_main.c")
|
||||
|
||||
#
|
||||
# 4. Call function to build ULP binary and embed in project using the argument
|
||||
# values above.
|
||||
ulp_embed_binary(${ulp_app_name} "${ulp_sources}" "${ulp_exp_dep_srcs}")
|
||||
@@ -0,0 +1,20 @@
|
||||
menu "Example Configuration"
|
||||
config EXAMPLE_PULSE_COUNT_PIN
|
||||
int "Input pin for the pulse counter"
|
||||
default 6
|
||||
help
|
||||
GPIO pin used as the input for the pulse counter
|
||||
|
||||
config EXAMPLE_PULSE_COUNT_WAKEUP_LIMIT
|
||||
int "Wake-up pulse count limit"
|
||||
default 10
|
||||
help
|
||||
Number of pulses counted after which the ULP will wake up the main CPU
|
||||
|
||||
config EXAMPLE_PULSE_COUNT_SIMULATE
|
||||
bool "Simulate pulses on input pin"
|
||||
default n
|
||||
help
|
||||
The ULP will periodically toggle the input pin to simulate pulses
|
||||
|
||||
endmenu
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
/* LP core gpio example
|
||||
|
||||
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||
|
||||
Unless required by applicable law or agreed to in writing, this
|
||||
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
#include "esp_sleep.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/rtc_io.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "ulp_lp_core.h"
|
||||
#include "ulp_main.h"
|
||||
#include "lp_core_uart.h"
|
||||
|
||||
extern const uint8_t ulp_main_bin_start[] asm("_binary_ulp_main_bin_start");
|
||||
extern const uint8_t ulp_main_bin_end[] asm("_binary_ulp_main_bin_end");
|
||||
|
||||
|
||||
static void init_ulp_program(void);
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
/* If user is using USB-serial-jtag then idf monitor needs some time to
|
||||
* re-connect to the USB port. We wait 1 sec here to allow for it to make the reconnection
|
||||
* before we print anything. Otherwise the chip will go back to sleep again before the user
|
||||
* has time to monitor any output.
|
||||
*/
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
|
||||
/* Initialize selected GPIO as RTC IO, enable input/output, disable pullup and pulldown */
|
||||
printf("Using pin %d as pulse counter input\n", CONFIG_EXAMPLE_PULSE_COUNT_PIN);
|
||||
rtc_gpio_init(CONFIG_EXAMPLE_PULSE_COUNT_PIN);
|
||||
rtc_gpio_set_direction(CONFIG_EXAMPLE_PULSE_COUNT_PIN, RTC_GPIO_MODE_INPUT_OUTPUT);
|
||||
rtc_gpio_pulldown_dis(CONFIG_EXAMPLE_PULSE_COUNT_PIN);
|
||||
rtc_gpio_pullup_dis(CONFIG_EXAMPLE_PULSE_COUNT_PIN);
|
||||
|
||||
printf("ULP will wake up processor after every %d pulses\n", CONFIG_EXAMPLE_PULSE_COUNT_WAKEUP_LIMIT);
|
||||
|
||||
esp_sleep_wakeup_cause_t cause = esp_sleep_get_wakeup_cause();
|
||||
/* not a wakeup from ULP, load the firmware */
|
||||
if (cause != ESP_SLEEP_WAKEUP_ULP) {
|
||||
printf("Not a ULP wakeup, initializing it! \n");
|
||||
init_ulp_program();
|
||||
} else {
|
||||
printf("ULP woke up the main CPU!\n");
|
||||
printf("Pulse count: %"PRIu32"\n", ulp_pulse_count);
|
||||
}
|
||||
|
||||
/* Go back to sleep, only the ULP will run */
|
||||
printf("Entering in deep sleep\n\n");
|
||||
|
||||
/* Small delay to ensure the messages are printed */
|
||||
ESP_ERROR_CHECK( esp_sleep_enable_ulp_wakeup());
|
||||
|
||||
esp_deep_sleep_start();
|
||||
}
|
||||
|
||||
static void init_ulp_program(void)
|
||||
{
|
||||
lp_core_uart_cfg_t uart_cfg = LP_CORE_UART_DEFAULT_CONFIG();
|
||||
|
||||
ESP_ERROR_CHECK(lp_core_uart_init(&uart_cfg));
|
||||
|
||||
esp_err_t err = ulp_lp_core_load_binary(ulp_main_bin_start, (ulp_main_bin_end - ulp_main_bin_start));
|
||||
ESP_ERROR_CHECK(err);
|
||||
|
||||
/* Start the program */
|
||||
ulp_lp_core_cfg_t cfg = {
|
||||
.wakeup_source = ULP_LP_CORE_WAKEUP_SOURCE_HP_CPU,
|
||||
};
|
||||
|
||||
err = ulp_lp_core_run(&cfg);
|
||||
ESP_ERROR_CHECK(err);
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "ulp_lp_core.h"
|
||||
#include "ulp_lp_core_utils.h"
|
||||
#include "ulp_lp_core_gpio.h"
|
||||
#include "ulp_lp_core_interrupts.h"
|
||||
#include "ulp_lp_core_print.h"
|
||||
#include "riscv/csr.h"
|
||||
|
||||
#define DEBOUNCE_INTERVAL_CYCLES 10 // 10 cycles is about 0.625 us at 16 MHz
|
||||
|
||||
#define SIMULATED_PULSE_FREQUENCY_HZ 2
|
||||
#define SIMULATED_PULSE_DELAY_US (1000000 / SIMULATED_PULSE_FREQUENCY_HZ) / 2
|
||||
|
||||
uint32_t pulse_count;
|
||||
static uint32_t last_trigger_time_cycles;
|
||||
|
||||
void LP_CORE_ISR_ATTR ulp_lp_core_lp_io_intr_handler(void)
|
||||
{
|
||||
ulp_lp_core_gpio_clear_intr_status();
|
||||
uint32_t trigger_time_cycles = RV_READ_CSR(mcycle);
|
||||
/* Do some simple debouncing, do not count spurious pulses */
|
||||
if (trigger_time_cycles - last_trigger_time_cycles > DEBOUNCE_INTERVAL_CYCLES) {
|
||||
pulse_count++;
|
||||
last_trigger_time_cycles = trigger_time_cycles;
|
||||
}
|
||||
|
||||
if (pulse_count % CONFIG_EXAMPLE_PULSE_COUNT_WAKEUP_LIMIT == 0) {
|
||||
lp_core_printf("Pulse count: %d, wake-up main CPU\n", pulse_count);
|
||||
ulp_lp_core_wakeup_main_processor();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
int main (void)
|
||||
{
|
||||
lp_core_printf("LP Core pulse counter started\n");
|
||||
ulp_lp_core_intr_enable();
|
||||
ulp_lp_core_gpio_intr_enable(CONFIG_EXAMPLE_PULSE_COUNT_PIN, LP_IO_INTR_POSEDGE);
|
||||
|
||||
while(1) {
|
||||
|
||||
#if CONFIG_EXAMPLE_PULSE_COUNT_SIMULATE
|
||||
/* No external device connected to generate pulses, we simulate them ourselves instead */
|
||||
ulp_lp_core_delay_us(SIMULATED_PULSE_DELAY_US);
|
||||
ulp_lp_core_gpio_set_level(CONFIG_EXAMPLE_PULSE_COUNT_PIN, 1);
|
||||
ulp_lp_core_delay_us(SIMULATED_PULSE_DELAY_US);
|
||||
ulp_lp_core_gpio_set_level(CONFIG_EXAMPLE_PULSE_COUNT_PIN, 0);
|
||||
#else
|
||||
/* Put CPU into a wait state to reduce power consumption while waiting for pulses */
|
||||
ulp_lp_core_wait_for_intr();
|
||||
#endif //CONFIG_EXAMPLE_PULSE_COUNT_SIMULATE
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user