Merge branch 'master' into release/v3.3.x
This commit is contained in:
commit
3f32903125
14 changed files with 552 additions and 18 deletions
1
.github/CODEOWNERS
vendored
1
.github/CODEOWNERS
vendored
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
# CI
|
||||
/.github/ @lucasssvaz @me-no-dev @P-R-O-C-H-Y
|
||||
/.gitlab/ @lucasssvaz
|
||||
/tests/ @lucasssvaz @P-R-O-C-H-Y
|
||||
|
||||
# Tools
|
||||
|
|
|
|||
5
.github/scripts/update-version.sh
vendored
5
.github/scripts/update-version.sh
vendored
|
|
@ -45,6 +45,11 @@ cat docs/conf_common.py | \
|
|||
sed "s/.. |version| replace:: .*/.. |version| replace:: $ESP_ARDUINO_VERSION/g" | \
|
||||
sed "s/.. |idf_version| replace:: .*/.. |idf_version| replace:: $ESP_IDF_VERSION/g" > docs/__conf_common.py && mv docs/__conf_common.py docs/conf_common.py
|
||||
|
||||
echo "Updating .gitlab/workflows/common.yml..."
|
||||
cat .gitlab/workflows/common.yml | \
|
||||
sed "s/ESP_IDF_VERSION:.*/ESP_IDF_VERSION: \"$ESP_IDF_VERSION\"/g" | \
|
||||
sed "s/ESP_ARDUINO_VERSION:.*/ESP_ARDUINO_VERSION: \"$ESP_ARDUINO_VERSION\"/g" > .gitlab/workflows/__common.yml && mv .gitlab/workflows/__common.yml .gitlab/workflows/common.yml
|
||||
|
||||
echo "Updating cores/esp32/esp_arduino_version.h..."
|
||||
cat cores/esp32/esp_arduino_version.h | \
|
||||
sed "s/#define ESP_ARDUINO_VERSION_MAJOR.*/#define ESP_ARDUINO_VERSION_MAJOR $ESP_ARDUINO_VERSION_MAJOR/g" | \
|
||||
|
|
|
|||
25
.gitlab-ci.yml
Normal file
25
.gitlab-ci.yml
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
workflow:
|
||||
rules:
|
||||
# Disable those non-protected push triggered pipelines
|
||||
- if: '$CI_COMMIT_REF_NAME != "master" && $CI_COMMIT_BRANCH !~ /^release\/v/ && $CI_COMMIT_TAG !~ /^\d+\.\d+(\.\d+)?($|-)/ && $CI_PIPELINE_SOURCE == "push"'
|
||||
when: never
|
||||
# when running merged result pipelines, CI_COMMIT_SHA represents the temp commit it created.
|
||||
# Please use PIPELINE_COMMIT_SHA at all places that require a commit sha of the original commit.
|
||||
- if: $CI_OPEN_MERGE_REQUESTS != null
|
||||
variables:
|
||||
PIPELINE_COMMIT_SHA: $CI_MERGE_REQUEST_SOURCE_BRANCH_SHA
|
||||
IS_MR_PIPELINE: 1
|
||||
- if: $CI_OPEN_MERGE_REQUESTS == null
|
||||
variables:
|
||||
PIPELINE_COMMIT_SHA: $CI_COMMIT_SHA
|
||||
IS_MR_PIPELINE: 0
|
||||
- if: '$CI_PIPELINE_SOURCE == "schedule"'
|
||||
variables:
|
||||
IS_SCHEDULED_RUN: "true"
|
||||
- when: always
|
||||
|
||||
# Place the default settings in `.gitlab/workflows/common.yml` instead
|
||||
|
||||
include:
|
||||
- ".gitlab/workflows/common.yml"
|
||||
- ".gitlab/workflows/sample.yml"
|
||||
26
.gitlab/workflows/common.yml
Normal file
26
.gitlab/workflows/common.yml
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
#####################
|
||||
# Default Variables #
|
||||
#####################
|
||||
|
||||
stages:
|
||||
- pre_check
|
||||
- build
|
||||
- test
|
||||
- result
|
||||
|
||||
variables:
|
||||
ESP_IDF_VERSION: "5.4"
|
||||
ESP_ARDUINO_VERSION: "3.2.1"
|
||||
|
||||
#############
|
||||
# `default` #
|
||||
#############
|
||||
|
||||
default:
|
||||
retry:
|
||||
max: 2
|
||||
when:
|
||||
# In case of a runner failure we could hop to another one, or a network error could go away.
|
||||
- runner_system_failure
|
||||
# Job execution timeout may be caused by a network issue.
|
||||
- job_execution_timeout
|
||||
6
.gitlab/workflows/sample.yml
Normal file
6
.gitlab/workflows/sample.yml
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
hello-world:
|
||||
stage: test
|
||||
script:
|
||||
- echo "Hello, World from GitLab CI!"
|
||||
rules:
|
||||
- if: $CI_PIPELINE_SOURCE == "push"
|
||||
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
#include <inttypes.h>
|
||||
#include "Stream.h"
|
||||
#include <functional>
|
||||
|
||||
class HardwareI2C : public Stream {
|
||||
public:
|
||||
|
|
@ -36,6 +37,7 @@ public:
|
|||
virtual size_t requestFrom(uint8_t address, size_t len, bool stopBit) = 0;
|
||||
virtual size_t requestFrom(uint8_t address, size_t len) = 0;
|
||||
|
||||
virtual void onReceive(void (*)(int)) = 0;
|
||||
virtual void onRequest(void (*)(void)) = 0;
|
||||
// Update base class to use std::function
|
||||
virtual void onReceive(const std::function<void(int)> &) = 0;
|
||||
virtual void onRequest(const std::function<void()> &) = 0;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -347,20 +347,147 @@ This function will return ``true`` if the peripheral was initialized correctly.
|
|||
onReceive
|
||||
^^^^^^^^^
|
||||
|
||||
The ``onReceive`` function is used to define the callback for the data received from the master.
|
||||
The ``onReceive`` function is used to define the callback for data received from the master device.
|
||||
|
||||
.. code-block:: arduino
|
||||
|
||||
void onReceive( void (*)(int) );
|
||||
void onReceive(const std::function<void(int)>& callback);
|
||||
|
||||
**Function Signature:**
|
||||
|
||||
The callback function must have the signature ``void(int numBytes)`` where ``numBytes`` indicates how many bytes were received from the master.
|
||||
|
||||
**Usage Examples:**
|
||||
|
||||
.. code-block:: arduino
|
||||
|
||||
// Method 1: Regular function
|
||||
void handleReceive(int numBytes) {
|
||||
Serial.printf("Received %d bytes: ", numBytes);
|
||||
while (Wire.available()) {
|
||||
char c = Wire.read();
|
||||
Serial.print(c);
|
||||
}
|
||||
Serial.println();
|
||||
}
|
||||
Wire.onReceive(handleReceive);
|
||||
|
||||
// Method 2: Lambda function
|
||||
Wire.onReceive([](int numBytes) {
|
||||
Serial.printf("Master sent %d bytes\n", numBytes);
|
||||
while (Wire.available()) {
|
||||
uint8_t data = Wire.read();
|
||||
// Process received data
|
||||
Serial.printf("Data: 0x%02X\n", data);
|
||||
}
|
||||
});
|
||||
|
||||
// Method 3: Lambda with capture (for accessing variables)
|
||||
int deviceId = 42;
|
||||
Wire.onReceive([deviceId](int numBytes) {
|
||||
Serial.printf("Device %d received %d bytes\n", deviceId, numBytes);
|
||||
// Process data...
|
||||
});
|
||||
|
||||
// Method 4: Using std::function variable
|
||||
std::function<void(int)> receiveHandler = [](int bytes) {
|
||||
Serial.printf("Handling %d received bytes\n", bytes);
|
||||
};
|
||||
Wire.onReceive(receiveHandler);
|
||||
|
||||
// Method 5: Class member function (using lambda wrapper)
|
||||
class I2CDevice {
|
||||
private:
|
||||
int deviceAddress;
|
||||
public:
|
||||
I2CDevice(int addr) : deviceAddress(addr) {}
|
||||
|
||||
void handleReceive(int numBytes) {
|
||||
Serial.printf("Device 0x%02X received %d bytes\n", deviceAddress, numBytes);
|
||||
}
|
||||
|
||||
void setup() {
|
||||
Wire.onReceive([this](int bytes) {
|
||||
this->handleReceive(bytes);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
.. note::
|
||||
The ``onReceive`` callback is triggered when the I2C master sends data to this slave device.
|
||||
Use ``Wire.available()`` and ``Wire.read()`` inside the callback to retrieve the received data.
|
||||
|
||||
onRequest
|
||||
^^^^^^^^^
|
||||
|
||||
The ``onRequest`` function is used to define the callback for the data to be send to the master.
|
||||
The ``onRequest`` function is used to define the callback for responding to master read requests.
|
||||
|
||||
.. code-block:: arduino
|
||||
|
||||
void onRequest( void (*)(void) );
|
||||
void onRequest(const std::function<void()>& callback);
|
||||
|
||||
**Function Signature:**
|
||||
|
||||
The callback function must have the signature ``void()`` with no parameters. This callback is triggered when the master requests data from this slave device.
|
||||
|
||||
**Usage Examples:**
|
||||
|
||||
.. code-block:: arduino
|
||||
|
||||
// Method 1: Regular function
|
||||
void handleRequest() {
|
||||
static int counter = 0;
|
||||
Wire.printf("Response #%d", counter++);
|
||||
}
|
||||
Wire.onRequest(handleRequest);
|
||||
|
||||
// Method 2: Lambda function
|
||||
Wire.onRequest([]() {
|
||||
// Send sensor data to master
|
||||
int sensorValue = analogRead(A0);
|
||||
Wire.write(sensorValue >> 8); // High byte
|
||||
Wire.write(sensorValue & 0xFF); // Low byte
|
||||
});
|
||||
|
||||
// Method 3: Lambda with capture (for accessing variables)
|
||||
int deviceStatus = 1;
|
||||
String deviceName = "Sensor1";
|
||||
Wire.onRequest([&deviceStatus, &deviceName]() {
|
||||
Wire.write(deviceStatus);
|
||||
Wire.write(deviceName.c_str(), deviceName.length());
|
||||
});
|
||||
|
||||
// Method 4: Using std::function variable
|
||||
std::function<void()> requestHandler = []() {
|
||||
Wire.write("Hello Master!");
|
||||
};
|
||||
Wire.onRequest(requestHandler);
|
||||
|
||||
// Method 5: Class member function (using lambda wrapper)
|
||||
class TemperatureSensor {
|
||||
private:
|
||||
float temperature;
|
||||
public:
|
||||
void updateTemperature() {
|
||||
temperature = 25.5; // Read from actual sensor
|
||||
}
|
||||
|
||||
void sendTemperature() {
|
||||
// Convert float to bytes and send
|
||||
uint8_t* tempBytes = (uint8_t*)&temperature;
|
||||
Wire.write(tempBytes, sizeof(float));
|
||||
}
|
||||
|
||||
void setup() {
|
||||
Wire.onRequest([this]() {
|
||||
this->sendTemperature();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
.. note::
|
||||
The ``onRequest`` callback is triggered when the I2C master requests data from this slave device.
|
||||
Use ``Wire.write()`` inside the callback to send response data back to the master.
|
||||
|
||||
slaveWrite
|
||||
^^^^^^^^^^
|
||||
|
|
|
|||
|
|
@ -0,0 +1,157 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
ESP32 Lambda FunctionalInterrupt Example
|
||||
========================================
|
||||
|
||||
This example demonstrates how to use lambda functions with FunctionalInterrupt
|
||||
for GPIO pin interrupt callbacks on ESP32. It shows CHANGE mode detection
|
||||
with LED toggle functionality and proper debouncing.
|
||||
|
||||
Hardware Setup:
|
||||
- Use BOOT Button or connect a button between BUTTON_PIN and GND (with internal pullup)
|
||||
- Use Builtin Board LED or connect an LED with resistor to GPIO 2 (LED_PIN)
|
||||
|
||||
Features Demonstrated:
|
||||
1. CHANGE mode lambda to detect both RISING and FALLING edges
|
||||
2. LED toggle on button press (FALLING edge)
|
||||
3. Edge type detection using digitalRead() within ISR
|
||||
4. Hardware debouncing with configurable timeout
|
||||
|
||||
IMPORTANT NOTE ABOUT ESP32 INTERRUPT BEHAVIOR:
|
||||
- Only ONE interrupt handler can be attached per GPIO pin at a time
|
||||
- Calling attachInterrupt() on a pin that already has an interrupt will override the previous one
|
||||
- This applies regardless of edge type (RISING, FALLING, CHANGE)
|
||||
- If you need both RISING and FALLING detection on the same pin, use CHANGE mode
|
||||
and determine the edge type within your handler by reading the pin state
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <FunctionalInterrupt.h>
|
||||
|
||||
// Pin definitions
|
||||
#define BUTTON_PIN BOOT_PIN // BOOT BUTTON - change as needed
|
||||
#ifdef LED_BUILTIN
|
||||
#define LED_PIN LED_BUILTIN
|
||||
#else
|
||||
#warning Using LED_PIN = GPIO 2 as default - change as needed
|
||||
#define LED_PIN 2 // change as needed
|
||||
#endif
|
||||
|
||||
// Global variables for interrupt handling (volatile for ISR safety)
|
||||
volatile uint32_t buttonPressCount = 0;
|
||||
volatile uint32_t buttonReleaseCount = 0;
|
||||
volatile bool buttonPressed = false;
|
||||
volatile bool buttonReleased = false;
|
||||
volatile bool ledState = false;
|
||||
volatile bool ledStateChanged = false; // Flag to indicate LED needs updating
|
||||
|
||||
// Debouncing variables (volatile for ISR safety)
|
||||
volatile unsigned long lastButtonInterruptTime = 0;
|
||||
const unsigned long DEBOUNCE_DELAY_MS = 50; // 50ms debounce delay
|
||||
|
||||
// State-based debouncing to prevent hysteresis issues
|
||||
volatile bool lastButtonState = HIGH; // Track last stable state (HIGH = released)
|
||||
|
||||
// Global lambda function (declared at file scope) - ISR in IRAM
|
||||
IRAM_ATTR std::function<void()> changeModeLambda = []() {
|
||||
// Simple debouncing: check if enough time has passed since last interrupt
|
||||
unsigned long currentTime = millis();
|
||||
if (currentTime - lastButtonInterruptTime < DEBOUNCE_DELAY_MS) {
|
||||
return; // Ignore this interrupt due to bouncing
|
||||
}
|
||||
|
||||
// Read current pin state to determine edge type
|
||||
bool currentState = digitalRead(BUTTON_PIN);
|
||||
|
||||
// State-based debouncing: only process if state actually changed
|
||||
if (currentState == lastButtonState) {
|
||||
return; // No real state change, ignore (hysteresis/noise)
|
||||
}
|
||||
|
||||
// Update timing and state
|
||||
lastButtonInterruptTime = currentTime;
|
||||
lastButtonState = currentState;
|
||||
|
||||
if (currentState == LOW) {
|
||||
// FALLING edge detected (button pressed) - set flag for main loop
|
||||
// volatile variables require use of temporary value transfer
|
||||
uint32_t temp = buttonPressCount + 1;
|
||||
buttonPressCount = temp;
|
||||
buttonPressed = true;
|
||||
ledStateChanged = true; // Signal main loop to toggle LED
|
||||
} else {
|
||||
// RISING edge detected (button released) - set flag for main loop
|
||||
// volatile variables require use of temporary value transfer
|
||||
uint32_t temp = buttonReleaseCount + 1;
|
||||
buttonReleaseCount = temp;
|
||||
buttonReleased = true;
|
||||
}
|
||||
};
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
delay(1000); // Allow serial monitor to connect
|
||||
|
||||
Serial.println("ESP32 Lambda FunctionalInterrupt Example");
|
||||
Serial.println("========================================");
|
||||
|
||||
// Configure pins
|
||||
pinMode(BUTTON_PIN, INPUT_PULLUP);
|
||||
pinMode(LED_PIN, OUTPUT);
|
||||
digitalWrite(LED_PIN, LOW);
|
||||
|
||||
// CHANGE mode lambda to handle both RISING and FALLING edges
|
||||
// This toggles the LED on button press (FALLING edge)
|
||||
Serial.println("Setting up CHANGE mode lambda for LED toggle");
|
||||
|
||||
// Use the global lambda function
|
||||
attachInterrupt(BUTTON_PIN, changeModeLambda, CHANGE);
|
||||
|
||||
Serial.println();
|
||||
Serial.printf("Lambda interrupt configured on Pin %d (CHANGE mode)\r\n", BUTTON_PIN);
|
||||
Serial.printf("Debounce delay: %lu ms\r\n", DEBOUNCE_DELAY_MS);
|
||||
Serial.println();
|
||||
Serial.println("Press the button to toggle the LED!");
|
||||
Serial.println("Button press (FALLING edge) will toggle the LED.");
|
||||
Serial.println("Button release (RISING edge) will be detected and reported.");
|
||||
Serial.println("Button includes debouncing to prevent mechanical bounce issues.");
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// Handle LED state changes (ISR-safe approach)
|
||||
if (ledStateChanged) {
|
||||
ledStateChanged = false;
|
||||
ledState = !ledState; // Toggle LED state in main loop
|
||||
digitalWrite(LED_PIN, ledState);
|
||||
}
|
||||
|
||||
// Check for button presses
|
||||
if (buttonPressed) {
|
||||
buttonPressed = false;
|
||||
Serial.printf("==> Button PRESSED! Count: %lu, LED: %s (FALLING edge)\r\n", buttonPressCount, ledState ? "ON" : "OFF");
|
||||
}
|
||||
|
||||
// Check for button releases
|
||||
if (buttonReleased) {
|
||||
buttonReleased = false;
|
||||
Serial.printf("==> Button RELEASED! Count: %lu (RISING edge)\r\n", buttonReleaseCount);
|
||||
}
|
||||
|
||||
delay(10);
|
||||
}
|
||||
|
|
@ -0,0 +1,147 @@
|
|||
# ESP32 Lambda FunctionalInterrupt Example
|
||||
|
||||
This example demonstrates how to use lambda functions with FunctionalInterrupt for GPIO pin interrupt callbacks on ESP32. It shows CHANGE mode detection with LED toggle functionality and proper debouncing.
|
||||
|
||||
## Features Demonstrated
|
||||
|
||||
1. **CHANGE mode lambda** to detect both RISING and FALLING edges
|
||||
2. **LED toggle on button press** (FALLING edge)
|
||||
3. **Edge type detection** using digitalRead() within ISR
|
||||
4. **Hardware debouncing** with configurable timeout
|
||||
5. **IRAM_ATTR lambda declaration** for optimal ISR performance in RAM
|
||||
|
||||
## Hardware Setup
|
||||
|
||||
- Use BOOT Button or connect a button between BUTTON_PIN and GND (with internal pullup)
|
||||
- Use Builtin Board LED (no special hardware setup) or connect an LED with resistor to GPIO assigned as LED_PIN.\
|
||||
Some boards have an RGB LED that needs no special hardware setup to work as a simple white on/off LED.
|
||||
|
||||
```
|
||||
ESP32 Board Button/LED
|
||||
----------- ---------
|
||||
BOOT_PIN ------------ [BUTTON] ---- GND
|
||||
LED_PIN --------------- [LED] ----- GND
|
||||
¦
|
||||
[330O] (*) Only needed when using an external LED attached to the GPIO.
|
||||
¦
|
||||
3V3
|
||||
```
|
||||
|
||||
## Important ESP32 Interrupt Behavior
|
||||
|
||||
**CRITICAL:** Only ONE interrupt handler can be attached per GPIO pin at a time on ESP32.
|
||||
|
||||
- Calling `attachInterrupt()` on a pin that already has an interrupt will **override** the previous one
|
||||
- This applies regardless of edge type (RISING, FALLING, CHANGE)
|
||||
- If you need both RISING and FALLING detection on the same pin, use **CHANGE mode** and determine the edge type within your handler by reading the pin state
|
||||
|
||||
## Code Overview
|
||||
|
||||
This example demonstrates a simple CHANGE mode lambda interrupt that:
|
||||
|
||||
- **Detects both button press and release** using a single interrupt handler
|
||||
- **Toggles LED only on button press** (FALLING edge)
|
||||
- **Reports both press and release events** to Serial output
|
||||
- **Uses proper debouncing** to prevent switch bounce issues
|
||||
- **Implements minimal lambda captures** for simplicity
|
||||
|
||||
## Lambda Function Pattern
|
||||
|
||||
### CHANGE Mode Lambda with IRAM Declaration
|
||||
```cpp
|
||||
// Global lambda declared with IRAM_ATTR for optimal ISR performance
|
||||
IRAM_ATTR std::function<void()> changeModeLambda = []() {
|
||||
// Debouncing check
|
||||
unsigned long currentTime = millis();
|
||||
if (currentTime - lastButtonInterruptTime < DEBOUNCE_DELAY_MS) {
|
||||
return; // Ignore bouncing
|
||||
}
|
||||
|
||||
// Determine edge type
|
||||
bool currentState = digitalRead(BUTTON_PIN);
|
||||
if (currentState == lastButtonState) {
|
||||
return; // No real state change
|
||||
}
|
||||
|
||||
// Update state and handle edges
|
||||
lastButtonInterruptTime = currentTime;
|
||||
lastButtonState = currentState;
|
||||
|
||||
if (currentState == LOW) {
|
||||
// Button pressed (FALLING edge)
|
||||
buttonPressCount++;
|
||||
buttonPressed = true;
|
||||
ledStateChanged = true; // Signal LED toggle
|
||||
} else {
|
||||
// Button released (RISING edge)
|
||||
buttonReleaseCount++;
|
||||
buttonReleased = true;
|
||||
}
|
||||
};
|
||||
|
||||
attachInterrupt(BUTTON_PIN, changeModeLambda, CHANGE);
|
||||
```
|
||||
|
||||
## Key Concepts
|
||||
|
||||
### Edge Detection in CHANGE Mode
|
||||
```cpp
|
||||
if (digitalRead(pin) == LOW) {
|
||||
// FALLING edge detected (button pressed)
|
||||
} else {
|
||||
// RISING edge detected (button released)
|
||||
}
|
||||
```
|
||||
|
||||
### Debouncing Strategy
|
||||
This example implements dual-layer debouncing:
|
||||
1. **Time-based**: Ignores interrupts within 50 ms of previous one
|
||||
2. **State-based**: Only processes actual state changes
|
||||
|
||||
### Main Loop Processing
|
||||
```cpp
|
||||
void loop() {
|
||||
// Handle LED changes safely outside ISR
|
||||
if (ledStateChanged) {
|
||||
ledStateChanged = false;
|
||||
ledState = !ledState;
|
||||
digitalWrite(LED_PIN, ledState);
|
||||
}
|
||||
|
||||
// Report button events
|
||||
if (buttonPressed) {
|
||||
// Handle press event
|
||||
}
|
||||
if (buttonReleased) {
|
||||
// Handle release event
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Expected Output
|
||||
|
||||
```
|
||||
ESP32 Lambda FunctionalInterrupt Example
|
||||
========================================
|
||||
Setting up CHANGE mode lambda for LED toggle
|
||||
|
||||
Lambda interrupt configured on Pin 0 (CHANGE mode)
|
||||
Debounce delay: 50 ms
|
||||
|
||||
Press the button to toggle the LED!
|
||||
Button press (FALLING edge) will toggle the LED.
|
||||
Button release (RISING edge) will be detected and reported.
|
||||
Button includes debouncing to prevent mechanical bounce issues.
|
||||
|
||||
==> Button PRESSED! Count: 1, LED: ON (FALLING edge)
|
||||
==> Button RELEASED! Count: 1 (RISING edge)
|
||||
==> Button PRESSED! Count: 2, LED: OFF (FALLING edge)
|
||||
==> Button RELEASED! Count: 2 (RISING edge)
|
||||
```
|
||||
|
||||
## Pin Configuration
|
||||
|
||||
The example uses these default pins:
|
||||
|
||||
- `BUTTON_PIN`: BOOT_PIN (automatically assigned by the Arduino Core)
|
||||
- `LED_PIN`: LED_BUILTIN (may not be available for your board - please verify it)
|
||||
|
|
@ -13,7 +13,7 @@
|
|||
// limitations under the License.
|
||||
|
||||
/*
|
||||
This example create 6 on-off light endpoint that share the same onChangeOnOff() callback code.
|
||||
This example creates 6 on-off light endpoints that share the same onChangeOnOff() callback code.
|
||||
It uses Lambda Function with an extra Lambda Capture information that links the Endpoint to its individual information.
|
||||
After the Matter example is commissioned, the expected Serial output shall be similar to this:
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,37 @@
|
|||
// This example demonstrates the use of functional callbacks with the Wire library
|
||||
// for I2C slave communication. It shows how to handle requests and data reception
|
||||
|
||||
#include "Wire.h"
|
||||
|
||||
#define I2C_DEV_ADDR 0x55
|
||||
|
||||
uint32_t i = 0;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
Serial.setDebugOutput(true);
|
||||
|
||||
Wire.onRequest([]() {
|
||||
Wire.print(i++);
|
||||
Wire.print(" Packets.");
|
||||
Serial.println("onRequest");
|
||||
});
|
||||
|
||||
Wire.onReceive([](int len) {
|
||||
Serial.printf("onReceive[%d]: ", len);
|
||||
while (Wire.available()) {
|
||||
Serial.write(Wire.read());
|
||||
}
|
||||
Serial.println();
|
||||
});
|
||||
|
||||
Wire.begin((uint8_t)I2C_DEV_ADDR);
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
char message[64];
|
||||
snprintf(message, 64, "%lu Packets.", i++);
|
||||
Wire.slaveWrite((uint8_t *)message, strlen(message));
|
||||
#endif
|
||||
}
|
||||
|
||||
void loop() {}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"requires": [
|
||||
"CONFIG_SOC_I2C_SUPPORT_SLAVE=y"
|
||||
]
|
||||
}
|
||||
|
|
@ -48,7 +48,7 @@ TwoWire::TwoWire(uint8_t bus_num)
|
|||
#endif
|
||||
#if SOC_I2C_SUPPORT_SLAVE
|
||||
,
|
||||
is_slave(false), user_onRequest(NULL), user_onReceive(NULL)
|
||||
is_slave(false), user_onRequest(nullptr), user_onReceive(nullptr)
|
||||
#endif /* SOC_I2C_SUPPORT_SLAVE */
|
||||
{
|
||||
}
|
||||
|
|
@ -596,14 +596,14 @@ void TwoWire::flush() {
|
|||
//i2cFlush(num); // cleanup
|
||||
}
|
||||
|
||||
void TwoWire::onReceive(void (*function)(int)) {
|
||||
void TwoWire::onReceive(const std::function<void(int)> &function) {
|
||||
#if SOC_I2C_SUPPORT_SLAVE
|
||||
user_onReceive = function;
|
||||
#endif
|
||||
}
|
||||
|
||||
// sets function called on slave read
|
||||
void TwoWire::onRequest(void (*function)(void)) {
|
||||
void TwoWire::onRequest(const std::function<void()> &function) {
|
||||
#if SOC_I2C_SUPPORT_SLAVE
|
||||
user_onRequest = function;
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -48,10 +48,6 @@
|
|||
#ifndef I2C_BUFFER_LENGTH
|
||||
#define I2C_BUFFER_LENGTH 128 // Default size, if none is set using Wire::setBuffersize(size_t)
|
||||
#endif
|
||||
#if SOC_I2C_SUPPORT_SLAVE
|
||||
typedef void (*user_onRequest)(void);
|
||||
typedef void (*user_onReceive)(uint8_t *, int);
|
||||
#endif /* SOC_I2C_SUPPORT_SLAVE */
|
||||
|
||||
class TwoWire : public HardwareI2C {
|
||||
protected:
|
||||
|
|
@ -77,8 +73,8 @@ protected:
|
|||
private:
|
||||
#if SOC_I2C_SUPPORT_SLAVE
|
||||
bool is_slave;
|
||||
void (*user_onRequest)(void);
|
||||
void (*user_onReceive)(int);
|
||||
std::function<void()> user_onRequest;
|
||||
std::function<void(int)> user_onReceive;
|
||||
static void onRequestService(uint8_t, void *);
|
||||
static void onReceiveService(uint8_t, uint8_t *, size_t, bool, void *);
|
||||
#endif /* SOC_I2C_SUPPORT_SLAVE */
|
||||
|
|
@ -116,8 +112,8 @@ public:
|
|||
size_t requestFrom(uint8_t address, size_t len, bool stopBit) override;
|
||||
size_t requestFrom(uint8_t address, size_t len) override;
|
||||
|
||||
void onReceive(void (*)(int)) override;
|
||||
void onRequest(void (*)(void)) override;
|
||||
void onReceive(const std::function<void(int)> &) override;
|
||||
void onRequest(const std::function<void()> &) override;
|
||||
|
||||
//call setPins() first, so that begin() can be called without arguments from libraries
|
||||
bool setPins(int sda, int scl);
|
||||
|
|
|
|||
Loading…
Reference in a new issue