mirror of
https://github.com/rstrouse/ESPSomfy-RTS.git
synced 2026-10-31 13:52:15 +01:00
Merge pull request #121 from cjkas/feat/esp32p4-build
build: add the ESP32-P4 (#29)
This commit is contained in:
commit
bb7438d37d
19 changed files with 318 additions and 40 deletions
2
.github/ISSUE_TEMPLATE/BUG-REPORT.yaml
vendored
2
.github/ISSUE_TEMPLATE/BUG-REPORT.yaml
vendored
|
|
@ -72,7 +72,7 @@ body:
|
||||||
> After a crash, include the whole panic: the `Guru Meditation Error` line, the `Backtrace:` line and the `ELF file SHA256:` line.
|
> After a crash, include the whole panic: the `Guru Meditation Error` line, the `Backtrace:` line and the `ELF file SHA256:` line.
|
||||||
> Each release has a `SomfyController.ino.<chip>.elf.zip` that decodes the backtrace:
|
> Each release has a `SomfyController.ino.<chip>.elf.zip` that decodes the backtrace:
|
||||||
> `xtensa-esp32s3-elf-addr2line -pfiaC -e SomfyController.ino.esp32s3.elf <backtrace addresses>`
|
> `xtensa-esp32s3-elf-addr2line -pfiaC -e SomfyController.ino.esp32s3.elf <backtrace addresses>`
|
||||||
> (`riscv32-esp-elf-addr2line` on the C3, C5 and C6).
|
> (`riscv32-esp-elf-addr2line` on the C3, C5, C6 and P4).
|
||||||
render: bash
|
render: bash
|
||||||
validations:
|
validations:
|
||||||
required: false
|
required: false
|
||||||
20
.github/workflows/build.yaml
vendored
20
.github/workflows/build.yaml
vendored
|
|
@ -61,7 +61,7 @@ jobs:
|
||||||
# elfname: the symbols of that binary, to decode a crash's backtrace
|
# elfname: the symbols of that binary, to decode a crash's backtrace
|
||||||
# obname: onboard image (bootloader + partitions + firmware + littlefs merged)
|
# obname: onboard image (bootloader + partitions + firmware + littlefs merged)
|
||||||
# for flashing a new chip via USB/serial
|
# for flashing a new chip via USB/serial
|
||||||
# addr_bootloader: chip-dependent (ESP32: 0x1000, S3/C3/C6: 0x0, C5: 0x2000)
|
# addr_bootloader: chip-dependent (ESP32: 0x1000, S3/C3/C6: 0x0, C5/P4: 0x2000)
|
||||||
# addr_fs: must match the spiffs offset in the env's partition table
|
# addr_fs: must match the spiffs offset in the env's partition table
|
||||||
# (0x310000 in both esp32_3MB.csv and esp32_huge_app.csv)
|
# (0x310000 in both esp32_3MB.csv and esp32_huge_app.csv)
|
||||||
include:
|
include:
|
||||||
|
|
@ -110,6 +110,24 @@ jobs:
|
||||||
elfname: SomfyController.ino.esp32c6.elf
|
elfname: SomfyController.ino.esp32c6.elf
|
||||||
fsname: SomfyController.littlefs.esp32c6.bin
|
fsname: SomfyController.littlefs.esp32c6.bin
|
||||||
obname: SomfyController.onboard.esp32c6.bin
|
obname: SomfyController.onboard.esp32c6.bin
|
||||||
|
- env: esp32p4
|
||||||
|
name: ESP32-P4
|
||||||
|
chip: ESP32-P4
|
||||||
|
addr_bootloader: "0x2000"
|
||||||
|
addr_fs: "0x310000"
|
||||||
|
fwname: SomfyController.ino.esp32p4.bin
|
||||||
|
elfname: SomfyController.ino.esp32p4.elf
|
||||||
|
fsname: SomfyController.littlefs.esp32p4.bin
|
||||||
|
obname: SomfyController.onboard.esp32p4.bin
|
||||||
|
- env: esp32p4es
|
||||||
|
name: ESP32-P4 (before v2.0)
|
||||||
|
chip: ESP32-P4
|
||||||
|
addr_bootloader: "0x2000"
|
||||||
|
addr_fs: "0x310000"
|
||||||
|
fwname: SomfyController.ino.esp32p4es.bin
|
||||||
|
elfname: SomfyController.ino.esp32p4es.elf
|
||||||
|
fsname: SomfyController.littlefs.esp32p4es.bin
|
||||||
|
obname: SomfyController.onboard.esp32p4es.bin
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Get Release
|
- name: Get Release
|
||||||
|
|
|
||||||
|
|
@ -1578,23 +1578,22 @@ class Wifi {
|
||||||
{ val: 4, label: 'T-Internet POE - LILYGO', clk: 3, ct: 0, addr: 0, pwr: 16, mdc: 23, mdio: 18 },
|
{ val: 4, label: 'T-Internet POE - LILYGO', clk: 3, ct: 0, addr: 0, pwr: 16, mdc: 23, mdio: 18 },
|
||||||
{ val: 5, label: 'wESP32 v7+ - Silicognition', clk: 0, ct: 2, addr: 0, pwr: -1, mdc: 16, mdio: 17 },
|
{ val: 5, label: 'wESP32 v7+ - Silicognition', clk: 0, ct: 2, addr: 0, pwr: -1, mdc: 16, mdio: 17 },
|
||||||
{ val: 6, label: 'wESP32 < v7 - Silicognition', clk: 0, ct: 0, addr: 0, pwr: -1, mdc: 16, mdio: 17 },
|
{ val: 6, label: 'wESP32 < v7 - Silicognition', clk: 0, ct: 0, addr: 0, pwr: -1, mdc: 16, mdio: 17 },
|
||||||
{ val: 1, label: 'WT32-ETH01 - Wireless Tag', clk: 0, ct: 0, addr: 1, pwr: 16, mdc: 23, mdio: 18 }
|
{ val: 1, label: 'WT32-ETH01 - Wireless Tag', clk: 0, ct: 0, addr: 1, pwr: 16, mdc: 23, mdio: 18 },
|
||||||
|
{ val: 8, label: 'ESP32-P4-WIFI6-POE-ETH - Waveshare', clk: 0, ct: 1, addr: 1, pwr: 51, mdc: 31, mdio: 52, p4: true }
|
||||||
];
|
];
|
||||||
ethClockModes = [{ val: 0, label: 'GPIO0 IN' }, { val: 1, label: 'GPIO0 OUT' }, { val: 2, label: 'GPIO16 OUT' }, { val: 3, label: 'GPIO17 OUT' }];
|
ethClockModes = [{ val: 0, label: 'GPIO0 IN' }, { val: 1, label: 'GPIO0 OUT' }, { val: 2, label: 'GPIO16 OUT' }, { val: 3, label: 'GPIO17 OUT' }];
|
||||||
|
// The P4 takes the clock in on GPIO 50 only (eth_clock_id_t in EthPhy.h).
|
||||||
|
ethClockModesP4 = [{ val: 0, label: 'GPIO50 IN' }];
|
||||||
// The ids the firmware stores (eth_phy_id_t in EthPhy.h). 4 is the DM9051, an SPI chip the ESP32's MAC can't drive.
|
// The ids the firmware stores (eth_phy_id_t in EthPhy.h). 4 is the DM9051, an SPI chip the ESP32's MAC can't drive.
|
||||||
ethPhyTypes = [{ val: 0, label: 'LAN8720' }, { val: 1, label: 'TLK110' }, { val: 2, label: 'RTL8201' }, { val: 3, label: 'DP83848' }, { val: 5, label: 'KSZ8041' }, { val: 6, label: 'KSZ8081' }];
|
ethPhyTypes = [{ val: 0, label: 'LAN8720' }, { val: 1, label: 'TLK110' }, { val: 2, label: 'RTL8201' }, { val: 3, label: 'DP83848' }, { val: 5, label: 'KSZ8041' }, { val: 6, label: 'KSZ8081' }];
|
||||||
init() {
|
init() {
|
||||||
document.getElementById("divNetworkStrength").innerHTML = this.displaySignal(-100);
|
document.getElementById("divNetworkStrength").innerHTML = this.displaySignal(-100);
|
||||||
if (this.initialized) return;
|
if (this.initialized) return;
|
||||||
let addr = [];
|
let addr = [];
|
||||||
this.loadETHDropdown(document.getElementById('selETHClkMode'), this.ethClockModes);
|
|
||||||
this.loadETHDropdown(document.getElementById('selETHPhyType'), this.ethPhyTypes);
|
this.loadETHDropdown(document.getElementById('selETHPhyType'), this.ethPhyTypes);
|
||||||
this.loadETHDropdown(document.getElementById('selETHBoardType'), this.ethBoardTypes);
|
|
||||||
for (let i = 0; i < 32; i++) addr.push({ val: i, label: `PHY ${i}` });
|
for (let i = 0; i < 32; i++) addr.push({ val: i, label: `PHY ${i}` });
|
||||||
this.loadETHDropdown(document.getElementById('selETHAddress'), addr);
|
this.loadETHDropdown(document.getElementById('selETHAddress'), addr);
|
||||||
this.loadETHPins(document.getElementById('selETHPWRPin'), 'power');
|
this.loadETHOptions();
|
||||||
this.loadETHPins(document.getElementById('selETHMDCPin'), 'mdc', 23);
|
|
||||||
this.loadETHPins(document.getElementById('selETHMDIOPin'), 'mdio', 18);
|
|
||||||
ui.toElement(document.getElementById('divNetAdapter'), {
|
ui.toElement(document.getElementById('divNetAdapter'), {
|
||||||
wifi: {ssid:'', passphrase:''},
|
wifi: {ssid:'', passphrase:''},
|
||||||
ethernet: { boardType: 1, wirelessFallback: false, dhcp: true, dns1: '', dns2: '', ip: '', gateway: '' }
|
ethernet: { boardType: 1, wirelessFallback: false, dhcp: true, dns1: '', dns2: '', ip: '', gateway: '' }
|
||||||
|
|
@ -1602,14 +1601,27 @@ class Wifi {
|
||||||
this.onETHBoardTypeChanged(document.getElementById('selETHBoardType'));
|
this.onETHBoardTypeChanged(document.getElementById('selETHBoardType'));
|
||||||
this.initialized = true;
|
this.initialized = true;
|
||||||
}
|
}
|
||||||
loadETHPins(sel, type, selected) {
|
isP4() { return (document.getElementById('divContainer').getAttribute('data-chipmodel') || '').startsWith('p4'); }
|
||||||
|
clockModes() { return this.isP4() ? this.ethClockModesP4 : this.ethClockModes; }
|
||||||
|
// The board presets, clock modes and pins of the chip: the ESP32's or the
|
||||||
|
// P4's. The chip comes with the sync, after init().
|
||||||
|
loadETHOptions() {
|
||||||
|
let p4 = this.isP4();
|
||||||
|
this.loadETHDropdown(document.getElementById('selETHClkMode'), this.clockModes());
|
||||||
|
this.loadETHDropdown(document.getElementById('selETHBoardType'), this.ethBoardTypes.filter(b => b.val === 0 || (b.p4 === true) === p4));
|
||||||
|
let maxPin = p4 ? 54 : 35;
|
||||||
|
this.loadETHPins(document.getElementById('selETHPWRPin'), 'power', undefined, maxPin);
|
||||||
|
this.loadETHPins(document.getElementById('selETHMDCPin'), 'mdc', p4 ? 31 : 23, maxPin);
|
||||||
|
this.loadETHPins(document.getElementById('selETHMDIOPin'), 'mdio', p4 ? 52 : 18, maxPin);
|
||||||
|
}
|
||||||
|
loadETHPins(sel, type, selected, maxPin) {
|
||||||
let arr = [];
|
let arr = [];
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 'power':
|
case 'power':
|
||||||
arr.push({ val: -1, label: 'None' });
|
arr.push({ val: -1, label: 'None' });
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
for (let i = 0; i < 36; i++) {
|
for (let i = 0; i <= maxPin; i++) {
|
||||||
arr.push({ val: i, label: `GPIO ${i}` });
|
arr.push({ val: i, label: `GPIO ${i}` });
|
||||||
}
|
}
|
||||||
this.loadETHDropdown(sel, arr, selected);
|
this.loadETHDropdown(sel, arr, selected);
|
||||||
|
|
@ -1652,6 +1664,7 @@ class Wifi {
|
||||||
else {
|
else {
|
||||||
let settings = ProtoViews.network(proto.schema, reply);
|
let settings = ProtoViews.network(proto.schema, reply);
|
||||||
console.log(settings);
|
console.log(settings);
|
||||||
|
this.loadETHOptions();
|
||||||
let hasEthernet = settings.hasEthernet;
|
let hasEthernet = settings.hasEthernet;
|
||||||
this.hasEthernet = hasEthernet;
|
this.hasEthernet = hasEthernet;
|
||||||
document.getElementById('divHardwired').style.display = hasEthernet ? '' : 'none';
|
document.getElementById('divHardwired').style.display = hasEthernet ? '' : 'none';
|
||||||
|
|
@ -1815,7 +1828,7 @@ class Wifi {
|
||||||
if (obj.connType >= 2) {
|
if (obj.connType >= 2) {
|
||||||
let boardType = this.ethBoardTypes.find(elem => obj.ethernet.boardType === elem.val);
|
let boardType = this.ethBoardTypes.find(elem => obj.ethernet.boardType === elem.val);
|
||||||
let phyType = this.ethPhyTypes.find(elem => obj.ethernet.phyType === elem.val);
|
let phyType = this.ethPhyTypes.find(elem => obj.ethernet.phyType === elem.val);
|
||||||
let clkMode = this.ethClockModes.find(elem => obj.ethernet.CLKMode === elem.val);
|
let clkMode = this.clockModes().find(elem => obj.ethernet.CLKMode === elem.val);
|
||||||
let div = document.createElement('div');
|
let div = document.createElement('div');
|
||||||
let html = `<div id="divLanSettings" class="inst-overlay">`;
|
let html = `<div id="divLanSettings" class="inst-overlay">`;
|
||||||
html += '<div style="width:100%;color:red;text-align:center;font-weight:bold;"><span style="padding:10px;display:inline-block;width:100%;border-radius:5px;border-top-right-radius:17px;border-top-left-radius:17px;background:white;">BEWARE ... WARNING ... DANGER<span></div>';
|
html += '<div style="width:100%;color:red;text-align:center;font-weight:bold;"><span style="padding:10px;display:inline-block;width:100%;border-radius:5px;border-top-right-radius:17px;border-top-left-radius:17px;background:white;">BEWARE ... WARNING ... DANGER<span></div>';
|
||||||
|
|
@ -2720,12 +2733,18 @@ class Somfy {
|
||||||
{ name: 's3', maxPins: 48, inputs: [19, 20, 22, 23, 24, 25, 27, 28, 29, 30, 31, 32], outputs: [19, 20, 22, 23, 24, 25, 27, 28, 29, 30, 31, 32] },
|
{ name: 's3', maxPins: 48, inputs: [19, 20, 22, 23, 24, 25, 27, 28, 29, 30, 31, 32], outputs: [19, 20, 22, 23, 24, 25, 27, 28, 29, 30, 31, 32] },
|
||||||
{ name: 'c3', maxPins: 21, inputs: [11, 12, 13, 14, 15, 16, 17, 18, 19, 20], outputs: [11, 12, 13, 14, 15, 16, 17, 21] },
|
{ name: 'c3', maxPins: 21, inputs: [11, 12, 13, 14, 15, 16, 17, 18, 19, 20], outputs: [11, 12, 13, 14, 15, 16, 17, 21] },
|
||||||
{ name: 'c5', maxPins: 28, inputs: [13, 14, 15, 16, 17, 18, 19, 20, 21, 22], outputs: [13, 14, 15, 16, 17, 18, 19, 20, 21, 22] },
|
{ name: 'c5', maxPins: 28, inputs: [13, 14, 15, 16, 17, 18, 19, 20, 21, 22], outputs: [13, 14, 15, 16, 17, 18, 19, 20, 21, 22] },
|
||||||
{ name: 'c6', maxPins: 23, inputs: [], outputs: [] }
|
{ name: 'c6', maxPins: 23, inputs: [], outputs: [] },
|
||||||
|
// Without the C6's SDIO link (14-19, 54), USB Serial/JTAG (24, 25),
|
||||||
|
// Ethernet (28-31, 34, 35, 49-52), UART0 (37, 38) and the strapping
|
||||||
|
// pins (34-38).
|
||||||
|
{ name: 'p4', maxPins: 54, inputs: [14, 15, 16, 17, 18, 19, 24, 25, 28, 29, 30, 31, 34, 35, 36, 37, 38, 49, 50, 51, 52, 54], outputs: [14, 15, 16, 17, 18, 19, 24, 25, 28, 29, 30, 31, 34, 35, 36, 37, 38, 49, 50, 51, 52, 54] }
|
||||||
];
|
];
|
||||||
|
|
||||||
loadPins(type, sel, opt) {
|
loadPins(type, sel, opt) {
|
||||||
while (sel.firstChild) sel.removeChild(sel.firstChild);
|
while (sel.firstChild) sel.removeChild(sel.firstChild);
|
||||||
let cm = document.getElementById('divContainer').getAttribute('data-chipmodel');
|
let cm = document.getElementById('divContainer').getAttribute('data-chipmodel');
|
||||||
|
// The pre-v3 P4 build has the same pins.
|
||||||
|
if (cm === 'p4es') cm = 'p4';
|
||||||
let pm = this.pinMaps.find(x => x.name === cm) || { name: '', maxPins: 39, inputs: [], outputs: [] };
|
let pm = this.pinMaps.find(x => x.name === cm) || { name: '', maxPins: 39, inputs: [], outputs: [] };
|
||||||
//console.log({ cm: cm, pm: pm });
|
//console.log({ cm: cm, pm: pm });
|
||||||
for (let i = 0; i <= pm.maxPins; i++) {
|
for (let i = 0; i <= pm.maxPins; i++) {
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,8 @@ We moved every firmware env from `espressif32 @ 6.13.0` (Arduino 2.0.17 on ESP-I
|
||||||
|
|
||||||
> **Amended by [ADR 0006](0006-two-security-modes-eleven-http-routes.md) (4.0.0).** The C3 builds again. Without the old API (ports 8080 and 8081), its image is 1,498,512 bytes at level 2 and leaves 72.6 KB of the OTA slot. It runs on chip revision v0.3 or later only: the framework's C3 libraries are built with `CONFIG_ESP32C3_REV_MIN_3`. Its default radio pins moved off GPIO 12-17, which hold the SPI flash.
|
> **Amended by [ADR 0006](0006-two-security-modes-eleven-http-routes.md) (4.0.0).** The C3 builds again. Without the old API (ports 8080 and 8081), its image is 1,498,512 bytes at level 2 and leaves 72.6 KB of the OTA slot. It runs on chip revision v0.3 or later only: the framework's C3 libraries are built with `CONFIG_ESP32C3_REV_MIN_3`. Its default radio pins moved off GPIO 12-17, which hold the SPI flash.
|
||||||
- **The C5 is updated over USB.** New in 4.0.0. At level 2 its image left 3.4 KB of the OTA slot, under CI's 8 KB, so like the C6 it is released as a debug build with one 3 MB app slot (`esp32_huge_app.csv`), which no OTA can write. The framework's C5 libraries run on chip revision v1.0 or later only (`CONFIG_ESP32C5_REV_MIN_FULL=100`). Its WiFi has 5 GHz too, so the passive scans for the configured network (`src/ESPNetwork.cpp`, 300 ms a channel) cover about 38 channels instead of 13: about 11 s instead of 4 s, depending on the country's channels.
|
- **The C5 is updated over USB.** New in 4.0.0. At level 2 its image left 3.4 KB of the OTA slot, under CI's 8 KB, so like the C6 it is released as a debug build with one 3 MB app slot (`esp32_huge_app.csv`), which no OTA can write. The framework's C5 libraries run on chip revision v1.0 or later only (`CONFIG_ESP32C5_REV_MIN_FULL=100`). Its WiFi has 5 GHz too, so the passive scans for the configured network (`src/ESPNetwork.cpp`, 300 ms a channel) cover about 38 channels instead of 13: about 11 s instead of 4 s, depending on the country's channels.
|
||||||
- **Ethernet PHY ids are ours.** Arduino 3.x renumbered `eth_phy_type_t` (`ETH_PHY_GENERIC` is 0). NVS, backups and the web UI keep the Arduino 2.x numbers as `eth_phy_id_t` (`src/EthPhy.h`), translated by name when Ethernet starts. Never cast a stored id to the framework enum.
|
- **The P4 has two builds.** New in 4.0.0, for boards such as Waveshare's ESP32-P4-WIFI6-POE-ETH. The framework's P4 libraries run on chip revision v3.01 or later only (`CONFIG_ESP32P4_REV_MIN_FULL=301`), its `esp32p4_es` libraries on revisions before v2.0, so `esp32p4` (chip model `p4`) and `esp32p4es` (`p4es`) each get their own release files. No build runs on v2.x or v3.00. Both keep the OTA slot: at level 2 their images leave about 128 KB. WiFi goes through the board's ESP32-C6 on SDIO (esp-hosted, the framework's pins 14-19 and reset 54), so the C6 has to run a matching esp-hosted slave firmware, which Waveshare's boards ship with.
|
||||||
- **Ethernet only on the original ESP32.** Arduino 3.x has the RMII MAC API only where `CONFIG_ETH_USE_ESP32_EMAC` is set. S3, C3, C5 and C6 build without Ethernet.
|
- **Ethernet PHY ids are ours.** Arduino 3.x renumbered `eth_phy_type_t` (`ETH_PHY_GENERIC` is 0). NVS, backups and the web UI keep the Arduino 2.x numbers as `eth_phy_id_t` (`src/EthPhy.h`), translated by name when Ethernet starts. Never cast a stored id to the framework enum. The RMII clock mode is kept the same way, as `eth_clock_id_t` in the ESP32's numbering: the P4's `eth_clock_mode_t` is the IDF's `emac_rmii_clock_mode_t`, whose 0 is a deprecated default. On the P4 only clock in (GPIO 50) translates, since `ETH.begin()` keeps the clock on that pin, and a save refuses the others (`ETH_CLOCK_ID_MAX`).
|
||||||
|
- **Ethernet only on the original ESP32 and the P4.** Arduino 3.x has the RMII MAC API only where `CONFIG_ETH_USE_ESP32_EMAC` is set. S3, C3, C5 and C6 build without Ethernet.
|
||||||
- **Updates roll back until proven.** We override the core's `verifyRollbackLater()` hook to return true, and `loop()` marks the new firmware valid once it has run 60 s and the network is up. A reset before then boots the previous firmware. The LittleFS image an update wrote stays, so the old firmware runs with the new web UI.
|
- **Updates roll back until proven.** We override the core's `verifyRollbackLater()` hook to return true, and `loop()` marks the new firmware valid once it has run 60 s and the network is up. A reset before then boots the previous firmware. The LittleFS image an update wrote stays, so the old firmware runs with the new web UI.
|
||||||
- **Tooling.** pioarduino needs its own Core fork (`pip install pioarduino`, the pioarduino IDE extension in VS Code), which it installs into `~/.platformio/penv` in place of PlatformIO Core.
|
- **Tooling.** pioarduino needs its own Core fork (`pip install pioarduino`, the pioarduino IDE extension in VS Code), which it installs into `~/.platformio/penv` in place of PlatformIO Core.
|
||||||
|
|
|
||||||
|
|
@ -126,6 +126,27 @@ build_flags =
|
||||||
${esp32.build_flags}
|
${esp32.build_flags}
|
||||||
-DCORE_DEBUG_LEVEL=3
|
-DCORE_DEBUG_LEVEL=3
|
||||||
|
|
||||||
|
; ESP32-P4 boards such as Waveshare's ESP32-P4-WIFI6-POE-ETH: WiFi through an
|
||||||
|
; ESP32-C6 on SDIO (esp-hosted), Ethernet on the P4's own RMII MAC. The
|
||||||
|
; framework's P4 libraries run on chip revision v3.01 or later only, and its
|
||||||
|
; esp32p4_es libraries on revisions before v2.0, so each gets its own build.
|
||||||
|
; No build runs on v2.x or v3.00.
|
||||||
|
[env:esp32p4]
|
||||||
|
extends = esp32
|
||||||
|
board = esp32-p4_r3
|
||||||
|
board_build.partitions = esp32_3MB.csv
|
||||||
|
build_flags =
|
||||||
|
${dualcore.build_flags}
|
||||||
|
-DCORE_DEBUG_LEVEL=2
|
||||||
|
|
||||||
|
[env:esp32p4es]
|
||||||
|
extends = esp32
|
||||||
|
board = esp32-p4
|
||||||
|
board_build.partitions = esp32_3MB.csv
|
||||||
|
build_flags =
|
||||||
|
${dualcore.build_flags}
|
||||||
|
-DCORE_DEBUG_LEVEL=2
|
||||||
|
|
||||||
; Host-side unit tests: pio test -e native (needs gcc/g++ on PATH).
|
; Host-side unit tests: pio test -e native (needs gcc/g++ on PATH).
|
||||||
; Only the sources the tests cover are built; test/stubs stands in for Arduino.h.
|
; Only the sources the tests cover are built; test/stubs stands in for Arduino.h.
|
||||||
[env:native]
|
[env:native]
|
||||||
|
|
|
||||||
|
|
@ -149,7 +149,7 @@ static net_record_t netRecord() {
|
||||||
#if HAS_ETHERNET
|
#if HAS_ETHERNET
|
||||||
rec.ethBoardType = settings.Ethernet.boardType;
|
rec.ethBoardType = settings.Ethernet.boardType;
|
||||||
rec.ethPhyType = settings.Ethernet.phyType;
|
rec.ethPhyType = settings.Ethernet.phyType;
|
||||||
rec.ethClkMode = static_cast<uint8_t>(settings.Ethernet.CLKMode);
|
rec.ethClkMode = settings.Ethernet.CLKMode;
|
||||||
rec.ethPhyAddress = settings.Ethernet.phyAddress;
|
rec.ethPhyAddress = settings.Ethernet.phyAddress;
|
||||||
rec.ethPWRPin = settings.Ethernet.PWRPin;
|
rec.ethPWRPin = settings.Ethernet.PWRPin;
|
||||||
rec.ethMDCPin = settings.Ethernet.MDCPin;
|
rec.ethMDCPin = settings.Ethernet.MDCPin;
|
||||||
|
|
@ -196,7 +196,7 @@ static void applyNetRecord(const net_record_t &rec, const restore_options_t &opt
|
||||||
ESP_LOGI(TAG, "Restoring Ethernet adapter settings");
|
ESP_LOGI(TAG, "Restoring Ethernet adapter settings");
|
||||||
settings.Ethernet.boardType = rec.ethBoardType;
|
settings.Ethernet.boardType = rec.ethBoardType;
|
||||||
settings.Ethernet.phyType = rec.ethPhyType;
|
settings.Ethernet.phyType = rec.ethPhyType;
|
||||||
settings.Ethernet.CLKMode = static_cast<eth_clock_mode_t>(rec.ethClkMode);
|
settings.Ethernet.CLKMode = rec.ethClkMode;
|
||||||
settings.Ethernet.phyAddress = rec.ethPhyAddress;
|
settings.Ethernet.phyAddress = rec.ethPhyAddress;
|
||||||
settings.Ethernet.PWRPin = rec.ethPWRPin;
|
settings.Ethernet.PWRPin = rec.ethPWRPin;
|
||||||
settings.Ethernet.MDCPin = rec.ethMDCPin;
|
settings.Ethernet.MDCPin = rec.ethMDCPin;
|
||||||
|
|
|
||||||
|
|
@ -145,6 +145,17 @@ bool ConfigSettings::begin() {
|
||||||
strcpy(this->chipModel, "c6");
|
strcpy(this->chipModel, "c6");
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef CONFIG_IDF_TARGET_ESP32P4
|
||||||
|
// Chips before v2.0 run their own build (esp32p4_es libraries), so they
|
||||||
|
// get their own release files. v2.x and v3.00 run neither.
|
||||||
|
case esp_chip_model_t::CHIP_ESP32P4:
|
||||||
|
#if CONFIG_ESP32P4_SELECTS_REV_LESS_V3
|
||||||
|
strcpy(this->chipModel, "p4es");
|
||||||
|
#else
|
||||||
|
strcpy(this->chipModel, "p4");
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
default:
|
default:
|
||||||
sprintf(this->chipModel, "UNK%d", static_cast<int>(ci.model));
|
sprintf(this->chipModel, "UNK%d", static_cast<int>(ci.model));
|
||||||
break;
|
break;
|
||||||
|
|
@ -499,7 +510,7 @@ bool EthernetSettings::begin() {
|
||||||
bool EthernetSettings::fromJSON(JsonObject &obj) {
|
bool EthernetSettings::fromJSON(JsonObject &obj) {
|
||||||
if(!obj["boardType"].isNull()) this->boardType = obj["boardType"];
|
if(!obj["boardType"].isNull()) this->boardType = obj["boardType"];
|
||||||
if(!obj["phyAddress"].isNull()) this->phyAddress = obj["phyAddress"];
|
if(!obj["phyAddress"].isNull()) this->phyAddress = obj["phyAddress"];
|
||||||
if(!obj["CLKMode"].isNull()) this->CLKMode = static_cast<eth_clock_mode_t>(obj["CLKMode"]);
|
if(!obj["CLKMode"].isNull()) this->CLKMode = obj["CLKMode"];
|
||||||
if(!obj["phyType"].isNull()) this->phyType = obj["phyType"];
|
if(!obj["phyType"].isNull()) this->phyType = obj["phyType"];
|
||||||
if(!obj["PWRPin"].isNull()) this->PWRPin = obj["PWRPin"];
|
if(!obj["PWRPin"].isNull()) this->PWRPin = obj["PWRPin"];
|
||||||
if(!obj["MDCPin"].isNull()) this->MDCPin = obj["MDCPin"];
|
if(!obj["MDCPin"].isNull()) this->MDCPin = obj["MDCPin"];
|
||||||
|
|
@ -507,9 +518,7 @@ bool EthernetSettings::fromJSON(JsonObject &obj) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
bool EthernetSettings::usesPin(uint8_t pin) {
|
bool EthernetSettings::usesPin(uint8_t pin) {
|
||||||
if((this->CLKMode == 0 || this->CLKMode == 1) && pin == 0) return true;
|
if(ethClockPin(this->CLKMode) == pin) return true;
|
||||||
else if(this->CLKMode == 2 && pin == 16) return true;
|
|
||||||
else if(this->CLKMode == 3 && pin == 17) return true;
|
|
||||||
else if(this->PWRPin == pin) return true;
|
else if(this->PWRPin == pin) return true;
|
||||||
else if(this->MDCPin == pin) return true;
|
else if(this->MDCPin == pin) return true;
|
||||||
else if(this->MDIOPin == pin) return true;
|
else if(this->MDIOPin == pin) return true;
|
||||||
|
|
@ -522,7 +531,7 @@ bool EthernetSettings::save() {
|
||||||
pref.putChar("boardType", this->boardType);
|
pref.putChar("boardType", this->boardType);
|
||||||
pref.putChar("phyAddress", this->phyAddress);
|
pref.putChar("phyAddress", this->phyAddress);
|
||||||
pref.putChar("phyType", this->phyType);
|
pref.putChar("phyType", this->phyType);
|
||||||
pref.putChar("CLKMode", static_cast<uint8_t>(this->CLKMode));
|
pref.putChar("CLKMode", this->CLKMode);
|
||||||
pref.putChar("PWRPin", this->PWRPin);
|
pref.putChar("PWRPin", this->PWRPin);
|
||||||
pref.putChar("MDCPin", this->MDCPin);
|
pref.putChar("MDCPin", this->MDCPin);
|
||||||
pref.putChar("MDIOPin", this->MDIOPin);
|
pref.putChar("MDIOPin", this->MDIOPin);
|
||||||
|
|
@ -534,7 +543,7 @@ bool EthernetSettings::load() {
|
||||||
pref.begin("ETH");
|
pref.begin("ETH");
|
||||||
this->boardType = pref.getChar("boardType", this->boardType);
|
this->boardType = pref.getChar("boardType", this->boardType);
|
||||||
this->phyType = pref.getChar("phyType", this->phyType);
|
this->phyType = pref.getChar("phyType", this->phyType);
|
||||||
this->CLKMode = static_cast<eth_clock_mode_t>(pref.getChar("CLKMode", ETH_CLOCK_GPIO0_IN));
|
this->CLKMode = pref.getChar("CLKMode", this->CLKMode);
|
||||||
this->phyAddress = pref.getChar("phyAddress", this->phyAddress);
|
this->phyAddress = pref.getChar("phyAddress", this->phyAddress);
|
||||||
this->PWRPin = pref.getChar("PWRPin", this->PWRPin);
|
this->PWRPin = pref.getChar("PWRPin", this->PWRPin);
|
||||||
this->MDCPin = pref.getChar("MDCPin", this->MDCPin);
|
this->MDCPin = pref.getChar("MDCPin", this->MDCPin);
|
||||||
|
|
|
||||||
|
|
@ -88,14 +88,26 @@ class WifiSettings: BaseSettings {
|
||||||
class EthernetSettings: BaseSettings {
|
class EthernetSettings: BaseSettings {
|
||||||
public:
|
public:
|
||||||
EthernetSettings();
|
EthernetSettings();
|
||||||
|
uint8_t CLKMode = static_cast<uint8_t>(eth_clock_id_t::GPIO0_IN); // An eth_clock_id_t, see EthPhy.h.
|
||||||
|
#if defined(CONFIG_IDF_TARGET_ESP32P4)
|
||||||
|
// The IP101 wiring of Espressif's P4 boards, which Waveshare's ESP32-P4-ETH
|
||||||
|
// boards copy, and the web UI's board type for it. The ESP32's defaults
|
||||||
|
// would put MDIO on an SDIO pin.
|
||||||
|
uint8_t boardType = 8;
|
||||||
|
uint8_t phyType = static_cast<uint8_t>(eth_phy_id_t::TLK110);
|
||||||
|
int8_t phyAddress = 1;
|
||||||
|
int8_t PWRPin = 51;
|
||||||
|
int8_t MDCPin = 31;
|
||||||
|
int8_t MDIOPin = 52;
|
||||||
|
#else
|
||||||
uint8_t boardType = 0; // These board types are enumerated in the ui and used to set the chip settings.
|
uint8_t boardType = 0; // These board types are enumerated in the ui and used to set the chip settings.
|
||||||
uint8_t phyType = static_cast<uint8_t>(eth_phy_id_t::LAN8720); // An eth_phy_id_t, see EthPhy.h.
|
uint8_t phyType = static_cast<uint8_t>(eth_phy_id_t::LAN8720); // An eth_phy_id_t, see EthPhy.h.
|
||||||
eth_clock_mode_t CLKMode = ETH_CLOCK_GPIO0_IN;
|
|
||||||
// The LAN8720 wiring Arduino 2.x defaulted to. 3.x has no defaults.
|
// The LAN8720 wiring Arduino 2.x defaulted to. 3.x has no defaults.
|
||||||
int8_t phyAddress = 0;
|
int8_t phyAddress = 0;
|
||||||
int8_t PWRPin = -1;
|
int8_t PWRPin = -1;
|
||||||
int8_t MDCPin = 23;
|
int8_t MDCPin = 23;
|
||||||
int8_t MDIOPin = 18;
|
int8_t MDIOPin = 18;
|
||||||
|
#endif
|
||||||
|
|
||||||
bool begin();
|
bool begin();
|
||||||
bool fromJSON(JsonObject &obj);
|
bool fromJSON(JsonObject &obj);
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,7 @@ static void writeSettings(ProtoWriter &w, settings_section_t section) {
|
||||||
w.add(proto_field_t::hasEthernet, true);
|
w.add(proto_field_t::hasEthernet, true);
|
||||||
w.add(proto_field_t::boardType, settings.Ethernet.boardType);
|
w.add(proto_field_t::boardType, settings.Ethernet.boardType);
|
||||||
w.add(proto_field_t::phyType, settings.Ethernet.phyType);
|
w.add(proto_field_t::phyType, settings.Ethernet.phyType);
|
||||||
w.add(proto_field_t::CLKMode, static_cast<uint8_t>(settings.Ethernet.CLKMode));
|
w.add(proto_field_t::CLKMode, settings.Ethernet.CLKMode);
|
||||||
w.add(proto_field_t::phyAddress, settings.Ethernet.phyAddress);
|
w.add(proto_field_t::phyAddress, settings.Ethernet.phyAddress);
|
||||||
w.add(proto_field_t::PWRPin, settings.Ethernet.PWRPin);
|
w.add(proto_field_t::PWRPin, settings.Ethernet.PWRPin);
|
||||||
w.add(proto_field_t::MDCPin, settings.Ethernet.MDCPin);
|
w.add(proto_field_t::MDCPin, settings.Ethernet.MDCPin);
|
||||||
|
|
|
||||||
|
|
@ -356,11 +356,14 @@ bool ESPNetwork::connectWired() {
|
||||||
ETH.setHostname("ESPSomfy-RTS");
|
ETH.setHostname("ESPSomfy-RTS");
|
||||||
ESP_LOGD(TAG, "Set hostname to: %s", ETH.getHostname());
|
ESP_LOGD(TAG, "Set hostname to: %s", ETH.getHostname());
|
||||||
eth_phy_type_t phyType;
|
eth_phy_type_t phyType;
|
||||||
|
eth_clock_mode_t clkMode;
|
||||||
bool begun = false;
|
bool begun = false;
|
||||||
if(!ethPhyType(settings.Ethernet.phyType, phyType))
|
if(!ethPhyType(settings.Ethernet.phyType, phyType))
|
||||||
ESP_LOGE(TAG, "Ethernet PHY type %u is not supported", (unsigned int)settings.Ethernet.phyType);
|
ESP_LOGE(TAG, "Ethernet PHY type %u is not supported", (unsigned int)settings.Ethernet.phyType);
|
||||||
|
else if(!ethClockMode(settings.Ethernet.CLKMode, clkMode))
|
||||||
|
ESP_LOGE(TAG, "Ethernet clock mode %u is not supported", (unsigned int)settings.Ethernet.CLKMode);
|
||||||
else
|
else
|
||||||
begun = ETH.begin(phyType, settings.Ethernet.phyAddress, settings.Ethernet.MDCPin, settings.Ethernet.MDIOPin, settings.Ethernet.PWRPin, settings.Ethernet.CLKMode);
|
begun = ETH.begin(phyType, settings.Ethernet.phyAddress, settings.Ethernet.MDCPin, settings.Ethernet.MDIOPin, settings.Ethernet.PWRPin, clkMode);
|
||||||
if(!begun) {
|
if(!begun) {
|
||||||
ESP_LOGE(TAG, "Ethernet Begin failed");
|
ESP_LOGE(TAG, "Ethernet Begin failed");
|
||||||
this->ethStarted = false;
|
this->ethStarted = false;
|
||||||
|
|
|
||||||
52
src/EthPhy.h
52
src/EthPhy.h
|
|
@ -5,8 +5,8 @@
|
||||||
#include <sdkconfig.h>
|
#include <sdkconfig.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Ethernet needs the RMII MAC, which only the original ESP32 has. The C3, C5,
|
// Ethernet needs the RMII MAC, which only the original ESP32 and the P4 have.
|
||||||
// S3 and C6 build without it.
|
// The C3, C5, S3 and C6 build without it.
|
||||||
#if defined(CONFIG_ETH_USE_ESP32_EMAC) && CONFIG_ETH_USE_ESP32_EMAC
|
#if defined(CONFIG_ETH_USE_ESP32_EMAC) && CONFIG_ETH_USE_ESP32_EMAC
|
||||||
#define HAS_ETHERNET 1
|
#define HAS_ETHERNET 1
|
||||||
#else
|
#else
|
||||||
|
|
@ -26,6 +26,39 @@ enum class eth_phy_id_t : uint8_t {
|
||||||
KSZ8081 = 6
|
KSZ8081 = 6
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// RMII clock ids as stored in NVS and backups and sent to the web UI: the
|
||||||
|
// original ESP32's eth_clock_mode_t values. The P4's eth_clock_mode_t is the
|
||||||
|
// IDF's emac_rmii_clock_mode_t, a different enum, so an id is translated.
|
||||||
|
enum class eth_clock_id_t : uint8_t {
|
||||||
|
GPIO0_IN = 0, // The clock comes in. On the P4, on GPIO 50.
|
||||||
|
GPIO0_OUT = 1,
|
||||||
|
GPIO16_OUT = 2,
|
||||||
|
GPIO17_OUT = 3
|
||||||
|
};
|
||||||
|
// The highest clock id the chip takes: the P4's ETH.begin() takes the clock
|
||||||
|
// in on GPIO 50 only.
|
||||||
|
#if defined(CONFIG_IDF_TARGET_ESP32P4)
|
||||||
|
constexpr uint8_t ETH_CLOCK_ID_MAX = 0;
|
||||||
|
#else
|
||||||
|
constexpr uint8_t ETH_CLOCK_ID_MAX = 3;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// The GPIO a stored clock id puts the RMII clock on, -1 for an id the chip
|
||||||
|
// can't use.
|
||||||
|
inline int8_t ethClockPin(uint8_t id) {
|
||||||
|
#if defined(CONFIG_IDF_TARGET_ESP32P4)
|
||||||
|
return static_cast<eth_clock_id_t>(id) == eth_clock_id_t::GPIO0_IN ? 50 : -1;
|
||||||
|
#else
|
||||||
|
switch(static_cast<eth_clock_id_t>(id)) {
|
||||||
|
case eth_clock_id_t::GPIO0_IN:
|
||||||
|
case eth_clock_id_t::GPIO0_OUT: return 0;
|
||||||
|
case eth_clock_id_t::GPIO16_OUT: return 16;
|
||||||
|
case eth_clock_id_t::GPIO17_OUT: return 17;
|
||||||
|
default: return -1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
#if HAS_ETHERNET
|
#if HAS_ETHERNET
|
||||||
#include <ETH.h>
|
#include <ETH.h>
|
||||||
// Sets type to the framework's PHY for a stored id. False for an id the RMII
|
// Sets type to the framework's PHY for a stored id. False for an id the RMII
|
||||||
|
|
@ -41,5 +74,20 @@ inline bool ethPhyType(uint8_t id, eth_phy_type_t &type) {
|
||||||
default: return false;
|
default: return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Sets mode to the framework's clock mode for a stored id. False for an id
|
||||||
|
// the chip can't use.
|
||||||
|
inline bool ethClockMode(uint8_t id, eth_clock_mode_t &mode) {
|
||||||
|
switch(static_cast<eth_clock_id_t>(id)) {
|
||||||
|
#if defined(CONFIG_IDF_TARGET_ESP32P4)
|
||||||
|
case eth_clock_id_t::GPIO0_IN: mode = EMAC_CLK_EXT_IN; return true;
|
||||||
|
#else
|
||||||
|
case eth_clock_id_t::GPIO0_IN: mode = ETH_CLOCK_GPIO0_IN; return true;
|
||||||
|
case eth_clock_id_t::GPIO0_OUT: mode = ETH_CLOCK_GPIO0_OUT; return true;
|
||||||
|
case eth_clock_id_t::GPIO16_OUT: mode = ETH_CLOCK_GPIO16_OUT; return true;
|
||||||
|
case eth_clock_id_t::GPIO17_OUT: mode = ETH_CLOCK_GPIO17_OUT; return true;
|
||||||
|
#endif
|
||||||
|
default: return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "ProtoSettings.h"
|
#include "ProtoSettings.h"
|
||||||
#include "ProtoParse.h"
|
#include "ProtoParse.h"
|
||||||
|
#include "EthPhy.h"
|
||||||
|
|
||||||
static const char *const SECTIONS[] = {"general", "network", "mqtt", "security", "radio"};
|
static const char *const SECTIONS[] = {"general", "network", "mqtt", "security", "radio"};
|
||||||
const char *settingsSectionName(settings_section_t section) { return SECTIONS[static_cast<uint8_t>(section)]; }
|
const char *settingsSectionName(settings_section_t section) { return SECTIONS[static_cast<uint8_t>(section)]; }
|
||||||
|
|
@ -45,11 +46,12 @@ static const settings_field_t FIELDS[] = {
|
||||||
{settings_part_t::wifi, proto_field_t::hidden, nullptr, 0, 0},
|
{settings_part_t::wifi, proto_field_t::hidden, nullptr, 0, 0},
|
||||||
{settings_part_t::ethernet, proto_field_t::boardType, nullptr, 0, 255},
|
{settings_part_t::ethernet, proto_field_t::boardType, nullptr, 0, 255},
|
||||||
{settings_part_t::ethernet, proto_field_t::phyType, nullptr, 0, 255},
|
{settings_part_t::ethernet, proto_field_t::phyType, nullptr, 0, 255},
|
||||||
{settings_part_t::ethernet, proto_field_t::CLKMode, nullptr, 0, 3},
|
{settings_part_t::ethernet, proto_field_t::CLKMode, nullptr, 0, ETH_CLOCK_ID_MAX},
|
||||||
{settings_part_t::ethernet, proto_field_t::phyAddress, nullptr, -1, 31},
|
{settings_part_t::ethernet, proto_field_t::phyAddress, nullptr, -1, 31},
|
||||||
{settings_part_t::ethernet, proto_field_t::PWRPin, nullptr, -1, 48},
|
// Pins run to GPIO 54, the P4's last.
|
||||||
{settings_part_t::ethernet, proto_field_t::MDCPin, nullptr, 0, 48},
|
{settings_part_t::ethernet, proto_field_t::PWRPin, nullptr, -1, 54},
|
||||||
{settings_part_t::ethernet, proto_field_t::MDIOPin, nullptr, 0, 48},
|
{settings_part_t::ethernet, proto_field_t::MDCPin, nullptr, 0, 54},
|
||||||
|
{settings_part_t::ethernet, proto_field_t::MDIOPin, nullptr, 0, 54},
|
||||||
{settings_part_t::ip, proto_field_t::dhcp, nullptr, 0, 0},
|
{settings_part_t::ip, proto_field_t::dhcp, nullptr, 0, 0},
|
||||||
{settings_part_t::ip, proto_field_t::ip, nullptr, 0, 15},
|
{settings_part_t::ip, proto_field_t::ip, nullptr, 0, 15},
|
||||||
{settings_part_t::ip, proto_field_t::gateway, nullptr, 0, 15},
|
{settings_part_t::ip, proto_field_t::gateway, nullptr, 0, 15},
|
||||||
|
|
@ -75,12 +77,12 @@ static const settings_field_t FIELDS[] = {
|
||||||
// RTS, RTW, RTV, GP Relay or GP Remote (radio_proto), checked on its own.
|
// RTS, RTW, RTV, GP Relay or GP Remote (radio_proto), checked on its own.
|
||||||
{settings_part_t::radio, proto_field_t::proto, nullptr, 0, 9},
|
{settings_part_t::radio, proto_field_t::proto, nullptr, 0, 9},
|
||||||
{settings_part_t::radio, proto_field_t::enabled, nullptr, 0, 0},
|
{settings_part_t::radio, proto_field_t::enabled, nullptr, 0, 0},
|
||||||
{settings_part_t::radio, proto_field_t::TXPin, nullptr, 0, 48},
|
{settings_part_t::radio, proto_field_t::TXPin, nullptr, 0, 54},
|
||||||
{settings_part_t::radio, proto_field_t::RXPin, nullptr, 0, 48},
|
{settings_part_t::radio, proto_field_t::RXPin, nullptr, 0, 54},
|
||||||
{settings_part_t::radio, proto_field_t::SCKPin, nullptr, 0, 48},
|
{settings_part_t::radio, proto_field_t::SCKPin, nullptr, 0, 54},
|
||||||
{settings_part_t::radio, proto_field_t::MOSIPin, nullptr, 0, 48},
|
{settings_part_t::radio, proto_field_t::MOSIPin, nullptr, 0, 54},
|
||||||
{settings_part_t::radio, proto_field_t::MISOPin, nullptr, 0, 48},
|
{settings_part_t::radio, proto_field_t::MISOPin, nullptr, 0, 54},
|
||||||
{settings_part_t::radio, proto_field_t::CSNPin, nullptr, 0, 48},
|
{settings_part_t::radio, proto_field_t::CSNPin, nullptr, 0, 54},
|
||||||
// What the CC1101 can be set to, in MHz and kHz.
|
// What the CC1101 can be set to, in MHz and kHz.
|
||||||
{settings_part_t::radio, proto_field_t::frequency, nullptr, 30000, 92800},
|
{settings_part_t::radio, proto_field_t::frequency, nullptr, 30000, 92800},
|
||||||
{settings_part_t::radio, proto_field_t::rxBandwidth, nullptr, 5803, 81250},
|
{settings_part_t::radio, proto_field_t::rxBandwidth, nullptr, 5803, 81250},
|
||||||
|
|
@ -137,7 +139,8 @@ static const char *checkValue(const settings_field_t &s, const proto_field_info_
|
||||||
return why;
|
return why;
|
||||||
}
|
}
|
||||||
if(inRange) return nullptr;
|
if(inRange) return nullptr;
|
||||||
snprintf(why, sizeof(why), "%s must be %ld-%ld", f.name, (long)s.lo, (long)s.hi);
|
if(s.lo == s.hi) snprintf(why, sizeof(why), "%s must be %ld", f.name, (long)s.lo);
|
||||||
|
else snprintf(why, sizeof(why), "%s must be %ld-%ld", f.name, (long)s.lo, (long)s.hi);
|
||||||
return why;
|
return why;
|
||||||
}
|
}
|
||||||
if(f.kind == 'n') {
|
if(f.kind == 'n') {
|
||||||
|
|
|
||||||
|
|
@ -506,6 +506,21 @@ void transceiver_config_t::load() {
|
||||||
this->SCKPin = 6;
|
this->SCKPin = 6;
|
||||||
this->CSNPin = 0;
|
this->CSNPin = 0;
|
||||||
break;
|
break;
|
||||||
|
#endif
|
||||||
|
#ifdef CONFIG_IDF_TARGET_ESP32P4
|
||||||
|
case esp_chip_model_t::CHIP_ESP32P4:
|
||||||
|
// The SPI pins of the framework's variant for Waveshare's ESP32-P4-ETH
|
||||||
|
// (variants/waveshare_p4_poe_eth); TX and RX take 2 and 3, which that
|
||||||
|
// board leaves free. The C6's SDIO link holds 14-19 and 54, Ethernet
|
||||||
|
// 28-31, 34, 35 and 49-52, and 34-38 are strapping pins. 46 is on LDO
|
||||||
|
// channel 4, which the core turns on when a pin of it is used.
|
||||||
|
this->TXPin = 2;
|
||||||
|
this->RXPin = 3;
|
||||||
|
this->MOSIPin = 32;
|
||||||
|
this->MISOPin = 33;
|
||||||
|
this->SCKPin = 27;
|
||||||
|
this->CSNPin = 46;
|
||||||
|
break;
|
||||||
#endif
|
#endif
|
||||||
default:
|
default:
|
||||||
this->TXPin = 13;
|
this->TXPin = 13;
|
||||||
|
|
|
||||||
|
|
@ -85,7 +85,7 @@ const char *wifiAuthModeName(uint8_t authMode);
|
||||||
bool otaProven(bool networkUp, unsigned long uptimeMs, unsigned long minUptimeMs);
|
bool otaProven(bool networkUp, unsigned long uptimeMs, unsigned long minUptimeMs);
|
||||||
// A release asset's name: "SomfyController.<kind>.esp32<chipModel>.bin", kind
|
// A release asset's name: "SomfyController.<kind>.esp32<chipModel>.bin", kind
|
||||||
// "ino" for the firmware or "littlefs" for the web UI image, chipModel as in
|
// "ino" for the firmware or "littlefs" for the web UI image, chipModel as in
|
||||||
// ConfigSettings ("" for the ESP32, "s3", "c3", "c5", "c6").
|
// ConfigSettings ("" for the ESP32, "s3", "c3", "c5", "c6", "p4", "p4es").
|
||||||
void releaseAssetName(char *buf, size_t size, const char *kind, const char *chipModel);
|
void releaseAssetName(char *buf, size_t size, const char *kind, const char *chipModel);
|
||||||
// A coredump backtrace as " 0x%08x" per frame. bt holds maxFrames entries and
|
// A coredump backtrace as " 0x%08x" per frame. bt holds maxFrames entries and
|
||||||
// depth is how many the dump claims are valid.
|
// depth is how many the dump claims are valid.
|
||||||
|
|
|
||||||
|
|
@ -13,4 +13,20 @@ typedef enum {
|
||||||
ETH_PHY_KSZ8081,
|
ETH_PHY_KSZ8081,
|
||||||
ETH_PHY_MAX
|
ETH_PHY_MAX
|
||||||
} eth_phy_type_t;
|
} eth_phy_type_t;
|
||||||
|
#if defined(CONFIG_IDF_TARGET_ESP32P4)
|
||||||
|
// The P4's ETH.h takes the IDF's enum, where 0 is a deprecated default.
|
||||||
|
typedef enum {
|
||||||
|
EMAC_CLK_DEFAULT,
|
||||||
|
EMAC_CLK_EXT_IN,
|
||||||
|
EMAC_CLK_OUT
|
||||||
|
} emac_rmii_clock_mode_t;
|
||||||
|
typedef emac_rmii_clock_mode_t eth_clock_mode_t;
|
||||||
|
#else
|
||||||
|
typedef enum {
|
||||||
|
ETH_CLOCK_GPIO0_IN,
|
||||||
|
ETH_CLOCK_GPIO0_OUT,
|
||||||
|
ETH_CLOCK_GPIO16_OUT,
|
||||||
|
ETH_CLOCK_GPIO17_OUT
|
||||||
|
} eth_clock_mode_t;
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,45 @@ static void test_rejects_unknown_ids() {
|
||||||
TEST_ASSERT_FALSE(ethPhyType(255, type));
|
TEST_ASSERT_FALSE(ethPhyType(255, type));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*********************************************************************
|
||||||
|
* Clock modes
|
||||||
|
********************************************************************/
|
||||||
|
static void test_clock_ids_match_stored_values() {
|
||||||
|
TEST_ASSERT_EQUAL_UINT8(0, static_cast<uint8_t>(eth_clock_id_t::GPIO0_IN));
|
||||||
|
TEST_ASSERT_EQUAL_UINT8(1, static_cast<uint8_t>(eth_clock_id_t::GPIO0_OUT));
|
||||||
|
TEST_ASSERT_EQUAL_UINT8(2, static_cast<uint8_t>(eth_clock_id_t::GPIO16_OUT));
|
||||||
|
TEST_ASSERT_EQUAL_UINT8(3, static_cast<uint8_t>(eth_clock_id_t::GPIO17_OUT));
|
||||||
|
}
|
||||||
|
static void test_translates_each_clock_mode() {
|
||||||
|
eth_clock_mode_t mode;
|
||||||
|
TEST_ASSERT_TRUE(ethClockMode(0, mode));
|
||||||
|
TEST_ASSERT_EQUAL(ETH_CLOCK_GPIO0_IN, mode);
|
||||||
|
TEST_ASSERT_TRUE(ethClockMode(1, mode));
|
||||||
|
TEST_ASSERT_EQUAL(ETH_CLOCK_GPIO0_OUT, mode);
|
||||||
|
TEST_ASSERT_TRUE(ethClockMode(2, mode));
|
||||||
|
TEST_ASSERT_EQUAL(ETH_CLOCK_GPIO16_OUT, mode);
|
||||||
|
TEST_ASSERT_TRUE(ethClockMode(3, mode));
|
||||||
|
TEST_ASSERT_EQUAL(ETH_CLOCK_GPIO17_OUT, mode);
|
||||||
|
}
|
||||||
|
static void test_rejects_unknown_clock_ids() {
|
||||||
|
eth_clock_mode_t mode;
|
||||||
|
TEST_ASSERT_FALSE(ethClockMode(4, mode));
|
||||||
|
TEST_ASSERT_FALSE(ethClockMode(255, mode));
|
||||||
|
}
|
||||||
|
static void test_a_save_takes_each_clock_id_that_translates() {
|
||||||
|
eth_clock_mode_t mode;
|
||||||
|
TEST_ASSERT_EQUAL_UINT8(3, ETH_CLOCK_ID_MAX);
|
||||||
|
TEST_ASSERT_TRUE(ethClockMode(ETH_CLOCK_ID_MAX, mode));
|
||||||
|
TEST_ASSERT_FALSE(ethClockMode(ETH_CLOCK_ID_MAX + 1, mode));
|
||||||
|
}
|
||||||
|
static void test_clock_pins() {
|
||||||
|
TEST_ASSERT_EQUAL_INT8(0, ethClockPin(0));
|
||||||
|
TEST_ASSERT_EQUAL_INT8(0, ethClockPin(1));
|
||||||
|
TEST_ASSERT_EQUAL_INT8(16, ethClockPin(2));
|
||||||
|
TEST_ASSERT_EQUAL_INT8(17, ethClockPin(3));
|
||||||
|
TEST_ASSERT_EQUAL_INT8(-1, ethClockPin(4));
|
||||||
|
}
|
||||||
|
|
||||||
int main(int, char **) {
|
int main(int, char **) {
|
||||||
UNITY_BEGIN();
|
UNITY_BEGIN();
|
||||||
RUN_TEST(test_ids_match_stored_values);
|
RUN_TEST(test_ids_match_stored_values);
|
||||||
|
|
@ -59,5 +98,10 @@ int main(int, char **) {
|
||||||
RUN_TEST(test_lan8720_is_not_the_framework_zero);
|
RUN_TEST(test_lan8720_is_not_the_framework_zero);
|
||||||
RUN_TEST(test_rejects_dm9051);
|
RUN_TEST(test_rejects_dm9051);
|
||||||
RUN_TEST(test_rejects_unknown_ids);
|
RUN_TEST(test_rejects_unknown_ids);
|
||||||
|
RUN_TEST(test_clock_ids_match_stored_values);
|
||||||
|
RUN_TEST(test_translates_each_clock_mode);
|
||||||
|
RUN_TEST(test_rejects_unknown_clock_ids);
|
||||||
|
RUN_TEST(test_a_save_takes_each_clock_id_that_translates);
|
||||||
|
RUN_TEST(test_clock_pins);
|
||||||
return UNITY_END();
|
return UNITY_END();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
58
test/test_ethphy_p4/test_ethphy_p4.cpp
Normal file
58
test/test_ethphy_p4/test_ethphy_p4.cpp
Normal file
|
|
@ -0,0 +1,58 @@
|
||||||
|
#include <unity.h>
|
||||||
|
// As on the ESP32-P4, which has the RMII MAC too but takes the IDF's clock
|
||||||
|
// enum.
|
||||||
|
#define CONFIG_ETH_USE_ESP32_EMAC 1
|
||||||
|
#define CONFIG_IDF_TARGET_ESP32P4 1
|
||||||
|
#include "EthPhy.h"
|
||||||
|
|
||||||
|
void setUp() {}
|
||||||
|
void tearDown() {}
|
||||||
|
|
||||||
|
static void test_builds_with_ethernet() {
|
||||||
|
TEST_ASSERT_EQUAL(1, HAS_ETHERNET);
|
||||||
|
}
|
||||||
|
static void test_ip101_is_the_tlk110_id() {
|
||||||
|
// Waveshare's ESP32-P4-ETH boards have an IP101, which Arduino drives as
|
||||||
|
// the TLK110; the web UI's preset stores 1.
|
||||||
|
eth_phy_type_t type = ETH_PHY_MAX;
|
||||||
|
TEST_ASSERT_TRUE(ethPhyType(1, type));
|
||||||
|
TEST_ASSERT_EQUAL(ETH_PHY_TLK110, type);
|
||||||
|
}
|
||||||
|
static void test_clock_in_is_ext_in() {
|
||||||
|
// A cast would give the IDF's deprecated EMAC_CLK_DEFAULT.
|
||||||
|
eth_clock_mode_t mode = EMAC_CLK_DEFAULT;
|
||||||
|
TEST_ASSERT_TRUE(ethClockMode(static_cast<uint8_t>(eth_clock_id_t::GPIO0_IN), mode));
|
||||||
|
TEST_ASSERT_EQUAL(EMAC_CLK_EXT_IN, mode);
|
||||||
|
}
|
||||||
|
static void test_rejects_clock_out() {
|
||||||
|
// ETH.begin() keeps the clock on GPIO 50, which only takes a clock in.
|
||||||
|
eth_clock_mode_t mode;
|
||||||
|
TEST_ASSERT_FALSE(ethClockMode(1, mode));
|
||||||
|
TEST_ASSERT_FALSE(ethClockMode(2, mode));
|
||||||
|
TEST_ASSERT_FALSE(ethClockMode(3, mode));
|
||||||
|
TEST_ASSERT_FALSE(ethClockMode(4, mode));
|
||||||
|
}
|
||||||
|
static void test_a_save_takes_clock_in_only() {
|
||||||
|
// ProtoSettings refuses a CLKMode over this, so a save can't store a mode
|
||||||
|
// that stops Ethernet at the next start.
|
||||||
|
eth_clock_mode_t mode;
|
||||||
|
TEST_ASSERT_EQUAL_UINT8(0, ETH_CLOCK_ID_MAX);
|
||||||
|
TEST_ASSERT_TRUE(ethClockMode(ETH_CLOCK_ID_MAX, mode));
|
||||||
|
TEST_ASSERT_FALSE(ethClockMode(ETH_CLOCK_ID_MAX + 1, mode));
|
||||||
|
}
|
||||||
|
static void test_clock_pin_is_50() {
|
||||||
|
TEST_ASSERT_EQUAL_INT8(50, ethClockPin(0));
|
||||||
|
TEST_ASSERT_EQUAL_INT8(-1, ethClockPin(1));
|
||||||
|
TEST_ASSERT_EQUAL_INT8(-1, ethClockPin(3));
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int, char **) {
|
||||||
|
UNITY_BEGIN();
|
||||||
|
RUN_TEST(test_builds_with_ethernet);
|
||||||
|
RUN_TEST(test_ip101_is_the_tlk110_id);
|
||||||
|
RUN_TEST(test_clock_in_is_ext_in);
|
||||||
|
RUN_TEST(test_rejects_clock_out);
|
||||||
|
RUN_TEST(test_a_save_takes_clock_in_only);
|
||||||
|
RUN_TEST(test_clock_pin_is_50);
|
||||||
|
return UNITY_END();
|
||||||
|
}
|
||||||
|
|
@ -93,11 +93,18 @@ static void test_whole_numbers_are_checked_against_what_the_setting_holds() {
|
||||||
TEST_ASSERT_EQUAL_STRING("connMode must be 1-3", expand(R"({"se":"network","cn":0})"));
|
TEST_ASSERT_EQUAL_STRING("connMode must be 1-3", expand(R"({"se":"network","cn":0})"));
|
||||||
TEST_ASSERT_EQUAL_STRING("port must be 1-65535", expand(R"({"se":"mqtt","po":65536})"));
|
TEST_ASSERT_EQUAL_STRING("port must be 1-65535", expand(R"({"se":"mqtt","po":65536})"));
|
||||||
TEST_ASSERT_EQUAL_STRING("txPower must be -30-12", expand(R"({"se":"radio","tp":13})"));
|
TEST_ASSERT_EQUAL_STRING("txPower must be -30-12", expand(R"({"se":"radio","tp":13})"));
|
||||||
TEST_ASSERT_EQUAL_STRING("TXPin must be 0-48", expand(R"({"se":"radio","tx":-1})"));
|
TEST_ASSERT_EQUAL_STRING("TXPin must be 0-54", expand(R"({"se":"radio","tx":-1})"));
|
||||||
TEST_ASSERT_EQUAL_STRING("securityType must be 0-2", expand(R"({"se":"security","sy":3})"));
|
TEST_ASSERT_EQUAL_STRING("securityType must be 0-2", expand(R"({"se":"security","sy":3})"));
|
||||||
TEST_ASSERT_EQUAL_STRING("port must be 1-65535", expand(R"({"se":"mqtt","po":18446744073709551615})"));
|
TEST_ASSERT_EQUAL_STRING("port must be 1-65535", expand(R"({"se":"mqtt","po":18446744073709551615})"));
|
||||||
// A pin of -1 is none.
|
// A pin of -1 is none.
|
||||||
TEST_ASSERT_GOOD(expand(R"({"se":"network","pw":-1})"));
|
TEST_ASSERT_GOOD(expand(R"({"se":"network","pw":-1})"));
|
||||||
|
// Pins run to GPIO 54, the P4's last.
|
||||||
|
TEST_ASSERT_GOOD(expand(R"({"se":"radio","tx":54})"));
|
||||||
|
TEST_ASSERT_EQUAL_STRING("TXPin must be 0-54", expand(R"({"se":"radio","tx":55})"));
|
||||||
|
TEST_ASSERT_GOOD(expand(R"({"se":"network","mi":54})"));
|
||||||
|
// The ESP32's four clock modes; a P4 build takes 0 only (ETH_CLOCK_ID_MAX).
|
||||||
|
TEST_ASSERT_GOOD(expand(R"({"se":"network","ck":3})"));
|
||||||
|
TEST_ASSERT_EQUAL_STRING("CLKMode must be 0-3", expand(R"({"se":"network","ck":4})"));
|
||||||
TEST_ASSERT_GOOD(expand(R"({"se":"radio","tp":-30})"));
|
TEST_ASSERT_GOOD(expand(R"({"se":"radio","tp":-30})"));
|
||||||
}
|
}
|
||||||
static void test_the_bit_length_is_56_or_80() {
|
static void test_the_bit_length_is_56_or_80() {
|
||||||
|
|
|
||||||
|
|
@ -284,6 +284,10 @@ static void test_releaseAssetName_matches_the_release_workflow() {
|
||||||
TEST_ASSERT_EQUAL_STRING("SomfyController.ino.esp32c5.bin", buf);
|
TEST_ASSERT_EQUAL_STRING("SomfyController.ino.esp32c5.bin", buf);
|
||||||
releaseAssetName(buf, sizeof(buf), "littlefs", "c6");
|
releaseAssetName(buf, sizeof(buf), "littlefs", "c6");
|
||||||
TEST_ASSERT_EQUAL_STRING("SomfyController.littlefs.esp32c6.bin", buf);
|
TEST_ASSERT_EQUAL_STRING("SomfyController.littlefs.esp32c6.bin", buf);
|
||||||
|
releaseAssetName(buf, sizeof(buf), "ino", "p4");
|
||||||
|
TEST_ASSERT_EQUAL_STRING("SomfyController.ino.esp32p4.bin", buf);
|
||||||
|
releaseAssetName(buf, sizeof(buf), "littlefs", "p4es");
|
||||||
|
TEST_ASSERT_EQUAL_STRING("SomfyController.littlefs.esp32p4es.bin", buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*********************************************************************
|
/*********************************************************************
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue