Merge branch 'master' into release/v3.3.x

This commit is contained in:
Me No Dev 2025-06-10 13:28:31 +03:00 committed by GitHub
commit aaeabb5b87
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 383 additions and 115 deletions

View file

@ -342,12 +342,14 @@ jq_arg=".packages[0].platforms[0].version = \"$RELEASE_TAG\" | \
echo "Generating $PACKAGE_JSON_DEV ..."
cat "$PACKAGE_JSON_TEMPLATE" | jq "$jq_arg" > "$OUTPUT_DIR/$PACKAGE_JSON_DEV"
# On MacOS the sed command won't skip the first match. Use gsed instead.
sed '0,/github\.com\/espressif\//!s|github\.com/espressif/|dl.espressif.cn/github_assets/espressif/|g' "$OUTPUT_DIR/$PACKAGE_JSON_DEV" > "$OUTPUT_DIR/$PACKAGE_JSON_DEV_CN"
sed '0,/github\.com\//!s|github\.com/|dl.espressif.cn/github_assets/|g' "$OUTPUT_DIR/$PACKAGE_JSON_DEV" > "$OUTPUT_DIR/$PACKAGE_JSON_DEV_CN"
python "$SCRIPTS_DIR/release_append_cn.py" "$OUTPUT_DIR/$PACKAGE_JSON_DEV_CN"
if [ "$RELEASE_PRE" == "false" ]; then
echo "Generating $PACKAGE_JSON_REL ..."
cat "$PACKAGE_JSON_TEMPLATE" | jq "$jq_arg" > "$OUTPUT_DIR/$PACKAGE_JSON_REL"
# On MacOS the sed command won't skip the first match. Use gsed instead.
sed '0,/github\.com\/espressif\//!s|github\.com/espressif/|dl.espressif.cn/github_assets/espressif/|g' "$OUTPUT_DIR/$PACKAGE_JSON_REL" > "$OUTPUT_DIR/$PACKAGE_JSON_REL_CN"
sed '0,/github\.com\//!s|github\.com/|dl.espressif.cn/github_assets/|g' "$OUTPUT_DIR/$PACKAGE_JSON_REL" > "$OUTPUT_DIR/$PACKAGE_JSON_REL_CN"
python "$SCRIPTS_DIR/release_append_cn.py" "$OUTPUT_DIR/$PACKAGE_JSON_REL_CN"
fi
# Figure out the last release or pre-release
@ -456,14 +458,14 @@ echo "Uploading $PACKAGE_JSON_DEV ..."
echo "Download URL: $(git_safe_upload_asset "$OUTPUT_DIR/$PACKAGE_JSON_DEV")"
echo "Pages URL: $(git_safe_upload_to_pages "$PACKAGE_JSON_DEV" "$OUTPUT_DIR/$PACKAGE_JSON_DEV")"
echo "Download CN URL: $(git_safe_upload_asset "$OUTPUT_DIR/$PACKAGE_JSON_DEV_CN")"
echo "Pages CN URL: $(git_safe_upload_to_pages "$PACKAGE_JSON_DEV" "$OUTPUT_DIR/$PACKAGE_JSON_DEV_CN")"
echo "Pages CN URL: $(git_safe_upload_to_pages "$PACKAGE_JSON_DEV_CN" "$OUTPUT_DIR/$PACKAGE_JSON_DEV_CN")"
echo
if [ "$RELEASE_PRE" == "false" ]; then
echo "Uploading $PACKAGE_JSON_REL ..."
echo "Download URL: $(git_safe_upload_asset "$OUTPUT_DIR/$PACKAGE_JSON_REL")"
echo "Pages URL: $(git_safe_upload_to_pages "$PACKAGE_JSON_REL" "$OUTPUT_DIR/$PACKAGE_JSON_REL")"
echo "Download CN URL: $(git_safe_upload_asset "$OUTPUT_DIR/$PACKAGE_JSON_REL_CN")"
echo "Pages CN URL: $(git_safe_upload_to_pages "$PACKAGE_JSON_REL" "$OUTPUT_DIR/$PACKAGE_JSON_REL_CN")"
echo "Pages CN URL: $(git_safe_upload_to_pages "$PACKAGE_JSON_REL_CN" "$OUTPUT_DIR/$PACKAGE_JSON_REL_CN")"
echo
fi

56
.github/scripts/release_append_cn.py vendored Executable file
View file

@ -0,0 +1,56 @@
#!/usr/bin/env python3
# Arduino IDE provides by default a package file for the ESP32. This causes version conflicts
# when the user tries to use the JSON file with the Chinese mirrors.
#
# The downside is that the Arduino IDE will always warn the user that updates are available as it
# will consider the version from the Chinese mirrors as a pre-release version.
#
# This script is used to append "-cn" to all versions in the package_esp32_index_cn.json file so that
# the user can select the Chinese mirrors without conflicts.
#
# If Arduino ever stops providing the package_esp32_index.json file by default,
# this script can be removed and the tags reverted.
import json
def append_cn_to_versions(obj):
if isinstance(obj, dict):
# dfu-util comes from arduino.cc and not from the Chinese mirrors, so we skip it
if obj.get("name") == "dfu-util":
return
for key, value in obj.items():
if key == "version" and isinstance(value, str):
if not value.endswith("-cn"):
obj[key] = value + "-cn"
else:
append_cn_to_versions(value)
elif isinstance(obj, list):
for item in obj:
append_cn_to_versions(item)
def process_json_file(input_path, output_path=None):
with open(input_path, "r", encoding="utf-8") as f:
data = json.load(f)
append_cn_to_versions(data)
if output_path is None:
output_path = input_path
with open(output_path, "w", encoding="utf-8") as f:
json.dump(data, f, indent=2)
print(f"Updated JSON written to {output_path}")
if __name__ == "__main__":
import sys
if len(sys.argv) < 2:
print("Usage: python release_append_cn.py input.json [output.json]")
else:
input_file = sys.argv[1]
output_file = sys.argv[2] if len(sys.argv) > 2 else None
process_json_file(input_file, output_file)

