Skip to content

Commit c606475

Browse files
authored
Merge branch 'master' into feat/mqtt5-connect-properties
2 parents b22b29d + ffb20e8 commit c606475

6 files changed

Lines changed: 62 additions & 35 deletions

File tree

.github/workflows/ci-esp-idf-next.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ jobs:
2626
- xtensa-esp32s3-espidf
2727
idf-version:
2828
- release/v6.0
29+
- release/v6.1
2930
- master
3031
steps:
3132
- name: Setup | Checkout

CHANGELOG.md

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
88
## [Unreleased]
99

1010
### Breaking
11+
- MQTT: `MqttProtocolVersion::V5` variant and [`Mqtt5ConnectionPropertyConfig`] struct exposing MQTT 5.0 CONNECT properties (session/will/message expiry intervals, receive/packet/topic-alias maxima, request-response/problem info, payload format indicator). Gated on `CONFIG_MQTT_PROTOCOL_5=y`. To negotiate MQTT 5 and set properties:
12+
```rust
13+
MqttClientConfiguration {
14+
protocol_version: Some(MqttProtocolVersion::V5),
15+
mqtt5_connection_property: Some(Mqtt5ConnectionPropertyConfig {
16+
session_expiry_interval: Some(60),
17+
..Default::default()
18+
}),
19+
..Default::default()
20+
}
21+
```
1122
- HTTP: Add `keep_alive: Option<KeepAlive>` and `so_linger: Option<Duration>` to server `Configuration`
1223
- New events need to be handled in the WiFi event loop:
1324
- `WifiEvent::StaNeighborRep` / `StaNeighborRepRef` (v5.3.0+)
@@ -27,19 +38,11 @@ remote_component = { name = "espressif/lan87xx", version = "1.*" }
2738
- WiFi: receiving any of the six new events listed above on ESP-IDF v5.3+ / v5.5+ no longer causes a panic (fixes #618)
2839
- WebSocket: `EspWebSocketClient::drop()` no longer panics when `esp_websocket_client_close` returns `ESP_FAIL` (e.g. after a network disconnection); errors are now logged instead of unwrapped
2940
- MQTT: MQTT 5.0 CONNECT properties can now be set on `EspMqttClient` without deadlocking on `MQTT_API_LOCK`; they are applied inside the library between `esp_mqtt_client_init` and `esp_mqtt_client_start` via the new [`MqttClientConfiguration::mqtt5_connection_property`] field.
41+
- BT: Fixed panic when an A2DP sink disconnects from the ESP while streaming audio.
42+
- Thread: `scan`, `energy_scan` and the IPv6 receive callbacks no longer pass the wrong context pointer to OpenThread (the closure box instead of the `ThreadDriverInner`), fixing a type-confusion crash when the callbacks fire.
43+
- Ethernet: `mod eth` is enabled again on ESP-IDF 6.0+ when SPI Ethernet PHYs are provided as managed components (`espressif/w5500`, `espressif/dm9051`, `espressif/ksz8851snl`), not only via the removed in-tree `CONFIG_ETH_SPI_ETHERNET_*` Kconfig options
3044

3145
### Added
32-
- MQTT: `MqttProtocolVersion::V5` variant and [`Mqtt5ConnectionPropertyConfig`] struct exposing MQTT 5.0 CONNECT properties (session/will/message expiry intervals, receive/packet/topic-alias maxima, request-response/problem info, payload format indicator). Gated on `CONFIG_MQTT_PROTOCOL_5=y`. To negotiate MQTT 5 and set properties:
33-
```rust
34-
MqttClientConfiguration {
35-
protocol_version: Some(MqttProtocolVersion::V5),
36-
mqtt5_connection_property: Some(Mqtt5ConnectionPropertyConfig {
37-
session_expiry_interval: Some(60),
38-
..Default::default()
39-
}),
40-
..Default::default()
41-
}
42-
```
4346
- Compatibility with ESP-IDF V6.0, and some pre-release 6.0.x.
4447
- Added support for the Generic Ethernet PHY driver: particularly useful on ESP-IDF 6.0+ as it is built-in.
4548

src/bt/a2dp.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -455,6 +455,9 @@ where
455455
}
456456

457457
unsafe extern "C" fn source_data_handler(buf: *mut u8, len: i32) -> i32 {
458+
if buf.is_null() || len <= 0 {
459+
return 0; // nothing to read; matches the "bytes provided" contract
460+
}
458461
let event = A2dpEvent::SourceData(core::slice::from_raw_parts_mut(buf, len as _));
459462
trace!("Got event {{ {:#?} }}", event);
460463

src/eth.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,11 @@ use embedded_svc::eth::*;
1414
any(
1515
esp_idf_eth_spi_ethernet_dm9051,
1616
esp_idf_eth_spi_ethernet_w5500,
17-
esp_idf_eth_spi_ethernet_ksz8851snl
17+
esp_idf_eth_spi_ethernet_ksz8851snl,
18+
// ESP-IDF 6.0+ managed components
19+
esp_idf_comp_espressif__dm9051_enabled,
20+
esp_idf_comp_espressif__w5500_enabled,
21+
esp_idf_comp_espressif__ksz8851snl_enabled,
1822
)
1923
))]
2024
use crate::hal::gpio;

src/lib.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,13 +48,18 @@ pub mod espnow;
4848
esp_idf_comp_esp_event_enabled,
4949
))]
5050
#[cfg(any(
51+
// On-chip EMAC (ESP32); RMII PHYs such as lan87xx are used only with EMAC
5152
all(esp32, esp_idf_eth_use_esp32_emac),
5253
any(
5354
esp_idf_eth_spi_ethernet_dm9051,
5455
esp_idf_eth_spi_ethernet_w5500,
55-
esp_idf_eth_spi_ethernet_ksz8851snl
56+
esp_idf_eth_spi_ethernet_ksz8851snl,
57+
// ESP-IDF 6.0+ ships SPI Ethernet PHYs as managed components
58+
esp_idf_comp_espressif__dm9051_enabled,
59+
esp_idf_comp_espressif__w5500_enabled,
60+
esp_idf_comp_espressif__ksz8851snl_enabled,
5661
),
57-
esp_idf_eth_use_openeth
62+
esp_idf_eth_use_openeth,
5863
))]
5964
pub mod eth;
6065
#[cfg(all(feature = "alloc", esp_idf_comp_esp_event_enabled))]

src/thread.rs

Lines changed: 32 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -488,22 +488,28 @@ impl<'d> ThreadDriver<'d, Host> {
488488
}
489489

490490
#[allow(clippy::type_complexity)]
491-
let mut callback: Box<Box<dyn FnMut(Option<ActiveScanResult>) + Send + 'static>> =
491+
let callback: Box<Box<dyn FnMut(Option<ActiveScanResult>) + Send + 'static>> =
492492
Box::new(Box::new(callback));
493493

494-
ot_esp!(unsafe {
494+
// Store callback where on_active_scan_result can get to it
495+
inner.scan_cb = Some(callback);
496+
497+
match ot_esp!(unsafe {
495498
otLinkActiveScan(
496499
esp_openthread_get_instance(),
497500
0xffff_ffffu32, // All channels
498501
200, // ms scan per channel
499502
Some(Self::on_active_scan_result),
500-
callback.as_mut() as *mut _ as *mut c_void,
503+
&mut *inner as *mut ThreadDriverInner as *mut c_void,
501504
)
502-
})?;
503-
504-
inner.scan_cb = Some(callback);
505-
506-
Ok(())
505+
}) {
506+
Ok(()) => Ok(()),
507+
Err(err) => {
508+
// Clean up inner if we fail to start the scan
509+
inner.scan_cb = None;
510+
Err(err)
511+
}
512+
}
507513
}
508514

509515
/// Check if an active scan is in progress
@@ -528,22 +534,28 @@ impl<'d> ThreadDriver<'d, Host> {
528534
}
529535

530536
#[allow(clippy::type_complexity)]
531-
let mut callback: Box<Box<dyn FnMut(Option<EnergyScanResult>) + Send + 'static>> =
537+
let callback: Box<Box<dyn FnMut(Option<EnergyScanResult>) + Send + 'static>> =
532538
Box::new(Box::new(callback));
533539

534-
ot_esp!(unsafe {
540+
// Store callback where on_energy_scan_result can get to it
541+
inner.energy_cb = Some(callback);
542+
543+
match ot_esp!(unsafe {
535544
otLinkEnergyScan(
536545
esp_openthread_get_instance(),
537546
0xffff_ffffu32, // All channels
538547
200, // ms scan per channel
539548
Some(Self::on_energy_scan_result),
540-
callback.as_mut() as *mut _ as *mut c_void,
549+
&mut *inner as *mut ThreadDriverInner as *mut c_void,
541550
)
542-
})?;
543-
544-
inner.energy_cb = Some(callback);
545-
546-
Ok(())
551+
}) {
552+
Ok(()) => Ok(()),
553+
Err(err) => {
554+
// Clean up inner if we fail to start the scan
555+
inner.energy_cb = None;
556+
Err(err)
557+
}
558+
}
547559
}
548560

549561
/// Check if an energy scan is in progress
@@ -632,23 +644,22 @@ impl<'d> ThreadDriver<'d, Host> {
632644
Box::new(Box::new(callback));
633645

634646
#[allow(clippy::type_complexity)]
635-
let mut callback: Box<Box<dyn FnMut(Ipv6Incoming) + Send + 'static>> =
647+
let callback: Box<Box<dyn FnMut(Ipv6Incoming) + Send + 'static>> =
636648
unsafe { core::mem::transmute(callback) };
637649

638-
let callback_ptr = callback.as_mut() as *mut _ as *mut c_void;
639-
650+
// Stick the callback where Self::on_address/Self::on_packet can get to it
640651
inner.ipv6_cb = Some(callback);
641652

642653
unsafe {
643654
otIp6SetAddressCallback(
644655
esp_openthread_get_instance(),
645656
Some(Self::on_address),
646-
callback_ptr,
657+
&mut *inner as *mut ThreadDriverInner as *mut c_void,
647658
);
648659
otIp6SetReceiveCallback(
649660
esp_openthread_get_instance(),
650661
Some(Self::on_packet),
651-
callback_ptr,
662+
&mut *inner as *mut ThreadDriverInner as *mut c_void,
652663
);
653664
otIp6SetReceiveFilterEnabled(esp_openthread_get_instance(), true);
654665

0 commit comments

Comments
 (0)