Skip to content
3 changes: 2 additions & 1 deletion .github/workflows/lib.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
{
"name": "ArduinoBLE",
"exclude_targets": [
"esp32s2"
"esp32s2",
"esp32p4"
],
"sketch_path": [
"~/Arduino/libraries/ArduinoBLE/examples/Central/Scan/Scan.ino"
Expand Down
57 changes: 57 additions & 0 deletions boards.txt
Original file line number Diff line number Diff line change
Expand Up @@ -50547,3 +50547,60 @@ cyobot_v2_esp32s3.menu.ZigbeeMode.zczr.build.zigbee_mode=-DZIGBEE_MODE_ZCZR
cyobot_v2_esp32s3.menu.ZigbeeMode.zczr.build.zigbee_libs=-lesp_zb_api.zczr -lzboss_stack.zczr -lzboss_port.remote

##############################################################

kodedot.name=kode dot

kodedot.bootloader.tool=esptool_py
kodedot.bootloader.tool.default=esptool_py

kodedot.upload.tool=esptool_py_app_only
kodedot.upload.tool.default=esptool_py_app_only
kodedot.upload.tool.network=esp_ota

kodedot.upload.maximum_size=8388608
kodedot.upload.maximum_data_size=327680
kodedot.upload.flags=
kodedot.upload.extra_flags=
kodedot.upload.use_1200bps_touch=false
kodedot.upload.wait_for_upload_port=false
kodedot.upload.speed=921600

kodedot.upload.erase_cmd=

kodedot.serial.disableDTR=false
kodedot.serial.disableRTS=false

kodedot.build.tarch=xtensa
kodedot.build.bootloader_addr=0x0
kodedot.build.target=esp32s3
kodedot.build.mcu=esp32s3
kodedot.build.core=esp32
kodedot.build.variant=kodedot
kodedot.build.board=KODE_DOT

kodedot.build.usb_mode=1
kodedot.build.cdc_on_boot=1
kodedot.build.msc_on_boot=0
kodedot.build.dfu_on_boot=0

kodedot.build.f_cpu=240000000L

kodedot.build.flash_offset=0x400000
kodedot.build.flash_size=16MB
kodedot.build.flash_freq=80m
kodedot.build.flash_mode=dio

kodedot.build.custom_partitions=kodedot_partitions

kodedot.build.psram_type=qspi
kodedot.build.defines=

kodedot.build.loop_core=-DARDUINO_RUNNING_CORE=1
kodedot.build.event_core=-DARDUINO_EVENT_RUNNING_CORE=1

kodedot.recipe.hooks.objcopy.postobjcopy.3.pattern=
kodedot.recipe.hooks.objcopy.postobjcopy.3.pattern_args=

kodedot.recipe.output.save_file={build.project_name}.ino.bin

##############################################################
6 changes: 3 additions & 3 deletions cores/esp32/WString.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -180,15 +180,15 @@ bool String::changeBuffer(unsigned int maxStrLen) {
if (maxStrLen < sizeof(sso.buff) - 1) {
if (isSSO() || !buffer()) {
// Already using SSO, nothing to do
uint16_t oldLen = len();
size_t oldLen = len();
setSSO(true);
setLen(oldLen);
} else { // if bufptr && !isSSO()
// Using bufptr, need to shrink into sso.buff
char temp[sizeof(sso.buff)];
memcpy(temp, buffer(), maxStrLen);
free(wbuffer());
uint16_t oldLen = len();
size_t oldLen = len();
setSSO(true);
memcpy(wbuffer(), temp, maxStrLen);
setLen(oldLen);
Expand All @@ -201,7 +201,7 @@ bool String::changeBuffer(unsigned int maxStrLen) {
if (newSize > CAPACITY_MAX) {
return false;
}
uint16_t oldLen = len();
size_t oldLen = len();
char *newbuffer = (char *)realloc(isSSO() ? nullptr : wbuffer(), newSize);
if (newbuffer) {
size_t oldSize = capacity() + 1; // include NULL.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,8 @@ void setup() {
ESP.restart();
}

Serial.printf("ESP-NOW version: %d, max data length: %d\n", ESP_NOW.getVersion(), ESP_NOW.getMaxDataLen());

Serial.println("Setup complete. Broadcasting messages every 5 seconds.");
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,8 @@ void setup() {
ESP.restart();
}

Serial.printf("ESP-NOW version: %d, max data length: %d\n", ESP_NOW.getVersion(), ESP_NOW.getMaxDataLen());

// Register the new peer callback
ESP_NOW.onNewPeer(register_new_master, nullptr);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,12 @@
// The following struct is used to send data to the peer device.
// We use the attribute "packed" to ensure that the struct is not padded (all data
// is contiguous in the memory and without gaps).
// The maximum size of the complete message is 250 bytes (ESP_NOW_MAX_DATA_LEN).
// The maximum size of the payload is 250 bytes (ESP_NOW_MAX_DATA_LEN) for ESP-NOW v1.0.
// For ESP-NOW v2.0, the maximum size of the payload is 1470 bytes (ESP_NOW_MAX_DATA_LEN_V2).
// You can use ESP_NOW.getMaxDataLen() after calling ESP_NOW.begin() to get the maximum size
// of the data that can be sent.
// Read about the compatibility between ESP-NOW v1.0 and v2.0 in the ESP-IDF documentation:
// https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/network/esp_now.html#frame-format

typedef struct {
uint32_t count;
Expand Down Expand Up @@ -276,6 +281,8 @@ void setup() {
fail_reboot();
}

Serial.printf("ESP-NOW version: %d, max data length: %d\n", ESP_NOW.getVersion(), ESP_NOW.getMaxDataLen());

if (!broadcast_peer.begin()) {
Serial.println("Failed to initialize broadcast peer");
fail_reboot();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ void setup() {
// Start the ESP-NOW communication
Serial.println("ESP-NOW communication starting...");
NowSerial.begin(115200);
Serial.printf("ESP-NOW version: %d, max data length: %d\n", ESP_NOW.getVersion(), ESP_NOW.getMaxDataLen());
Serial.println("You can now send data to the peer device using the Serial Monitor.\n");
}

Expand Down
65 changes: 57 additions & 8 deletions libraries/ESP_NOW/src/ESP32_NOW.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,10 @@ static void _esp_now_tx_cb(const uint8_t *mac_addr, esp_now_send_status_t status
}
}

ESP_NOW_Class::ESP_NOW_Class() {}
ESP_NOW_Class::ESP_NOW_Class() {
max_data_len = 0;
version = 0;
}

ESP_NOW_Class::~ESP_NOW_Class() {}

Expand All @@ -155,6 +158,23 @@ bool ESP_NOW_Class::begin(const uint8_t *pmk) {
return false;
}

// Unfortunately we can't get the ESP-NOW version before initializing the Wi-Fi
uint32_t esp_now_version;
err = esp_now_get_version(&esp_now_version);
if (err != ESP_OK) {
log_w("esp_now_get_version failed! Assuming ESP-NOW v1.0");
esp_now_version = 1;
}

if (esp_now_version == 1) {
max_data_len = ESP_NOW_MAX_DATA_LEN;
} else {
max_data_len = ESP_NOW_MAX_DATA_LEN_V2;
}

version = esp_now_version;
log_i("ESP-NOW version: %lu, max_data_len: %lu", version, max_data_len);

_esp_now_has_begun = true;

memset(_esp_now_peers, 0, sizeof(ESP_NOW_Peer *) * ESP_NOW_MAX_TOTAL_PEER_NUM);
Expand Down Expand Up @@ -212,7 +232,7 @@ bool ESP_NOW_Class::end() {
return true;
}

int ESP_NOW_Class::getTotalPeerCount() {
int ESP_NOW_Class::getTotalPeerCount() const {
if (!_esp_now_has_begun) {
return -1;
}
Expand All @@ -225,7 +245,7 @@ int ESP_NOW_Class::getTotalPeerCount() {
return num.total_num;
}

int ESP_NOW_Class::getEncryptedPeerCount() {
int ESP_NOW_Class::getEncryptedPeerCount() const {
if (!_esp_now_has_begun) {
return -1;
}
Expand All @@ -238,16 +258,38 @@ int ESP_NOW_Class::getEncryptedPeerCount() {
return num.encrypt_num;
}

int ESP_NOW_Class::getMaxDataLen() const {
if (max_data_len == 0) {
log_e("ESP-NOW not initialized. Please call begin() first to get the max data length.");
return -1;
}

return max_data_len;
}

int ESP_NOW_Class::getVersion() const {
if (version == 0) {
log_e("ESP-NOW not initialized. Please call begin() first to get the version.");
return -1;
}

return version;
}

int ESP_NOW_Class::availableForWrite() {
return ESP_NOW_MAX_DATA_LEN;
int available = getMaxDataLen();
if (available < 0) {
return 0;
}
return available;
}

size_t ESP_NOW_Class::write(const uint8_t *data, size_t len) {
if (!_esp_now_has_begun) {
return 0;
}
if (len > ESP_NOW_MAX_DATA_LEN) {
len = ESP_NOW_MAX_DATA_LEN;
if (len > max_data_len) {
len = max_data_len;
}
esp_err_t result = esp_now_send(nullptr, data, len);
if (result == ESP_OK) {
Expand Down Expand Up @@ -386,8 +428,15 @@ size_t ESP_NOW_Peer::send(const uint8_t *data, int len) {
log_e("Peer not added.");
return 0;
}
if (len > ESP_NOW_MAX_DATA_LEN) {
len = ESP_NOW_MAX_DATA_LEN;

int max_data_len = ESP_NOW.getMaxDataLen();
if (max_data_len < 0) {
log_e("Error getting max data length.");
return 0;
}

if (len > max_data_len) {
len = max_data_len;
}
esp_err_t result = esp_now_send(mac, data, len);
if (result == ESP_OK) {
Expand Down
10 changes: 8 additions & 2 deletions libraries/ESP_NOW/src/ESP32_NOW.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,10 @@ class ESP_NOW_Class : public Print {
bool begin(const uint8_t *pmk = nullptr /* 16 bytes */);
bool end();

int getTotalPeerCount();
int getEncryptedPeerCount();
int getTotalPeerCount() const;
int getEncryptedPeerCount() const;
int getMaxDataLen() const;
int getVersion() const;

int availableForWrite();
size_t write(const uint8_t *data, size_t len);
Expand All @@ -34,6 +36,10 @@ class ESP_NOW_Class : public Print {

void onNewPeer(void (*cb)(const esp_now_recv_info_t *info, const uint8_t *data, int len, void *arg), void *arg);
bool removePeer(ESP_NOW_Peer &peer);

protected:
size_t max_data_len;
uint32_t version;
};

class ESP_NOW_Peer {
Expand Down
24 changes: 20 additions & 4 deletions libraries/ESP_NOW/src/ESP32_NOW_Serial.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,25 @@ bool ESP_NOW_Serial_Class::begin(unsigned long baud) {
//xSemaphoreTake(tx_sem, 0);
xSemaphoreGive(tx_sem);
}
setRxBufferSize(1024); //default if not preset
setTxBufferSize(1024); //default if not preset

size_t buf_size = 0;
if (ESP_NOW.getVersion() == 2) {
// ESP-NOW v2.0 has a larger maximum data length, so we need to increase the buffer sizes
// to hold around 3-4 packets
buf_size = setRxBufferSize(4096);
buf_size &= setTxBufferSize(4096);
} else {
// ESP-NOW v1.0 has a smaller maximum data length, so we can use the default buffer sizes
// to hold around 3-4 packets
buf_size = setRxBufferSize(1024);
buf_size &= setTxBufferSize(1024);
}

if (buf_size == 0) {
log_e("Failed to set buffer size");
return false;
}

return true;
}

Expand Down Expand Up @@ -164,7 +181,6 @@ void ESP_NOW_Serial_Class::onReceive(const uint8_t *data, size_t len, bool broad

//Print
int ESP_NOW_Serial_Class::availableForWrite() {
//return ESP_NOW_MAX_DATA_LEN;
if (tx_ring_buf == nullptr) {
return 0;
}
Expand All @@ -189,7 +205,7 @@ bool ESP_NOW_Serial_Class::checkForTxData() {
//do we have something that failed the last time?
resend_count = 0;
if (queued_buff == nullptr) {
queued_buff = (uint8_t *)xRingbufferReceiveUpTo(tx_ring_buf, &queued_size, 0, ESP_NOW_MAX_DATA_LEN);
queued_buff = (uint8_t *)xRingbufferReceiveUpTo(tx_ring_buf, &queued_size, 0, ESP_NOW.getMaxDataLen());
} else {
log_d(MACSTR " : PREVIOUS", MAC2STR(addr()));
}
Expand Down
4 changes: 4 additions & 0 deletions libraries/SD/src/SD.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ using namespace fs;

SDFS::SDFS(FSImplPtr impl) : FS(impl), _pdrv(0xFF) {}

SDFS::~SDFS() {
end();
}

bool SDFS::begin(uint8_t ssPin, SPIClass &spi, uint32_t frequency, const char *mountpoint, uint8_t max_files, bool format_if_empty) {
if (_pdrv != 0xFF) {
return true;
Expand Down
1 change: 1 addition & 0 deletions libraries/SD/src/SD.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ class SDFS : public FS {

public:
SDFS(FSImplPtr impl);
~SDFS();
bool begin(
uint8_t ssPin = SS, SPIClass &spi = SPI, uint32_t frequency = 4000000, const char *mountpoint = "/sd", uint8_t max_files = 5, bool format_if_empty = false
);
Expand Down
16 changes: 16 additions & 0 deletions platform.txt
Original file line number Diff line number Diff line change
Expand Up @@ -330,3 +330,19 @@ tools.dfu-util.cmd=dfu-util
tools.dfu-util.upload.params.verbose=-d
tools.dfu-util.upload.params.quiet=
tools.dfu-util.upload.pattern="{path}/{cmd}" --device {vid.0}:{pid.0} -D "{build.path}/{build.project_name}.bin" -Q

## --------------------------------------------------------------------------
## esptool_py_app_only is used to upload only the application image
## It won't upload the bootloader or any other binary except for the main application
## --------------------------------------------------------------------------
tools.esptool_py_app_only.path={runtime.tools.esptool_py.path}
tools.esptool_py_app_only.cmd=esptool
tools.esptool_py_app_only.cmd.windows=esptool.exe

tools.esptool_py_app_only.upload.protocol=serial
tools.esptool_py_app_only.upload.params.verbose=
tools.esptool_py_app_only.upload.params.quiet=

tools.esptool_py_app_only.upload.pattern_args=--chip {build.mcu} --port "{serial.port}" --baud {upload.speed} {upload.flags} --before default_reset --after hard_reset write_flash --flash_mode {build.flash_mode} --flash_freq {build.flash_freq} --flash_size {build.flash_size} {build.flash_offset} "{build.path}/{build.project_name}.bin" {upload.extra_flags}

tools.esptool_py_app_only.upload.pattern="{path}/{cmd}" {tools.esptool_py_app_only.upload.pattern_args}
14 changes: 14 additions & 0 deletions variants/kodedot/custom_ota_override.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// custom_ota_override.cpp
// This function overrides the weak definition of `verifyRollbackLater()` in the kode dot board.

extern "C" {
// Declare the weak function symbol to override it
bool verifyRollbackLater() __attribute__((weak));
}

// Custom implementation of verifyRollbackLater()
// Returning `true` prevents the OTA image from being automatically marked as valid.
// This ensures that the system will roll back to the previous image unless it is explicitly validated later.
bool verifyRollbackLater() {
return true;
}
7 changes: 7 additions & 0 deletions variants/kodedot/kodedot_partitions.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Name, Type, SubType, Offset, Size, Flags
nvs, data, nvs, 0x9000, 0x6000,
phy_init, data, phy, 0xf000, 0x1000,
otadata, data, ota, 0x10000, 0x2000,
ota_0, app, ota_0, 0x20000, 0x3E0000,
ota_1, app, ota_1, 0x400000, 0x800000,
storage, data, spiffs, 0xC00000, 0x400000,
Loading