View file

@ -44,16 +44,17 @@ jobs:
gh api "$artifacts_url" -q '.artifacts[] | [.name, .archive_download_url] | @tsv' | while read artifact
do
IFS=$'\t' read name url <<< "$artifact"
# Only process pr_number and pr_cli_compile artifacts
if [[ "$name" == "pr_number" || "$name" =~ ^pr_cli_compile_[0-9]+$ ]]; then
gh api $url > "$name.zip"
unzip -j "$name.zip" -d "temp_$name"
unzip -o -j "$name.zip" -d "temp_$name"
if [[ "$name" == "pr_number" ]]; then
mv "temp_$name"/* sizes-report
elif [[ "$name" == "pr_cli"* ]]; then
elif [[ "$name" =~ ^pr_cli_compile_[0-9]+$ ]]; then
mv "temp_$name"/* sizes-report/pr
else
mv "temp_$name"/* sizes-report
fi
rm -r "temp_$name"
fi
done
echo "Contents of parent directory:"
ls -R ..

View file

@ -493,6 +493,15 @@ esp32p4.menu.PartitionScheme.fatflash.upload.maximum_size=2097152
esp32p4.menu.PartitionScheme.app3M_fat9M_16MB=16M Flash (3MB APP/9.9MB FATFS)
esp32p4.menu.PartitionScheme.app3M_fat9M_16MB.build.partitions=app3M_fat9M_16MB
esp32p4.menu.PartitionScheme.app3M_fat9M_16MB.upload.maximum_size=3145728
esp32p4.menu.PartitionScheme.app5M_fat24M_32MB=32M Flash (4.8MB APP/22MB FATFS)
esp32p4.menu.PartitionScheme.app5M_fat24M_32MB.build.partitions=large_fat_32MB
esp32p4.menu.PartitionScheme.app5M_fat24M_32MB.upload.maximum_size=4718592
esp32p4.menu.PartitionScheme.app5M_little24M_32MB=32M Flash (4.8MB APP/22MB LittleFS)
esp32p4.menu.PartitionScheme.app5M_little24M_32MB.build.partitions=large_littlefs_32MB
esp32p4.menu.PartitionScheme.app5M_little24M_32MB.upload.maximum_size=4718592
esp32p4.menu.PartitionScheme.app13M_data7M_32MB=32M Flash (13MB APP/6.75MB SPIFFS)
esp32p4.menu.PartitionScheme.app13M_data7M_32MB.build.partitions=default_32MB
esp32p4.menu.PartitionScheme.app13M_data7M_32MB.upload.maximum_size=13107200
esp32p4.menu.PartitionScheme.custom=Custom
esp32p4.menu.PartitionScheme.custom.build.partitions=
esp32p4.menu.PartitionScheme.custom.upload.maximum_size=16777216
@ -525,6 +534,8 @@ esp32p4.menu.FlashSize.2M.build.flash_size=2MB
esp32p4.menu.FlashSize.2M.build.partitions=minimal
esp32p4.menu.FlashSize.16M=16MB (128Mb)
esp32p4.menu.FlashSize.16M.build.flash_size=16MB
esp32p4.menu.FlashSize.32M=32MB (256Mb)
esp32p4.menu.FlashSize.32M.build.flash_size=32MB
esp32p4.menu.UploadSpeed.921600=921600
esp32p4.menu.UploadSpeed.921600.upload.speed=921600
@ -31724,16 +31735,16 @@ wifiduino32c3.build.target=esp
wifiduino32c3.build.mcu=esp32c3
wifiduino32c3.build.core=esp32
wifiduino32c3.build.variant=wifiduinov2
wifiduino32c3.build.board=WiFiduinoV2
wifiduino32c3.build.board=WIFIDUINOV2
wifiduino32c3.build.bootloader_addr=0x0
wifiduino32c3.build.cdc_on_boot=0
wifiduino32c3.build.f_cpu=160000000L
wifiduino32c3.build.flash_size=4MB
wifiduino32c3.build.flash_freq=80m
wifiduino32c3.build.flash_mode=qio
wifiduino32c3.build.boot=qio
wifiduino32c3.build.partitions=default
wifiduino32c3.build.flash_mode=dio
wifiduino32c3.build.boot=dio
wifiduino32c3.build.partitions=no_ota
wifiduino32c3.build.defines=
wifiduino32c3.menu.CDCOnBoot.default=Disabled
@ -31741,6 +31752,9 @@ wifiduino32c3.menu.CDCOnBoot.default.build.cdc_on_boot=0
wifiduino32c3.menu.CDCOnBoot.cdc=Enabled
wifiduino32c3.menu.CDCOnBoot.cdc.build.cdc_on_boot=1
wifiduino32c3.menu.PartitionScheme.no_ota=No OTA (2MB APP/2MB SPIFFS)
wifiduino32c3.menu.PartitionScheme.no_ota.build.partitions=no_ota
wifiduino32c3.menu.PartitionScheme.no_ota.upload.maximum_size=2097152
wifiduino32c3.menu.PartitionScheme.default=Default 4MB with spiffs (1.2MB APP/1.5MB SPIFFS)
wifiduino32c3.menu.PartitionScheme.default.build.partitions=default
wifiduino32c3.menu.PartitionScheme.defaultffat=Default 4MB with ffat (1.2MB APP/1.5MB FATFS)
@ -31750,9 +31764,6 @@ wifiduino32c3.menu.PartitionScheme.default_8MB.build.partitions=default_8MB
wifiduino32c3.menu.PartitionScheme.default_8MB.upload.maximum_size=3342336
wifiduino32c3.menu.PartitionScheme.minimal=Minimal (1.3MB APP/700KB SPIFFS)
wifiduino32c3.menu.PartitionScheme.minimal.build.partitions=minimal
wifiduino32c3.menu.PartitionScheme.no_ota=No OTA (2MB APP/2MB SPIFFS)
wifiduino32c3.menu.PartitionScheme.no_ota.build.partitions=no_ota
wifiduino32c3.menu.PartitionScheme.no_ota.upload.maximum_size=2097152
wifiduino32c3.menu.PartitionScheme.noota_3g=No OTA (1MB APP/3MB SPIFFS)
wifiduino32c3.menu.PartitionScheme.noota_3g.build.partitions=noota_3g
wifiduino32c3.menu.PartitionScheme.noota_3g.upload.maximum_size=1048576
@ -31795,12 +31806,12 @@ wifiduino32c3.menu.CPUFreq.20.build.f_cpu=20000000L
wifiduino32c3.menu.CPUFreq.10=10MHz
wifiduino32c3.menu.CPUFreq.10.build.f_cpu=10000000L
wifiduino32c3.menu.FlashMode.qio=QIO
wifiduino32c3.menu.FlashMode.qio.build.flash_mode=dio
wifiduino32c3.menu.FlashMode.qio.build.boot=qio
wifiduino32c3.menu.FlashMode.dio=DIO
wifiduino32c3.menu.FlashMode.dio.build.flash_mode=dio
wifiduino32c3.menu.FlashMode.dio.build.boot=dio
wifiduino32c3.menu.FlashMode.qio=QIO
wifiduino32c3.menu.FlashMode.qio.build.flash_mode=dio
wifiduino32c3.menu.FlashMode.qio.build.boot=qio
wifiduino32c3.menu.FlashFreq.80=80MHz
wifiduino32c3.menu.FlashFreq.80.build.flash_freq=80m
@ -31876,34 +31887,34 @@ wifiduino32s3.build.target=esp32s3
wifiduino32s3.build.mcu=esp32s3
wifiduino32s3.build.core=esp32
wifiduino32s3.build.variant=wifiduino32s3
wifiduino32s3.build.board=WiFiduino32S3
wifiduino32s3.build.board=WIFIDUINO32S3
wifiduino32s3.build.usb_mode=1
wifiduino32s3.build.cdc_on_boot=0
wifiduino32s3.build.msc_on_boot=0
wifiduino32s3.build.dfu_on_boot=0
wifiduino32s3.build.f_cpu=240000000L
wifiduino32s3.build.flash_size=4MB
wifiduino32s3.build.flash_size=16MB
wifiduino32s3.build.flash_freq=80m
wifiduino32s3.build.flash_mode=dio
wifiduino32s3.build.boot=qio
wifiduino32s3.build.boot_freq=80m
wifiduino32s3.build.partitions=default
wifiduino32s3.build.partitions=app3M_fat9M_16MB
wifiduino32s3.build.defines=
wifiduino32s3.build.loop_core=
wifiduino32s3.build.event_core=
wifiduino32s3.build.psram_type=qspi
wifiduino32s3.build.psram_type=opi
wifiduino32s3.build.memory_type={build.boot}_{build.psram_type}
wifiduino32s3.menu.PSRAM.opi=OPI PSRAM
wifiduino32s3.menu.PSRAM.opi.build.defines=-DBOARD_HAS_PSRAM
wifiduino32s3.menu.PSRAM.opi.build.psram_type=opi
wifiduino32s3.menu.PSRAM.disabled=Disabled
wifiduino32s3.menu.PSRAM.disabled.build.defines=
wifiduino32s3.menu.PSRAM.disabled.build.psram_type=qspi
wifiduino32s3.menu.PSRAM.enabled=QSPI PSRAM
wifiduino32s3.menu.PSRAM.enabled.build.defines=-DBOARD_HAS_PSRAM
wifiduino32s3.menu.PSRAM.enabled.build.psram_type=qspi
wifiduino32s3.menu.PSRAM.opi=OPI PSRAM
wifiduino32s3.menu.PSRAM.opi.build.defines=-DBOARD_HAS_PSRAM
wifiduino32s3.menu.PSRAM.opi.build.psram_type=opi
wifiduino32s3.menu.FlashMode.qio=QIO 80MHz
wifiduino32s3.menu.FlashMode.qio.build.flash_mode=dio
@ -31926,12 +31937,10 @@ wifiduino32s3.menu.FlashMode.opi.build.boot=opi
wifiduino32s3.menu.FlashMode.opi.build.boot_freq=80m
wifiduino32s3.menu.FlashMode.opi.build.flash_freq=80m
wifiduino32s3.menu.FlashSize.4M=4MB (32Mb)
wifiduino32s3.menu.FlashSize.4M.build.flash_size=4MB
wifiduino32s3.menu.FlashSize.8M=8MB (64Mb)
wifiduino32s3.menu.FlashSize.8M.build.flash_size=8MB
wifiduino32s3.menu.FlashSize.16M=16MB (128Mb)
wifiduino32s3.menu.FlashSize.16M.build.flash_size=16MB
wifiduino32s3.menu.FlashSize.8M=8MB (64Mb)
wifiduino32s3.menu.FlashSize.8M.build.flash_size=8MB
#wifiduino32s3.menu.FlashSize.32M=32MB (256Mb)
#wifiduino32s3.menu.FlashSize.32M.build.flash_size=32MB
@ -31972,6 +31981,9 @@ wifiduino32s3.menu.UploadMode.cdc=USB-OTG CDC (TinyUSB)
wifiduino32s3.menu.UploadMode.cdc.upload.use_1200bps_touch=true
wifiduino32s3.menu.UploadMode.cdc.upload.wait_for_upload_port=true
wifiduino32s3.menu.PartitionScheme.app3M_fat9M_16MB=16M Flash (3MB APP/9.9MB FATFS)
wifiduino32s3.menu.PartitionScheme.app3M_fat9M_16MB.build.partitions=app3M_fat9M_16MB
wifiduino32s3.menu.PartitionScheme.app3M_fat9M_16MB.upload.maximum_size=3145728
wifiduino32s3.menu.PartitionScheme.default=Default 4MB with spiffs (1.2MB APP/1.5MB SPIFFS)
wifiduino32s3.menu.PartitionScheme.default.build.partitions=default
wifiduino32s3.menu.PartitionScheme.defaultffat=Default 4MB with ffat (1.2MB APP/1.5MB FATFS)
@ -32002,9 +32014,6 @@ wifiduino32s3.menu.PartitionScheme.min_spiffs.upload.maximum_size=1966080
wifiduino32s3.menu.PartitionScheme.fatflash=16M Flash (2MB APP/12.5MB FATFS)
wifiduino32s3.menu.PartitionScheme.fatflash.build.partitions=ffat
wifiduino32s3.menu.PartitionScheme.fatflash.upload.maximum_size=2097152
wifiduino32s3.menu.PartitionScheme.app3M_fat9M_16MB=16M Flash (3MB APP/9.9MB FATFS)
wifiduino32s3.menu.PartitionScheme.app3M_fat9M_16MB.build.partitions=app3M_fat9M_16MB
wifiduino32s3.menu.PartitionScheme.app3M_fat9M_16MB.upload.maximum_size=3145728
wifiduino32s3.menu.PartitionScheme.rainmaker=RainMaker 4MB
wifiduino32s3.menu.PartitionScheme.rainmaker.build.partitions=rainmaker
wifiduino32s3.menu.PartitionScheme.rainmaker.upload.maximum_size=1966080
@ -41800,11 +41809,6 @@ Geekble_ESP32C3.build.boot=qio
Geekble_ESP32C3.build.partitions=default
Geekble_ESP32C3.build.defines=
Geekble_ESP32C3.menu.CDCOnBoot.default=Enabled
Geekble_ESP32C3.menu.CDCOnBoot.default.build.cdc_on_boot=1
Geekble_ESP32C3.menu.CDCOnBoot.cdc=Disabled
Geekble_ESP32C3.menu.CDCOnBoot.cdc.build.cdc_on_boot=0
Geekble_ESP32C3.menu.PartitionScheme.default=Default 4MB with spiffs (1.2MB APP/1.5MB SPIFFS)
Geekble_ESP32C3.menu.PartitionScheme.default.build.partitions=default
Geekble_ESP32C3.menu.PartitionScheme.defaultffat=Default 4MB with ffat (1.2MB APP/1.5MB FATFS)
@ -41825,39 +41829,6 @@ Geekble_ESP32C3.menu.PartitionScheme.huge_app=Huge APP (3MB No OTA/1MB SPIFFS)
Geekble_ESP32C3.menu.PartitionScheme.huge_app.build.partitions=huge_app
Geekble_ESP32C3.menu.PartitionScheme.huge_app.upload.maximum_size=3145728
Geekble_ESP32C3.menu.CPUFreq.160=160MHz (WiFi) (Default)
Geekble_ESP32C3.menu.CPUFreq.160.build.f_cpu=160000000L
Geekble_ESP32C3.menu.CPUFreq.80=80MHz (WiFi)
Geekble_ESP32C3.menu.CPUFreq.80.build.f_cpu=80000000L
Geekble_ESP32C3.menu.CPUFreq.40=40MHz
Geekble_ESP32C3.menu.CPUFreq.40.build.f_cpu=40000000L
Geekble_ESP32C3.menu.CPUFreq.20=20MHz
Geekble_ESP32C3.menu.CPUFreq.20.build.f_cpu=20000000L
Geekble_ESP32C3.menu.CPUFreq.10=10MHz
Geekble_ESP32C3.menu.CPUFreq.10.build.f_cpu=10000000L
Geekble_ESP32C3.menu.FlashMode.qio=QIO (Default)
Geekble_ESP32C3.menu.FlashMode.qio.build.flash_mode=dio
Geekble_ESP32C3.menu.FlashMode.qio.build.boot=qio
Geekble_ESP32C3.menu.FlashMode.dio=DIO
Geekble_ESP32C3.menu.FlashMode.dio.build.flash_mode=dio
Geekble_ESP32C3.menu.FlashMode.dio.build.boot=dio
Geekble_ESP32C3.menu.FlashMode.qout=QOUT
Geekble_ESP32C3.menu.FlashMode.qout.build.flash_mode=dout
Geekble_ESP32C3.menu.FlashMode.qout.build.boot=qout
Geekble_ESP32C3.menu.FlashMode.dout=DOUT
Geekble_ESP32C3.menu.FlashMode.dout.build.flash_mode=dout
Geekble_ESP32C3.menu.FlashFreq.80=80MHz (Default)
Geekble_ESP32C3.menu.FlashFreq.80.build.flash_freq=80m
Geekble_ESP32C3.menu.FlashFreq.40=40MHz
Geekble_ESP32C3.menu.FlashFreq.40.build.flash_freq=40m
Geekble_ESP32C3.menu.FlashSize.4M=4MB (Default)
Geekble_ESP32C3.menu.FlashSize.4M.build.flash_size=4MB
Geekble_ESP32C3.menu.FlashSize.2M=2MB
Geekble_ESP32C3.menu.FlashSize.2M.build.flash_size=2MB
Geekble_ESP32C3.menu.UploadSpeed.921600=921600 (Default)
Geekble_ESP32C3.menu.UploadSpeed.921600.upload.speed=921600
Geekble_ESP32C3.menu.UploadSpeed.115200=115200

View file

@ -45,6 +45,93 @@ typedef struct {
ledc_periph_t ledc_handle = {0};
// Helper function to find a timer with matching frequency and resolution
static bool find_matching_timer(uint8_t speed_mode, uint32_t freq, uint8_t resolution, uint8_t *timer_num) {
log_d("Searching for timer with freq=%u, resolution=%u", freq, resolution);
// Check all channels to find one with matching frequency and resolution
for (uint8_t i = 0; i < SOC_GPIO_PIN_COUNT; i++) {
if (!perimanPinIsValid(i)) {
continue;
}
peripheral_bus_type_t type = perimanGetPinBusType(i);
if (type == ESP32_BUS_TYPE_LEDC) {
ledc_channel_handle_t *bus = (ledc_channel_handle_t *)perimanGetPinBus(i, ESP32_BUS_TYPE_LEDC);
if (bus != NULL && (bus->channel / 8) == speed_mode && bus->freq_hz == freq && bus->channel_resolution == resolution) {
log_d("Found matching timer %u for freq=%u, resolution=%u", bus->timer_num, freq, resolution);
*timer_num = bus->timer_num;
return true;
}
}
}
log_d("No matching timer found for freq=%u, resolution=%u", freq, resolution);
return false;
}
// Helper function to find an unused timer
static bool find_free_timer(uint8_t speed_mode, uint8_t *timer_num) {
// Check which timers are in use
uint8_t used_timers = 0;
for (uint8_t i = 0; i < SOC_GPIO_PIN_COUNT; i++) {
if (!perimanPinIsValid(i)) {
continue;
}
peripheral_bus_type_t type = perimanGetPinBusType(i);
if (type == ESP32_BUS_TYPE_LEDC) {
ledc_channel_handle_t *bus = (ledc_channel_handle_t *)perimanGetPinBus(i, ESP32_BUS_TYPE_LEDC);
if (bus != NULL && (bus->channel / 8) == speed_mode) {
log_d("Timer %u is in use by channel %u", bus->timer_num, bus->channel);
used_timers |= (1 << bus->timer_num);
}
}
}
// Find first unused timer
for (uint8_t i = 0; i < SOC_LEDC_TIMER_NUM; i++) {
if (!(used_timers & (1 << i))) {
log_d("Found free timer %u", i);
*timer_num = i;
return true;
}
}
log_e("No free timers available");
return false;
}
// Helper function to remove a channel from a timer and clear timer if no channels are using it
static void remove_channel_from_timer(uint8_t speed_mode, uint8_t timer_num, uint8_t channel) {
log_d("Removing channel %u from timer %u in speed_mode %u", channel, timer_num, speed_mode);
// Check if any other channels are using this timer
bool timer_in_use = false;
for (uint8_t i = 0; i < SOC_GPIO_PIN_COUNT; i++) {
if (!perimanPinIsValid(i)) {
continue;
}
peripheral_bus_type_t type = perimanGetPinBusType(i);
if (type == ESP32_BUS_TYPE_LEDC) {
ledc_channel_handle_t *bus = (ledc_channel_handle_t *)perimanGetPinBus(i, ESP32_BUS_TYPE_LEDC);
if (bus != NULL && (bus->channel / 8) == speed_mode && bus->timer_num == timer_num && bus->channel != channel) {
log_d("Timer %u is still in use by channel %u", timer_num, bus->channel);
timer_in_use = true;
break;
}
}
}
if (!timer_in_use) {
log_d("No other channels using timer %u, deconfiguring timer", timer_num);
// Stop the timer
ledc_timer_pause(speed_mode, timer_num);
// Deconfigure the timer
ledc_timer_config_t ledc_timer;
memset((void *)&ledc_timer, 0, sizeof(ledc_timer_config_t));
ledc_timer.speed_mode = speed_mode;
ledc_timer.timer_num = timer_num;
ledc_timer.deconfigure = true;
ledc_timer_config(&ledc_timer);
}
}
static bool fade_initialized = false;
static ledc_clk_cfg_t clock_source = LEDC_DEFAULT_CLK;
@ -81,6 +168,8 @@ static bool ledcDetachBus(void *bus) {
}
pinMatrixOutDetach(handle->pin, false, false);
if (!channel_found) {
uint8_t group = (handle->channel / 8);
remove_channel_from_timer(group, handle->timer_num, handle->channel % 8);
ledc_handle.used_channels &= ~(1UL << handle->channel);
}
free(handle);
@ -117,8 +206,10 @@ bool ledcAttachChannel(uint8_t pin, uint32_t freq, uint8_t resolution, uint8_t c
return false;
}
uint8_t group = (channel / 8), timer = ((channel / 2) % 4);
uint8_t group = (channel / 8);
uint8_t timer = 0;
bool channel_used = ledc_handle.used_channels & (1UL << channel);
if (channel_used) {
log_i("Channel %u is already set up, given frequency and resolution will be ignored", channel);
if (ledc_set_pin(pin, group, channel % 8) != ESP_OK) {
@ -126,6 +217,14 @@ bool ledcAttachChannel(uint8_t pin, uint32_t freq, uint8_t resolution, uint8_t c
return false;
}
} else {
// Find a timer with matching frequency and resolution, or a free timer
if (!find_matching_timer(group, freq, resolution, &timer)) {
if (!find_free_timer(group, &timer)) {
log_e("No free timers available for speed mode %u", group);
return false;
}
// Configure the timer if we're using a new one
ledc_timer_config_t ledc_timer;
memset((void *)&ledc_timer, 0, sizeof(ledc_timer_config_t));
ledc_timer.speed_mode = group;
@ -138,6 +237,7 @@ bool ledcAttachChannel(uint8_t pin, uint32_t freq, uint8_t resolution, uint8_t c
log_e("ledc setup failed!");
return false;
}
}
uint32_t duty = ledc_get_duty(group, (channel % 8));
@ -157,6 +257,8 @@ bool ledcAttachChannel(uint8_t pin, uint32_t freq, uint8_t resolution, uint8_t c
ledc_channel_handle_t *handle = (ledc_channel_handle_t *)malloc(sizeof(ledc_channel_handle_t));
handle->pin = pin;
handle->channel = channel;
handle->timer_num = timer;
handle->freq_hz = freq;
#ifndef SOC_LEDC_SUPPORT_FADE_STOP
handle->lock = NULL;
#endif

View file

@ -51,6 +51,8 @@ typedef struct {
uint8_t pin; // Pin assigned to channel
uint8_t channel; // Channel number
uint8_t channel_resolution; // Resolution of channel
uint8_t timer_num; // Timer number used by this channel
uint32_t freq_hz; // Frequency configured for this channel
voidFuncPtr fn;
void *arg;
#ifndef SOC_LEDC_SUPPORT_FADE_STOP

View file

@ -25,7 +25,7 @@
#include "esp_ota_ops.h"
#endif //CONFIG_APP_ROLLBACK_ENABLE
#include "esp_private/startup_internal.h"
#if defined(CONFIG_BT_BLUEDROID_ENABLED) && SOC_BT_SUPPORTED
#if defined(CONFIG_BT_BLUEDROID_ENABLED) && SOC_BT_SUPPORTED && __has_include("esp_bt.h")
#include "esp_bt.h"
#endif //CONFIG_BT_BLUEDROID_ENABLED
#include <sys/time.h>

View file

@ -70,6 +70,8 @@ To start the installation process using the Boards Manager, follow these steps:
:figclass: align-center
- Open Boards Manager from Tools > Board menu and install *esp32* platform (and do not forget to select your ESP32 board from Tools > Board menu after installation).
Users in China must select the package version with the "-cn" suffix and perform updates manually.
Automatic updates are not supported in this region, as they target the default package without the "-cn" suffix, resulting in download failures.
.. figure:: ../_static/install_guide_boards_manager_esp32.png
:align: center

View file

@ -682,6 +682,8 @@ igmp_fail:
}
bool AsyncUDP::listenMulticast(const ip_addr_t *addr, uint16_t port, uint8_t ttl, tcpip_adapter_if_t tcpip_if) {
ip_addr_t bind_addr;
if (!ip_addr_ismulticast(addr)) {
return false;
}
@ -690,7 +692,18 @@ bool AsyncUDP::listenMulticast(const ip_addr_t *addr, uint16_t port, uint8_t ttl
return false;
}
if (!listen(NULL, port)) {
#if CONFIG_LWIP_IPV6
if (IP_IS_V6(addr)) {
IP_SET_TYPE(&bind_addr, IPADDR_TYPE_V6);
ip6_addr_set_any(&bind_addr.u_addr.ip6);
} else {
#endif
IP_SET_TYPE(&bind_addr, IPADDR_TYPE_V4);
ip4_addr_set_any(&bind_addr.u_addr.ip4);
#if CONFIG_LWIP_IPV6
}
#endif
if (!listen(&bind_addr, port)) {
return false;
}

View file

@ -24,10 +24,17 @@
2nd September 2021
Lucas Saavedra Vaz (lucasssvaz)
22nd December 2023
anon
10nd February 2025
*/
#include <ESP_I2S.h>
// The GPIO pins are not fixed, most other pins could be used for the I2S function.
#define I2S_LRC 25
#define I2S_BCLK 5
#define I2S_DIN 26
const int frequency = 440; // frequency of square wave in Hz
const int amplitude = 500; // amplitude of square wave
const int sampleRate = 8000; // sample rate in Hz
@ -36,10 +43,10 @@ i2s_data_bit_width_t bps = I2S_DATA_BIT_WIDTH_16BIT;
i2s_mode_t mode = I2S_MODE_STD;
i2s_slot_mode_t slot = I2S_SLOT_MODE_STEREO;
const int halfWavelength = (sampleRate / frequency); // half wavelength of square wave
const unsigned int halfWavelength = sampleRate / frequency / 2; // half wavelength of square wave
int32_t sample = amplitude; // current sample value
int count = 0;
unsigned int count = 0;
I2SClass i2s;
@ -47,6 +54,8 @@ void setup() {
Serial.begin(115200);
Serial.println("I2S simple tone");
i2s.setPins(I2S_BCLK, I2S_LRC, I2S_DIN);
// start I2S at the sample rate with 16-bits per sample
if (!i2s.begin(mode, sampleRate, bps, slot)) {
Serial.println("Failed to initialize I2S!");
@ -60,8 +69,13 @@ void loop() {
sample = -1 * sample;
}
i2s.write(sample); // Right channel
i2s.write(sample); // Left channel
// Left channel, the low 8 bits then high 8 bits
i2s.write(sample);
i2s.write(sample >> 8);
// Right channel, the low 8 bits then high 8 bits
i2s.write(sample);
i2s.write(sample >> 8);
// increment the counter for the next sample
count++;

View file

@ -72,6 +72,9 @@ void setup() {
zbAnalogDevice.setAnalogOutputDescription("Fan Speed (RPM)");
zbAnalogDevice.setAnalogOutputResolution(1);
// Set the min and max values for the analog output which is used by HA to limit the range of the analog output
zbAnalogDevice.setAnalogOutputMinMax(-10000, 10000); //-10000 to 10000 RPM
// If analog output cluster is added, set callback function for analog output change
zbAnalogDevice.onAnalogOutputChange(onAnalogOutputChange);

View file

@ -1,5 +1,6 @@
#include "ZigbeeAnalog.h"
#if CONFIG_ZB_ENABLED
#include <cfloat>
ZigbeeAnalog::ZigbeeAnalog(uint8_t endpoint) : ZigbeeEP(endpoint) {
_device_id = ESP_ZB_HA_SIMPLE_SENSOR_DEVICE_ID;
@ -20,6 +21,8 @@ bool ZigbeeAnalog::addAnalogInput() {
"Analog Input";
uint32_t application_type = 0x00000000 | (ESP_ZB_ZCL_AI_GROUP_ID << 24);
float resolution = 0.1; // Default resolution of 0.1
float min = -FLT_MAX; // Default min value for float
float max = FLT_MAX; // Default max value for float
esp_err_t ret = esp_zb_analog_input_cluster_add_attr(esp_zb_analog_input_cluster, ESP_ZB_ZCL_ATTR_ANALOG_INPUT_DESCRIPTION_ID, (void *)default_description);
if (ret != ESP_OK) {
@ -39,11 +42,24 @@ bool ZigbeeAnalog::addAnalogInput() {
return false;
}
ret = esp_zb_analog_input_cluster_add_attr(esp_zb_analog_input_cluster, ESP_ZB_ZCL_ATTR_ANALOG_INPUT_MIN_PRESENT_VALUE_ID, (void *)&min);
if (ret != ESP_OK) {
log_e("Failed to set min value: 0x%x: %s", ret, esp_err_to_name(ret));
return false;
}
ret = esp_zb_analog_input_cluster_add_attr(esp_zb_analog_input_cluster, ESP_ZB_ZCL_ATTR_ANALOG_INPUT_MAX_PRESENT_VALUE_ID, (void *)&max);
if (ret != ESP_OK) {
log_e("Failed to set max value: 0x%x: %s", ret, esp_err_to_name(ret));
return false;
}
ret = esp_zb_cluster_list_add_analog_input_cluster(_cluster_list, esp_zb_analog_input_cluster, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);
if (ret != ESP_OK) {
log_e("Failed to add Analog Input cluster: 0x%x: %s", ret, esp_err_to_name(ret));
return false;
}
_analog_clusters |= ANALOG_INPUT;
return true;
}
@ -76,6 +92,8 @@ bool ZigbeeAnalog::addAnalogOutput() {
"Analog Output";
uint32_t application_type = 0x00000000 | (ESP_ZB_ZCL_AO_GROUP_ID << 24);
float resolution = 1; // Default resolution of 1
float min = -FLT_MAX; // Default min value for float
float max = FLT_MAX; // Default max value for float
esp_err_t ret =
esp_zb_analog_output_cluster_add_attr(esp_zb_analog_output_cluster, ESP_ZB_ZCL_ATTR_ANALOG_OUTPUT_DESCRIPTION_ID, (void *)default_description);
@ -96,6 +114,18 @@ bool ZigbeeAnalog::addAnalogOutput() {
return false;
}
ret = esp_zb_analog_output_cluster_add_attr(esp_zb_analog_output_cluster, ESP_ZB_ZCL_ATTR_ANALOG_OUTPUT_MIN_PRESENT_VALUE_ID, (void *)&min);
if (ret != ESP_OK) {
log_e("Failed to set min value: 0x%x: %s", ret, esp_err_to_name(ret));
return false;
}
ret = esp_zb_analog_output_cluster_add_attr(esp_zb_analog_output_cluster, ESP_ZB_ZCL_ATTR_ANALOG_OUTPUT_MAX_PRESENT_VALUE_ID, (void *)&max);
if (ret != ESP_OK) {
log_e("Failed to set max value: 0x%x: %s", ret, esp_err_to_name(ret));
return false;
}
ret = esp_zb_cluster_list_add_analog_output_cluster(_cluster_list, esp_zb_analog_output_cluster, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);
if (ret != ESP_OK) {
log_e("Failed to add Analog Output cluster: 0x%x: %s", ret, esp_err_to_name(ret));
@ -376,4 +406,58 @@ bool ZigbeeAnalog::setAnalogOutputResolution(float resolution) {
return true;
}
bool ZigbeeAnalog::setAnalogOutputMinMax(float min, float max) {
if (!(_analog_clusters & ANALOG_OUTPUT)) {
log_e("Analog Output cluster not added");
return false;
}
esp_zb_attribute_list_t *analog_output_cluster =
esp_zb_cluster_list_get_cluster(_cluster_list, ESP_ZB_ZCL_CLUSTER_ID_ANALOG_OUTPUT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);
if (analog_output_cluster == nullptr) {
log_e("Failed to get analog output cluster");
return false;
}
esp_err_t ret = esp_zb_cluster_update_attr(analog_output_cluster, ESP_ZB_ZCL_ATTR_ANALOG_OUTPUT_MIN_PRESENT_VALUE_ID, (void *)&min);
if (ret != ESP_OK) {
log_e("Failed to set min value: 0x%x: %s", ret, esp_err_to_name(ret));
return false;
}
ret = esp_zb_cluster_update_attr(analog_output_cluster, ESP_ZB_ZCL_ATTR_ANALOG_OUTPUT_MAX_PRESENT_VALUE_ID, (void *)&max);
if (ret != ESP_OK) {
log_e("Failed to set max value: 0x%x: %s", ret, esp_err_to_name(ret));
return false;
}
return true;
}
bool ZigbeeAnalog::setAnalogInputMinMax(float min, float max) {
if (!(_analog_clusters & ANALOG_INPUT)) {
log_e("Analog Input cluster not added");
return false;
}
esp_zb_attribute_list_t *analog_input_cluster =
esp_zb_cluster_list_get_cluster(_cluster_list, ESP_ZB_ZCL_CLUSTER_ID_ANALOG_INPUT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);
if (analog_input_cluster == nullptr) {
log_e("Failed to get analog input cluster");
return false;
}
esp_err_t ret = esp_zb_cluster_update_attr(analog_input_cluster, ESP_ZB_ZCL_ATTR_ANALOG_INPUT_MIN_PRESENT_VALUE_ID, (void *)&min);
if (ret != ESP_OK) {
log_e("Failed to set min value: 0x%x: %s", ret, esp_err_to_name(ret));
return false;
}
ret = esp_zb_cluster_update_attr(analog_input_cluster, ESP_ZB_ZCL_ATTR_ANALOG_INPUT_MAX_PRESENT_VALUE_ID, (void *)&max);
if (ret != ESP_OK) {
log_e("Failed to set max value: 0x%x: %s", ret, esp_err_to_name(ret));
return false;
}
return true;
}
#endif // CONFIG_ZB_ENABLED

View file

@ -41,6 +41,10 @@ public:
bool setAnalogOutputDescription(const char *description);
bool setAnalogOutputResolution(float resolution);
// Set the min and max values for the analog Input/Output
bool setAnalogOutputMinMax(float min, float max);
bool setAnalogInputMinMax(float min, float max);
// Use to set a cb function to be called on analog output change
void onAnalogOutputChange(void (*callback)(float analog)) {
_on_analog_output_change = callback;

View file

@ -2,43 +2,57 @@
#define Pins_Arduino_h
#include <stdint.h>
#include "soc/soc_caps.h"
#define USB_VID 0x303a
#define USB_PID 0x1001
#define USB_MANUFACTURER "openjumper"
#define USB_PRODUCT "Wifiduino32-S3"
#define USB_SERIAL "" // Empty string for MAC address
// No USER LED or NeoLED
// Some boards have too low voltage on this pin (board design bug)
// Use different pin with 3V and connect with 48
// and change this setup for the chosen pin (for example 38)
#define PIN_RGB_LED 48
// BUILTIN_LED can be used in new Arduino API digitalWrite() like in Blink.ino
static const uint8_t LED_BUILTIN = SOC_GPIO_PIN_COUNT + PIN_RGB_LED;
#define BUILTIN_LED LED_BUILTIN // backward compatibility
#define LED_BUILTIN LED_BUILTIN // allow testing #ifdef LED_BUILTIN
// RGB_BUILTIN and RGB_BRIGHTNESS can be used in new Arduino API rgbLedWrite()
#define RGB_BUILTIN LED_BUILTIN
#define RGB_BRIGHTNESS 64
static const uint8_t TX = 45;
static const uint8_t TX = 43;
static const uint8_t RX = 44;
static const uint8_t SDA = 4;
static const uint8_t SCL = 5;
static const uint8_t SS = 46;
static const uint8_t MOSI = 3;
static const uint8_t MISO = 20;
static const uint8_t SCK = 19;
static const uint8_t SS = 10;
static const uint8_t MOSI = 11;
static const uint8_t MISO = 13;
static const uint8_t SCK = 12;
static const uint8_t A0 = 7;
static const uint8_t A1 = 6;
static const uint8_t A0 = 0;
static const uint8_t A1 = 1;
static const uint8_t A2 = 2;
static const uint8_t A3 = 1;
static const uint8_t A3 = 3;
static const uint8_t A4 = 4;
static const uint8_t A5 = 5;
static const uint8_t D0 = 44;
static const uint8_t D1 = 45;
static const uint8_t D2 = 42;
static const uint8_t D3 = 41;
static const uint8_t D4 = 0;
static const uint8_t D5 = 45;
static const uint8_t D6 = 48;
static const uint8_t D7 = 47;
static const uint8_t D1 = 43;
static const uint8_t D2 = 45;
static const uint8_t D3 = 46;
static const uint8_t D4 = 47;
static const uint8_t D5 = 48;
static const uint8_t D6 = 18;
static const uint8_t D7 = 17;
static const uint8_t D8 = 21;
static const uint8_t D9 = 14;
static const uint8_t D10 = 46;
static const uint8_t D11 = 3;
static const uint8_t D12 = 20;
static const uint8_t D13 = 19;
static const uint8_t D9 = 42;
static const uint8_t D10 = 41;
static const uint8_t D11 = 40;
static const uint8_t D12 = 38;
static const uint8_t D13 = 39;
#endif /* Pins_Arduino_h */