From a83a845d5a394266118c587155e8532f6f146e35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Mon, 20 Jun 2022 20:38:19 +0200 Subject: [PATCH] [realtek-ambz] Move common digital/analog utils into core --- SUMMARY.md | 6 +- arduino/libretuya/core/LibreTuyaCustom.c | 99 +++++++++++++++++++ arduino/libretuya/core/LibreTuyaCustom.h | 38 +++---- .../cores/arduino/wiring_analog.c | 66 +++---------- .../cores/arduino/wiring_digital.c | 46 ++++----- 5 files changed, 160 insertions(+), 95 deletions(-) create mode 100644 arduino/libretuya/core/LibreTuyaCustom.c diff --git a/SUMMARY.md b/SUMMARY.md index 8d6eff4..0421b1b 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -5,14 +5,13 @@ * [📁 Project structure](docs/project-structure.md) * 🔖 Code reference * [LibreTuya API](docs/reference/lt-api.md) - * [Class reference](ltapi/class_libre_tuya.md) + * [LT class reference](ltapi/class_libre_tuya.md) * [Common methods](ltapi/_libre_tuya_a_p_i_8h.md) - * [Family-provided methods](ltapi/_libre_tuya_custom_8h.md) + * [Wiring custom methods](ltapi/_libre_tuya_custom_8h.md) * [Logger](ltapi/lt__logger_8h.md) * [Chip & family IDs](ltapi/_chip_type_8h_source.md) * [POSIX utilities](ltapi/lt__posix__api_8h.md) * Common API - * [Flash](ltapi/class_i_flash_class.md) * [FS](ltapi/classfs_1_1_f_s.md) * [Preferences](ltapi/class_i_preferences.md) * [WiFi API](ltapi/class_i_wi_fi_generic_class.md) @@ -24,6 +23,7 @@ * [TCP Server](ltapi/class_i_wi_fi_server.md) * [LibreTuya libraries](docs/libs-built-in.md) * [base64](ltapi/classbase64.md) + * [Flash](ltapi/class_flash_class.md) * [HTTPClient](ltapi/class_h_t_t_p_client.md) * [mDNS](ltapi/classm_d_n_s.md) * NetUtils diff --git a/arduino/libretuya/core/LibreTuyaCustom.c b/arduino/libretuya/core/LibreTuyaCustom.c new file mode 100644 index 0000000..7d74d84 --- /dev/null +++ b/arduino/libretuya/core/LibreTuyaCustom.c @@ -0,0 +1,99 @@ +/* Copyright (c) Kuba SzczodrzyƄski 2022-06-20. */ + +#include "LibreTuyaCustom.h" + +int _analogReadResolution = 10; // 0-1023 +int _analogWriteResolution = 8; // 0-255 +int _analogWritePeriod = 20000; // 50 Hz + +/** + * @brief Check if pin is invalid (too low or too high). + */ +bool pinInvalid(pin_size_t pinNumber) { + return pinNumber < 0 || pinNumber >= PINS_COUNT; +} + +/** + * @brief Get PinInfo struct for the specified number. + * Returns NULL if pin number is invalid. + */ +PinInfo *pinInfo(pin_size_t pinNumber) { + if (pinInvalid(pinNumber)) + return NULL; + return &(pinTable[pinNumber]); +} + +/** + * @brief Check if pin supports all features represented by 'mask'. + */ +bool pinHasFeat(PinInfo *pin, uint32_t mask) { + return (pin->features & mask) == mask; +} + +/** + * @brief Check if pin has all features represented by 'mask' enabled. + */ +bool pinIsFeat(PinInfo *pin, uint32_t mask) { + return (pin->types & mask) == mask; +} + +/** + * @brief Check if GPIO pin is configured as output. + */ +bool pinIsOutput(PinInfo *pin) { + return pin->mode == OUTPUT || pin->mode == OUTPUT_OPENDRAIN; +} + +/** + * @brief Check if GPIO pin is configured as output. + */ +bool pinIsInput(PinInfo *pin) { + return pin->mode == INPUT || pin->mode == INPUT_PULLUP || pin->mode == INPUT_PULLDOWN; +} + +/** + * @brief Read voltage from ADC and return a value between 0 and + * the current reading resolution. + */ +int analogRead(pin_size_t pinNumber) { + float voltage = analogReadVoltage(pinNumber); + float maxVoltage = analogReadMaxVoltage(pinNumber); + uint16_t ret = round((1 << _analogReadResolution) * voltage / maxVoltage); + if (ret >= (1 << _analogReadResolution)) + ret = (1 << _analogReadResolution) - 1; + return ret; +} + +/** + * @brief Set resolution of values (in bits) returned by analogRead(). + * Defaults to 10 bit (0-1023). + */ +void analogReadResolution(int res) { + _analogReadResolution = res; +} + +/** + * @brief Set resolution of values (in bits) expected by analogWrite(). + * Defaults to 8 bit (0-255). + */ +void analogWriteResolution(int res) { + _analogWriteResolution = res; +} + +/** + * @brief Set PWM output frequency (in Hz). + * Defaults to 50 Hz (20,000 uS). + */ +void analogWriteFrequency(int hz) { + _analogWritePeriod = 1E6 / hz; +} + +/** + * @brief Set PWM output frequency (cycle period) in microseconds. + * Defaults to 20,000 uS (50 Hz). + */ +void analogWritePeriod(int us) { + _analogWritePeriod = us; +} + +__attribute__((weak)) void analogReference(uint8_t mode) {} diff --git a/arduino/libretuya/core/LibreTuyaCustom.h b/arduino/libretuya/core/LibreTuyaCustom.h index 205f726..4f580da 100644 --- a/arduino/libretuya/core/LibreTuyaCustom.h +++ b/arduino/libretuya/core/LibreTuyaCustom.h @@ -53,30 +53,34 @@ typedef struct { extern PinInfo pinTable[]; +// Custom Wiring methods + +bool pinInvalid(pin_size_t pinNumber); +PinInfo *pinInfo(pin_size_t pinNumber); +bool pinHasFeat(PinInfo *pin, uint32_t mask); +bool pinIsFeat(PinInfo *pin, uint32_t mask); +bool pinIsOutput(PinInfo *pin); +bool pinIsInput(PinInfo *pin); + +int analogRead(pin_size_t pinNumber); +void analogReadResolution(int res); +void analogWriteResolution(int res); +void analogWriteFrequency(int hz); +void analogWritePeriod(int us); + +extern int _analogReadResolution; +extern int _analogWriteResolution; +extern int _analogWritePeriod; + /** * @brief Read voltage from analog input (in millivolts). */ uint16_t analogReadVoltage(pin_size_t pinNumber); /** - * @brief Set resolution of values (in bits) returned by analogRead(). + * @brief Get max reading voltage for the specified pin (millivolts). */ -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); +uint16_t analogReadMaxVoltage(pin_size_t pinNumber); #ifdef __cplusplus } // extern "C" diff --git a/arduino/realtek-ambz/cores/arduino/wiring_analog.c b/arduino/realtek-ambz/cores/arduino/wiring_analog.c index 9f89177..14b9ece 100644 --- a/arduino/realtek-ambz/cores/arduino/wiring_analog.c +++ b/arduino/realtek-ambz/cores/arduino/wiring_analog.c @@ -35,34 +35,8 @@ extern void *gpio_pin_struct[]; extern void pinRemoveMode(pin_size_t pinNumber); -static int _readResolution = 10; -static int _writeResolution = 8; -static int _writePeriod = 20000; // 50 Hz - // TODO implement custom ADC calibration -void analogReadResolution(int res) { - _readResolution = res; -} - -void analogWriteFrequency(int hz) { - _writePeriod = 1E6 / hz; -} - -void analogWritePeriod(int us) { - _writePeriod = us; -} - -void analogWriteResolution(int res) { - _writeResolution = res; -} - -uint8_t analog_reference = 0; - -void analogReference(uint8_t mode) { - analog_reference = mode; -} - uint16_t analogReadVoltage(pin_size_t pinNumber) { uint16_t ret = 0; switch (pinNumber) { @@ -102,42 +76,30 @@ uint16_t analogReadVoltage(pin_size_t pinNumber) { return AD2MV(ret, 0x418, 0x342); } -int analogRead(pin_size_t pinNumber) { - float voltage = analogReadVoltage(pinNumber); - uint16_t ret = 0; - if (pinNumber != PIN_A1) { - ret = round((1 << _readResolution) * voltage / 3300); - } else { - ret = round((1 << _readResolution) * voltage / 5000); - } - if (ret >= (1 << _readResolution)) - ret = (1 << _readResolution) - 1; - return ret; +uint16_t analogReadMaxVoltage(pin_size_t pinNumber) { + if (pinNumber == PIN_A1) + return 5000; + return 3300; } -void analogOutputInit(void) { - // nop -} - -// Right now, PWM output only works on the pins with -// hardware support. These are defined in the appropriate -// pins_*.c file. For the rest of the pins, we default -// to digital output. void analogWrite(pin_size_t pinNumber, int value) { + PinInfo *pin = pinInfo(pinNumber); + if (!pin) + return; pwmout_t *obj; - if ((pinTable[pinNumber].features & PIN_PWM) == PIN_PWM) { - float percent = value * 1.0 / (1 << _writeResolution); - if (pinTable[pinNumber].types != PIN_PWM) { - if ((pinTable[pinNumber].types == PIN_GPIO) || (pinTable[pinNumber].types == PIN_IRQ)) { + if (pinHasFeat(pin, PIN_PWM)) { + float percent = value * 1.0 / (1 << _analogWriteResolution); + if (pin->types != PIN_PWM) { + if ((pin->types == PIN_GPIO) || (pin->types == PIN_IRQ)) { pinRemoveMode(pinNumber); } gpio_pin_struct[pinNumber] = malloc(sizeof(pwmout_t)); pwmout_t *obj = (pwmout_t *)gpio_pin_struct[pinNumber]; - pwmout_init(obj, pinTable[pinNumber].gpio); - pwmout_period_us(obj, _writePeriod); + pwmout_init(obj, pin->gpio); + pwmout_period_us(obj, _analogWritePeriod); pwmout_write(obj, percent); - pinTable[pinNumber].types = PIN_PWM; + pin->types = PIN_PWM; } else { pwmout_t *obj = (pwmout_t *)gpio_pin_struct[pinNumber]; // pwmout_period_us(obj, _writePeriod); diff --git a/arduino/realtek-ambz/cores/arduino/wiring_digital.c b/arduino/realtek-ambz/cores/arduino/wiring_digital.c index 8cbe1c9..78a5c5a 100644 --- a/arduino/realtek-ambz/cores/arduino/wiring_digital.c +++ b/arduino/realtek-ambz/cores/arduino/wiring_digital.c @@ -6,65 +6,63 @@ extern void *gpio_pin_struct[PINS_COUNT]; -bool pinInvalid(pin_size_t pinNumber) { - return pinNumber < 0 || pinNumber >= PINS_COUNT || pinTable[pinNumber].gpio == NC; -} - void pinRemoveMode(pin_size_t pinNumber) { - if (pinInvalid(pinNumber)) + PinInfo *pin = pinInfo(pinNumber); + if (!pin) return; - if (pinTable[pinNumber].types & PIN_PWM) { + if (pinIsFeat(pin, PIN_PWM)) { pwmout_t *obj = (pwmout_t *)gpio_pin_struct[pinNumber]; pwmout_free(obj); } - if (pinTable[pinNumber].types & PIN_GPIO) { + if (pinIsFeat(pin, PIN_GPIO)) { gpio_t *obj = (gpio_t *)gpio_pin_struct[pinNumber]; - gpio_deinit(obj, pinTable[pinNumber].gpio); + gpio_deinit(obj, pin->gpio); free(obj); } - if (pinTable[pinNumber].types & PIN_IRQ) { + if (pinIsFeat(pin, PIN_IRQ)) { gpio_irq_t *obj = (gpio_irq_t *)gpio_pin_struct[pinNumber]; gpio_irq_deinit(obj); free(obj); } gpio_pin_struct[pinNumber] = NULL; - pinTable[pinNumber].types = PIN_NONE; + pin->types = PIN_NONE; } void pinMode(pin_size_t pinNumber, PinModeArduino pinMode) { - if (pinInvalid(pinNumber)) + PinInfo *pin = pinInfo(pinNumber); + if (!pin) return; - if (pinTable[pinNumber].types == PIN_GPIO && pinTable[pinNumber].mode == pinMode) + if (pinIsFeat(pin, PIN_GPIO) && pin->mode == pinMode) // Nothing changes in pin mode return; - if ((pinTable[pinNumber].features & PIN_GPIO) != PIN_GPIO) + if (!pinHasFeat(pin, PIN_GPIO)) // cannot set ADC as I/O return; - /* if (pinTable[pinNumber].types == PIN_PWM) { + /* if (pin->types == PIN_PWM) { // If this pin has been configured as PWM, then it cannot change to another mode return; } */ - if (pinTable[pinNumber].types != PIN_GPIO) + if (pin->types != PIN_GPIO) // pin mode changes; deinit gpio and free memory pinRemoveMode(pinNumber); gpio_t *gpio; - if (pinTable[pinNumber].types == PIN_NONE) { + if (pin->types == PIN_NONE) { // allocate memory if pin not used before gpio = malloc(sizeof(gpio_t)); gpio_pin_struct[pinNumber] = gpio; - gpio_init(gpio, pinTable[pinNumber].gpio); - pinTable[pinNumber].types = PIN_GPIO; + gpio_init(gpio, pin->gpio); + pin->types = PIN_GPIO; } else { // pin already used as gpio gpio = (gpio_t *)gpio_pin_struct[pinNumber]; } - pinTable[pinNumber].mode = pinMode; + pin->mode = pinMode; PinDirection dir; PinMode mode; @@ -99,9 +97,10 @@ void pinMode(pin_size_t pinNumber, PinModeArduino pinMode) { } void digitalWrite(pin_size_t pinNumber, PinStatus status) { - if (pinInvalid(pinNumber)) + PinInfo *pin = pinInfo(pinNumber); + if (!pin) return; - if (pinTable[pinNumber].types != PIN_GPIO) + if (pin->types != PIN_GPIO) return; gpio_t *gpio = (gpio_t *)gpio_pin_struct[pinNumber]; @@ -109,9 +108,10 @@ void digitalWrite(pin_size_t pinNumber, PinStatus status) { } PinStatus digitalRead(pin_size_t pinNumber) { - if (pinInvalid(pinNumber)) + PinInfo *pin = pinInfo(pinNumber); + if (!pin) return; - if (pinTable[pinNumber].types != PIN_GPIO) + if (pin->types != PIN_GPIO) return; gpio_t *gpio = (gpio_t *)gpio_pin_struct[pinNumber];