diff --git a/SUMMARY.md b/SUMMARY.md index e863465..5d0e55c 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -6,7 +6,8 @@ * 🔖 Code reference * [LibreTuya API](docs/reference/lt-api.md) * [Class reference](ltapi/class_libre_tuya.md) - * [Static functions](ltapi/_libre_tuya_a_p_i_8cpp.md) + * [Common methods](ltapi/_libre_tuya_a_p_i_8h.md) + * [Family-provided methods](ltapi/_libre_tuya_custom_8h.md) * [Logger](ltapi/lt__logger_8h.md) * [Chip types & UF2 families](ltapi/_chip_type_8h.md) * [POSIX utilities](ltapi/lt__posix__api_8h.md) diff --git a/arduino/libretuya/core/LibreTuyaAPI.cpp b/arduino/libretuya/core/LibreTuyaAPI.cpp index 64c7ea8..cf8ba1c 100644 --- a/arduino/libretuya/core/LibreTuyaAPI.cpp +++ b/arduino/libretuya/core/LibreTuyaAPI.cpp @@ -59,115 +59,3 @@ void hexdump(uint8_t *buf, size_t len, uint32_t offset, uint8_t width) { pos += lineWidth; } } - -/** - * @brief Get LibreTuya version string. - */ -const char *LibreTuya::getVersion() { - return LT_VERSION_STR; -} - -/** - * @brief Get board name. - */ -const char *LibreTuya::getBoard() { - return LT_BOARD_STR; -} - -/** - * @brief Get CPU family ID. - */ -ChipFamily LibreTuya::getChipFamily() { - return FAMILY; -} - -/** - * @brief Get CPU family name as string. - */ -const char *LibreTuya::getChipFamilyName() { - return STRINGIFY_MACRO(FAMILY); -} - -static char *deviceName = NULL; - -/** - * @brief Get device friendly name in format "LT--". - * Can be used as hostname. - */ -const char *LibreTuya::getDeviceName() { - if (deviceName) - return deviceName; - uint32_t chipId = getChipId(); - uint8_t *id = (uint8_t *)&chipId; - - const char *board = getBoard(); - uint8_t boardLen = strlen(board); - deviceName = (char *)malloc(3 + boardLen + 1 + 6 + 1); - - sprintf(deviceName, "LT-%s-%02x%02x%02x", board, id[0], id[1], id[2]); - return deviceName; -} - -/** - * @brief Get CPU frequency in MHz. - */ -uint32_t LibreTuya::getCpuFreqMHz() { - return getCpuFreq() / 1000000; -} - -static uint8_t otaRunningIndex = 0; - -/** - * @brief Get the currently running firmware OTA index. - */ -uint8_t LibreTuya::otaGetRunning() { - if (otaRunningIndex) - return otaRunningIndex; - // otaRunningIndex will be correct even after switchOta() - return otaRunningIndex = otaGetStoredIndex(); -} - -/** - * @brief Get the OTA index for updated firmware. - * - * Note: returns 1 for chips without dual-OTA. - */ -uint8_t LibreTuya::otaGetTarget() { - if (!otaSupportsDual()) - return 1; - return otaGetRunning() ^ 0b11; -} - -/** - * @brief Perform OTA rollback. - * - * @return false if no second image to run, writing failed or dual-OTA not supported - */ -bool LibreTuya::otaRollback() { - if (!otaCanRollback()) - return false; - if (otaGetRunning() != otaGetStoredIndex()) - // force switching back to current image - return otaSwitch(true); - return true; -} - -/** - * @brief Check if OTA rollback is supported and available (there is another image to run). - * @return false if no second image to run or dual-OTA not supported - */ -bool LibreTuya::otaCanRollback() { - if (!otaSupportsDual()) - return false; - if (otaGetRunning() == otaGetStoredIndex()) - return true; - if (otaGetRunning() == 1 && otaHasImage1()) - return true; - if (otaGetRunning() == 2 && otaHasImage2()) - return true; - return false; -} - -__attribute__((weak)) void LibreTuya::gpioRecover() { - // nop by default -} diff --git a/arduino/libretuya/core/LibreTuyaAPI.h b/arduino/libretuya/core/LibreTuyaAPI.h index d383b37..8d74318 100644 --- a/arduino/libretuya/core/LibreTuyaAPI.h +++ b/arduino/libretuya/core/LibreTuyaAPI.h @@ -15,8 +15,10 @@ #define LT_BOARD_STR STRINGIFY_MACRO(LT_BOARD) // Includes -#include "LibreTuyaCompat.h" -#include "LibreTuyaConfig.h" +#include "LibreTuyaClass.h" // global LT class +#include "LibreTuyaCompat.h" // compatibility methods +#include "LibreTuyaConfig.h" // configuration macros +#include "LibreTuyaCustom.h" // family-defined methods #include // C includes @@ -48,137 +50,3 @@ void hexdump(uint8_t *buf, size_t len, uint32_t offset = 0, uint8_t width = 16); #else void hexdump(uint8_t *buf, size_t len, uint32_t offset, uint8_t width); #endif - -// Main class -#ifdef __cplusplus - -#include // for flash inline methods -#include - -/** - * @brief Main LibreTuya API class. - * - * This class contains all functions common amongst all families. - * Implementations of these methods may vary between families. - * - * The class is accessible using the `LT` global object (defined by the family). - */ -class LibreTuya { - public: /* Common methods - note: these are documented in LibreTuyaAPI.cpp */ - const char *getVersion(); - const char *getBoard(); - ChipFamily getChipFamily(); - const char *getChipFamilyName(); - const char *getDeviceName(); - uint32_t getCpuFreqMHz(); - uint8_t otaGetRunning(); - uint8_t otaGetTarget(); - bool otaRollback(); - bool otaCanRollback(); - - public: /* Inline methods */ - inline uint32_t getFlashChipSize() { - return Flash.getSize(); - } - - // inline bool flashEraseSector(uint32_t sector) {} - // inline bool flashWrite(uint32_t offset, uint32_t *data, size_t size) {} - // inline bool flashRead(uint32_t offset, uint32_t *data, size_t size) {} - // inline bool partitionEraseRange(const esp_partition_t *partition, uint32_t offset, size_t size) {} - // inline bool partitionWrite(const esp_partition_t *partition, uint32_t offset, uint32_t *data, size_t size) {} - // inline bool partitionRead(const esp_partition_t *partition, uint32_t offset, uint32_t *data, size_t size) {} - - public: /* Family-defined methods */ - /** - * @brief Reboot the CPU. - */ - void restart(); - /** - * @brief Reconfigure GPIO pins used for debugging - * (SWD/JTAG), so that they can be used as normal I/O. - */ - void gpioRecover(); - - public: /* CPU-related */ - /** - * @brief Get CPU model ID. - */ - ChipType getChipType(); - /** - * @brief Get CPU model name as string. - */ - const char *getChipModel(); - /** - * @brief Get CPU unique ID. This may be based on MAC, eFuse, etc. - */ - uint32_t getChipId(); - /** - * @brief Get CPU core count. - */ - uint8_t getChipCores(); - /** - * @brief Get CPU core type name as string. - */ - const char *getChipCoreType(); - /** - * @brief Get CPU frequency in Hz. - */ - uint32_t getCpuFreq(); - /** - * @brief Get CPU cycle count. - */ - uint32_t getCycleCount(); - - public: /* Memory management */ - /** - * @brief Get total RAM size. - */ - uint32_t getRamSize(); - /** - * @brief Get total heap size. - */ - uint32_t getHeapSize(); - /** - * @brief Get free heap size. - */ - uint32_t getFreeHeap(); - /** - * @brief Get lowest level of free heap memory. - */ - uint32_t getMinFreeHeap(); - /** - * @brief Get largest block of heap that can be allocated at once. - */ - uint32_t getMaxAllocHeap(); - - public: /* OTA-related */ - /** - * @brief Read the currently active OTA index, i.e. the one that will boot upon restart. - */ - uint8_t otaGetStoredIndex(); - /** - * @brief Check if the chip supports dual-OTA. - */ - bool otaSupportsDual(); - /** - * @brief Check if OTA1 image is valid. - */ - bool otaHasImage1(); - /** - * @brief Check if OTA2 image is valid. - */ - bool otaHasImage2(); - /** - * @brief Try to switch OTA index to the other image. - * - * Note: should return true for chips without dual-OTA. Should return false if one of two images is not valid. - * - * @param force switch even if other image already marked as active - * @return false if writing failed; true otherwise - */ - bool otaSwitch(bool force = false); -}; - -extern LibreTuya LT; -extern LibreTuya ESP; -#endif diff --git a/arduino/libretuya/core/LibreTuyaClass.cpp b/arduino/libretuya/core/LibreTuyaClass.cpp new file mode 100644 index 0000000..b2eeba2 --- /dev/null +++ b/arduino/libretuya/core/LibreTuyaClass.cpp @@ -0,0 +1,115 @@ +/* Copyright (c) Kuba SzczodrzyƄski 2022-06-06. */ + +#include "LibreTuyaClass.h" + +/** + * @brief Get LibreTuya version string. + */ +const char *LibreTuya::getVersion() { + return LT_VERSION_STR; +} + +/** + * @brief Get board name. + */ +const char *LibreTuya::getBoard() { + return LT_BOARD_STR; +} + +/** + * @brief Get CPU family ID. + */ +ChipFamily LibreTuya::getChipFamily() { + return FAMILY; +} + +/** + * @brief Get CPU family name as string. + */ +const char *LibreTuya::getChipFamilyName() { + return STRINGIFY_MACRO(FAMILY); +} + +static char *deviceName = NULL; + +/** + * @brief Get device friendly name in format "LT--". + * Can be used as hostname. + */ +const char *LibreTuya::getDeviceName() { + if (deviceName) + return deviceName; + uint32_t chipId = getChipId(); + uint8_t *id = (uint8_t *)&chipId; + + const char *board = getBoard(); + uint8_t boardLen = strlen(board); + deviceName = (char *)malloc(3 + boardLen + 1 + 6 + 1); + + sprintf(deviceName, "LT-%s-%02x%02x%02x", board, id[0], id[1], id[2]); + return deviceName; +} + +/** + * @brief Get CPU frequency in MHz. + */ +uint32_t LibreTuya::getCpuFreqMHz() { + return getCpuFreq() / 1000000; +} + +static uint8_t otaRunningIndex = 0; + +/** + * @brief Get the currently running firmware OTA index. + */ +uint8_t LibreTuya::otaGetRunning() { + if (otaRunningIndex) + return otaRunningIndex; + // otaRunningIndex will be correct even after switchOta() + return otaRunningIndex = otaGetStoredIndex(); +} + +/** + * @brief Get the OTA index for updated firmware. + * + * Note: returns 1 for chips without dual-OTA. + */ +uint8_t LibreTuya::otaGetTarget() { + if (!otaSupportsDual()) + return 1; + return otaGetRunning() ^ 0b11; +} + +/** + * @brief Perform OTA rollback. + * + * @return false if no second image to run, writing failed or dual-OTA not supported + */ +bool LibreTuya::otaRollback() { + if (!otaCanRollback()) + return false; + if (otaGetRunning() != otaGetStoredIndex()) + // force switching back to current image + return otaSwitch(true); + return true; +} + +/** + * @brief Check if OTA rollback is supported and available (there is another image to run). + * @return false if no second image to run or dual-OTA not supported + */ +bool LibreTuya::otaCanRollback() { + if (!otaSupportsDual()) + return false; + if (otaGetRunning() == otaGetStoredIndex()) + return true; + if (otaGetRunning() == 1 && otaHasImage1()) + return true; + if (otaGetRunning() == 2 && otaHasImage2()) + return true; + return false; +} + +__attribute__((weak)) void LibreTuya::gpioRecover() { + // nop by default +} diff --git a/arduino/libretuya/core/LibreTuyaClass.h b/arduino/libretuya/core/LibreTuyaClass.h new file mode 100644 index 0000000..d3c7c1b --- /dev/null +++ b/arduino/libretuya/core/LibreTuyaClass.h @@ -0,0 +1,139 @@ +/* Copyright (c) Kuba SzczodrzyƄski 2022-06-06. */ + +#pragma once + +#ifdef __cplusplus + +#include "LibreTuyaAPI.h" +#include + +#include // for flash inline methods + +/** + * @brief Main LibreTuya API class. + * + * This class contains all functions common amongst all families. + * Implementations of these methods may vary between families. + * + * The class is accessible using the `LT` global object (defined by the family). + */ +class LibreTuya { + public: /* Common methods - note: these are documented in LibreTuyaAPI.cpp */ + const char *getVersion(); + const char *getBoard(); + ChipFamily getChipFamily(); + const char *getChipFamilyName(); + const char *getDeviceName(); + uint32_t getCpuFreqMHz(); + uint8_t otaGetRunning(); + uint8_t otaGetTarget(); + bool otaRollback(); + bool otaCanRollback(); + + public: /* Inline methods */ + inline uint32_t getFlashChipSize() { + return Flash.getSize(); + } + + // inline bool flashEraseSector(uint32_t sector) {} + // inline bool flashWrite(uint32_t offset, uint32_t *data, size_t size) {} + // inline bool flashRead(uint32_t offset, uint32_t *data, size_t size) {} + // inline bool partitionEraseRange(const esp_partition_t *partition, uint32_t offset, size_t size) {} + // inline bool partitionWrite(const esp_partition_t *partition, uint32_t offset, uint32_t *data, size_t size) {} + // inline bool partitionRead(const esp_partition_t *partition, uint32_t offset, uint32_t *data, size_t size) {} + + public: /* Family-defined methods */ + /** + * @brief Reboot the CPU. + */ + void restart(); + /** + * @brief Reconfigure GPIO pins used for debugging + * (SWD/JTAG), so that they can be used as normal I/O. + */ + void gpioRecover(); + + public: /* CPU-related */ + /** + * @brief Get CPU model ID. + */ + ChipType getChipType(); + /** + * @brief Get CPU model name as string. + */ + const char *getChipModel(); + /** + * @brief Get CPU unique ID. This may be based on MAC, eFuse, etc. + */ + uint32_t getChipId(); + /** + * @brief Get CPU core count. + */ + uint8_t getChipCores(); + /** + * @brief Get CPU core type name as string. + */ + const char *getChipCoreType(); + /** + * @brief Get CPU frequency in Hz. + */ + uint32_t getCpuFreq(); + /** + * @brief Get CPU cycle count. + */ + uint32_t getCycleCount(); + + public: /* Memory management */ + /** + * @brief Get total RAM size. + */ + uint32_t getRamSize(); + /** + * @brief Get total heap size. + */ + uint32_t getHeapSize(); + /** + * @brief Get free heap size. + */ + uint32_t getFreeHeap(); + /** + * @brief Get lowest level of free heap memory. + */ + uint32_t getMinFreeHeap(); + /** + * @brief Get largest block of heap that can be allocated at once. + */ + uint32_t getMaxAllocHeap(); + + public: /* OTA-related */ + /** + * @brief Read the currently active OTA index, i.e. the one that will boot upon restart. + */ + uint8_t otaGetStoredIndex(); + /** + * @brief Check if the chip supports dual-OTA. + */ + bool otaSupportsDual(); + /** + * @brief Check if OTA1 image is valid. + */ + bool otaHasImage1(); + /** + * @brief Check if OTA2 image is valid. + */ + bool otaHasImage2(); + /** + * @brief Try to switch OTA index to the other image. + * + * Note: should return true for chips without dual-OTA. Should return false if one of two images is not valid. + * + * @param force switch even if other image already marked as active + * @return false if writing failed; true otherwise + */ + bool otaSwitch(bool force = false); +}; + +extern LibreTuya LT; +extern LibreTuya ESP; + +#endif diff --git a/arduino/libretuya/core/LibreTuyaCustom.h b/arduino/libretuya/core/LibreTuyaCustom.h new file mode 100644 index 0000000..b2ebd16 --- /dev/null +++ b/arduino/libretuya/core/LibreTuyaCustom.h @@ -0,0 +1,31 @@ +/* Copyright (c) Kuba SzczodrzyƄski 2022-06-06. */ + +#include "LibreTuyaAPI.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Set resolution of values (in bits) returned by analogRead(). + */ +void analogReadResolution(int res); + +/** + * @brief Set PWM output frequency (in Hz). + */ +void analogWriteFrequency(int hz); + +/** + * @brief Set PWM output frequency (cycle period) in microseconds. + */ +void analogWritePeriod(int us); + +/** + * @brief Set resolution of values (in bits) expected by analogWrite(). + */ +void analogWriteResolution(int res); + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/arduino/realtek-ambz/cores/arduino/WVariant.h b/arduino/realtek-ambz/cores/arduino/WVariant.h index f18b66c..efdf7d4 100644 --- a/arduino/realtek-ambz/cores/arduino/WVariant.h +++ b/arduino/realtek-ambz/cores/arduino/WVariant.h @@ -50,10 +50,7 @@ extern PinDescription g_APinDescription[]; // Additional Wiring functions extern uint32_t digitalPinToPort(uint32_t pinNumber); extern uint32_t digitalPinToBitMask(uint32_t pinNumber); -extern void analogReadResolution(int res); -extern void analogWriteResolution(int res); extern void analogOutputInit(void); -extern void analogWritePeriod(int us); extern void wait_for_debug(); #ifdef __cplusplus diff --git a/arduino/realtek-ambz/cores/arduino/wiring_analog.c b/arduino/realtek-ambz/cores/arduino/wiring_analog.c index 1e5695e..878a1cd 100644 --- a/arduino/realtek-ambz/cores/arduino/wiring_analog.c +++ b/arduino/realtek-ambz/cores/arduino/wiring_analog.c @@ -38,20 +38,24 @@ extern void pinRemoveMode(pin_size_t pinNumber); static int _readResolution = 10; static int _writeResolution = 8; -static int _writePeriod = 20000; +static int _writePeriod = 20000; // 50 Hz void analogReadResolution(int res) { _readResolution = res; } -void analogWriteResolution(int res) { - _writeResolution = res; +void analogWriteFrequency(int hz) { + _writePeriod = 1E6 / hz; } void analogWritePeriod(int us) { _writePeriod = us; } +void analogWriteResolution(int res) { + _writeResolution = res; +} + static inline uint32_t mapResolution(uint32_t value, uint32_t from, uint32_t to) { if (from == to) return value;