diff --git a/components/pcf2131/.eil.yml b/components/pcf2131/.eil.yml new file mode 100644 index 00000000..953db969 --- /dev/null +++ b/components/pcf2131/.eil.yml @@ -0,0 +1,21 @@ +name: pcf2131 +description: Driver for PCF2131 real-time clock/calendar +version: 1.0.0 +groups: + - rtc +code_owners: UncleRus +depends: + - i2cdev + - log + - esp_idf_lib_helpers +thread_safe: yes +targets: + - esp32 + - esp8266 + - esp32s2 + - esp32s3 + - esp32c3 +license: BSD-3 +copyrights: + - name: UncleRus + year: 2020 diff --git a/components/pcf2131/CMakeLists.txt b/components/pcf2131/CMakeLists.txt new file mode 100644 index 00000000..c44eb7d4 --- /dev/null +++ b/components/pcf2131/CMakeLists.txt @@ -0,0 +1,5 @@ +idf_component_register( + SRCS pcf2131.c + INCLUDE_DIRS . + REQUIRES i2cdev log esp_idf_lib_helpers +) diff --git a/components/pcf2131/LICENSE b/components/pcf2131/LICENSE new file mode 100644 index 00000000..348a02df --- /dev/null +++ b/components/pcf2131/LICENSE @@ -0,0 +1,26 @@ +Copyright (c) 2020 Ruslan V. Uss + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of itscontributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/components/pcf2131/component.mk b/components/pcf2131/component.mk new file mode 100644 index 00000000..a3610e86 --- /dev/null +++ b/components/pcf2131/component.mk @@ -0,0 +1,2 @@ +COMPONENT_ADD_INCLUDEDIRS = . +COMPONENT_DEPENDS = i2cdev log esp_idf_lib_helpers diff --git a/components/pcf2131/pcf2131.c b/components/pcf2131/pcf2131.c new file mode 100644 index 00000000..6550d4c8 --- /dev/null +++ b/components/pcf2131/pcf2131.c @@ -0,0 +1,424 @@ +/* + * Copyright (c) 2020 Ruslan V. Uss + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of itscontributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file pcf2131.c + * + * ESP-IDF driver for PCF2131 (BM8563) real-time clock/calendar + * + * Copyright (c) 2020 Ruslan V. Uss + * + * BSD Licensed as described in the file LICENSE + */ +#include "pcf2131.h" + +#define I2C_FREQ_HZ 400000 + +#define REG_CTRL_STATUS1 0x00 +#define REG_CTRL_STATUS2 0x01 +#define REG_CTRL_STATUS3 0x02 +#define REG_CTRL_STATUS4 0x03 +#define REG_CTRL_STATUS5 0x04 +#define REG_SW_RESET 0x05 +#define REG_100TH_SEC 0x06 +#define REG_VL_SECONDS 0x07 +#define REG_MINUTES 0x08 +#define REG_HOURS 0x09 +#define REG_DAYS 0x0A +#define REG_WEEKDAYS 0x0B +#define REG_CENT_MONTHS 0x0C +#define REG_YEARS 0x0D +#define REG_ALARM_SEC 0x0E +#define REG_ALARM_MIN 0x0F +#define REG_ALARM_HOUR 0x10 +#define REG_ALARM_DAY 0x11 +#define REG_ALARM_WDAY 0x12 +#define REG_CLKOUT 0x13 +#define REG_TIMER_CTRL 0x0e +#define REG_TIMER 0x0f + +#define BIT_YEAR_CENTURY 7 +#define BIT_VL 7 +#define BIT_AE 7 +#define BIT_CLKOUT_FD 0 +#define BIT_CLKOUT_FE 7 + +#define BIT_CTRL_STATUS2_TIE 0 +#define BIT_CTRL_STATUS2_AIE 1 +#define BIT_CTRL_STATUS2_TF 3 +#define BIT_CTRL_STATUS2_AF 4 + +#define BIT_TIMER_CTRL_TE 7 + +#define MASK_TIMER_CTRL_TD 0x03 +#define MASK_ALARM 0x7f + +#define MASK_MIN 0x7f +#define MASK_HOUR 0x3f +#define MASK_MDAY 0x3f +#define MASK_WDAY 0x07 +#define MASK_MON 0x1f + +#define BV(x) ((uint8_t)(1 << (x))) + +#define CHECK(x) do { esp_err_t __; if ((__ = x) != ESP_OK) return __; } while (0) +#define CHECK_ARG(ARG) do { if (!(ARG)) return ESP_ERR_INVALID_ARG; } while (0) + +static uint8_t bcd2dec(uint8_t val) +{ + return (val >> 4) * 10 + (val & 0x0f); +} + +static uint8_t dec2bcd(uint8_t val) +{ + return ((val / 10) << 4) + (val % 10); +} + +static inline esp_err_t read_reg_nolock(i2c_dev_t *dev, uint8_t reg, uint8_t *val) +{ + return i2c_dev_read_reg(dev, reg, val, 1); +} + +static inline esp_err_t write_reg_nolock(i2c_dev_t *dev, uint8_t reg, uint8_t val) +{ + return i2c_dev_write_reg(dev, reg, &val, 1); +} + +static esp_err_t update_reg_nolock(i2c_dev_t *dev, uint8_t reg, uint8_t mask, uint8_t val) +{ + uint8_t v; + CHECK(read_reg_nolock(dev, reg, &v)); + CHECK(write_reg_nolock(dev, reg, (v & ~mask) | val)); + return ESP_OK; +} + +static esp_err_t read_reg(i2c_dev_t *dev, uint8_t reg, uint8_t *val) +{ + I2C_DEV_TAKE_MUTEX(dev); + I2C_DEV_CHECK(dev, read_reg_nolock(dev, reg, val)); + I2C_DEV_GIVE_MUTEX(dev); + + return ESP_OK; +} + +static esp_err_t write_reg(i2c_dev_t *dev, uint8_t reg, uint8_t val) +{ + I2C_DEV_TAKE_MUTEX(dev); + I2C_DEV_CHECK(dev, write_reg_nolock(dev, reg, val)); + I2C_DEV_GIVE_MUTEX(dev); + + return ESP_OK; +} + +static esp_err_t update_reg(i2c_dev_t *dev, uint8_t reg, uint8_t mask, uint8_t val) +{ + I2C_DEV_TAKE_MUTEX(dev); + I2C_DEV_CHECK(dev, update_reg_nolock(dev, reg, mask, val)); + I2C_DEV_GIVE_MUTEX(dev); + + return ESP_OK; +} + +/////////////////////////////////////////////////////////////////////////////// + +esp_err_t pcf2131_init_desc(i2c_dev_t *dev, i2c_port_t port, gpio_num_t sda_gpio, gpio_num_t scl_gpio) +{ + CHECK_ARG(dev); + + dev->port = port; + dev->addr = PCF2131_I2C_ADDR; + dev->cfg.sda_io_num = sda_gpio; + dev->cfg.scl_io_num = scl_gpio; +#if HELPER_TARGET_IS_ESP32 + dev->cfg.master.clk_speed = I2C_FREQ_HZ; +#endif + return i2c_dev_create_mutex(dev); +} + +esp_err_t pcf2131_init_default_config(i2c_dev_t *dev){ + + CHECK_ARG(dev); + + uint8_t reg_data[1]; + uint8_t read_data[16]; + + // control register 1 = general config + I2C_DEV_TAKE_MUTEX(dev); + // read all registers + /* + I2C_DEV_CHECK(dev, i2c_dev_read_reg(dev, REG_CTRL_STATUS1, read_data, 4)); + for (uint8_t i=0; i < 15; i++) + printf("Read reg. data i: %d -- %d", i, read_data[i]); + */ + //I2C_DEV_CHECK(dev, i2c_dev_read_reg(dev, REG_CTRL_STATUS1, reg_data, 1)); + reg_data[0] = 0x0; // TC_DIS 0, POR_OVRD 0, === normal run + I2C_DEV_CHECK(dev, i2c_dev_write_reg(dev, REG_CTRL_STATUS1, reg_data, 1)); + //I2C_DEV_GIVE_MUTEX(dev); + + // control register 3 = Battery switch over + add. intr + //I2C_DEV_TAKE_MUTEX(dev); + //reg_data[0] = 0x72; // PWRMNG 011, BTSE 1, BIE 1, rest 0 direct switch + reg_data[0] = 0x12; // PWRMNG 000, BTSE 1, BIE 1, rest 0 standard more + I2C_DEV_CHECK(dev, i2c_dev_write_reg(dev, REG_CTRL_STATUS3, reg_data, 1)); + + I2C_DEV_GIVE_MUTEX(dev); + + return ESP_OK; + +} + +esp_err_t pcf2131_free_desc(i2c_dev_t *dev) +{ + CHECK_ARG(dev); + + return i2c_dev_delete_mutex(dev); +} + +esp_err_t pcf2131_set_time(i2c_dev_t *dev, struct tm *time) +{ + CHECK_ARG(dev && time); + + bool ovf = time->tm_year >= 200; + uint8_t reg_data[1]; + + uint8_t data[8] = { + 0, + dec2bcd(time->tm_sec), + dec2bcd(time->tm_min), + dec2bcd(time->tm_hour), + dec2bcd(time->tm_mday), + dec2bcd(time->tm_wday), + dec2bcd(time->tm_mon + 1) | (ovf ? BV(BIT_YEAR_CENTURY) : 0), + dec2bcd(time->tm_year - (ovf ? 200 : 100)) + }; + + I2C_DEV_TAKE_MUTEX(dev); + // read and set STOP bit of register control_1 + I2C_DEV_CHECK(dev, i2c_dev_read_reg(dev, REG_CTRL_STATUS1, reg_data, 1)); + reg_data[0] |= 0x28; + I2C_DEV_CHECK(dev, i2c_dev_write_reg(dev, REG_CTRL_STATUS1, reg_data, 1)); + // trigger full SW reset + reg_data[0] = 0xA4; // full reset 0x2C, prescaler clear 0xA4 + I2C_DEV_CHECK(dev, i2c_dev_write_reg(dev, REG_SW_RESET, reg_data, 1)); + // set time + I2C_DEV_CHECK(dev, i2c_dev_write_reg(dev, REG_100TH_SEC, data, 8)); + + // start clock source + reg_data[0] = 0x00; + I2C_DEV_CHECK(dev, i2c_dev_write_reg(dev, REG_CTRL_STATUS1, reg_data, 1)); + + I2C_DEV_GIVE_MUTEX(dev); + + + return ESP_OK; +} + +esp_err_t pcf2131_get_time(i2c_dev_t *dev, struct tm *time, bool *valid) +{ + CHECK_ARG(dev && time && valid); + + uint8_t data[8]; + + I2C_DEV_TAKE_MUTEX(dev); + I2C_DEV_CHECK(dev, i2c_dev_read_reg(dev, REG_100TH_SEC, data, 8)); + I2C_DEV_GIVE_MUTEX(dev); + + *valid = data[1] & BV(BIT_VL) ? false : true; + time->tm_sec = bcd2dec(data[1] & ~BV(BIT_VL)); + time->tm_min = bcd2dec(data[2] & MASK_MIN); + time->tm_hour = bcd2dec(data[3] & MASK_HOUR); + time->tm_mday = bcd2dec(data[4] & MASK_MDAY); + time->tm_wday = bcd2dec(data[5] & MASK_WDAY); + time->tm_mon = bcd2dec(data[6] & MASK_MON) - 1; + time->tm_year = bcd2dec(data[7]) + (data[6] & BV(BIT_YEAR_CENTURY) ? 200 : 100); + + return ESP_OK; +} + +esp_err_t pcf2131_set_clkout(i2c_dev_t *dev, pcf2131_clkout_freq_t freq) +{ + CHECK_ARG(dev); + + return write_reg(dev, REG_CLKOUT, + freq == PCF2131_DISABLED + ? 0 + : (BV(BIT_CLKOUT_FE) | ((freq - 1) & 3)) + ); +} + +esp_err_t pcf2131_get_clkout(i2c_dev_t *dev, pcf2131_clkout_freq_t *freq) +{ + CHECK_ARG(dev && freq); + + uint8_t v; + CHECK(read_reg(dev, REG_CLKOUT, &v)); + *freq = v & BV(BIT_CLKOUT_FE) ? (v & 3) + 1 : PCF2131_DISABLED; + + return ESP_OK; +} + +esp_err_t pcf2131_set_timer_settings(i2c_dev_t *dev, bool int_enable, pcf2131_timer_clock_t clock) +{ + CHECK_ARG(dev); + + I2C_DEV_TAKE_MUTEX(dev); + I2C_DEV_CHECK(dev, update_reg_nolock(dev, REG_CTRL_STATUS2, + BV(BIT_CTRL_STATUS2_TIE), int_enable ? BV(BIT_CTRL_STATUS2_TIE) : 0)); + I2C_DEV_CHECK(dev, update_reg_nolock(dev, REG_TIMER_CTRL, MASK_TIMER_CTRL_TD, clock)); + I2C_DEV_GIVE_MUTEX(dev); + + return ESP_OK; +} + +esp_err_t pcf2131_get_timer_settings(i2c_dev_t *dev, bool *int_enabled, pcf2131_timer_clock_t *clock) +{ + CHECK_ARG(dev && int_enabled && clock); + + uint8_t s, t; + I2C_DEV_TAKE_MUTEX(dev); + I2C_DEV_CHECK(dev, read_reg_nolock(dev, REG_CTRL_STATUS2, &s)); + I2C_DEV_CHECK(dev, read_reg_nolock(dev, REG_TIMER_CTRL, &t)); + I2C_DEV_GIVE_MUTEX(dev); + + *int_enabled = s & BV(BIT_CTRL_STATUS2_TIE) ? true : false; + *clock = t & MASK_TIMER_CTRL_TD; + + return ESP_OK; +} + +esp_err_t pcf2131_set_timer_value(i2c_dev_t *dev, uint8_t value) +{ + CHECK_ARG(dev); + + return write_reg(dev, REG_TIMER, value); +} + +esp_err_t pcf2131_get_timer_value(i2c_dev_t *dev, uint8_t *value) +{ + CHECK_ARG(dev && value); + + return read_reg(dev, REG_TIMER, value); +} + +esp_err_t pcf2131_start_timer(i2c_dev_t *dev) +{ + CHECK_ARG(dev); + + return update_reg(dev, REG_TIMER_CTRL, BV(BIT_TIMER_CTRL_TE), BV(BIT_TIMER_CTRL_TE)); +} + +esp_err_t pcf2131_stop_timer(i2c_dev_t *dev) +{ + CHECK_ARG(dev); + + return update_reg(dev, REG_TIMER_CTRL, BV(BIT_TIMER_CTRL_TE), 0); +} + +esp_err_t pcf2131_get_timer_flag(i2c_dev_t *dev, bool *timer) +{ + CHECK_ARG(dev && timer); + + uint8_t v; + CHECK(read_reg(dev, REG_CTRL_STATUS2, &v)); + *timer = v & BIT_CTRL_STATUS2_TF ? true : false; + + return ESP_OK; +} + +esp_err_t pcf2131_clear_timer_flag(i2c_dev_t *dev) +{ + CHECK_ARG(dev); + + return update_reg(dev, REG_CTRL_STATUS2, BV(BIT_CTRL_STATUS2_TF), 0); +} + +esp_err_t pcf2131_set_alarm(i2c_dev_t *dev, bool int_enable, uint32_t flags, struct tm *time) +{ + CHECK_ARG(dev && time); + + I2C_DEV_TAKE_MUTEX(dev); + I2C_DEV_CHECK(dev, update_reg_nolock(dev, REG_CTRL_STATUS2, + BV(BIT_CTRL_STATUS2_AIE), int_enable ? BV(BIT_CTRL_STATUS2_AIE) : 0)); + uint8_t data[4] = { + dec2bcd(time->tm_min) | (flags & PCF2131_ALARM_MATCH_MIN ? 0 : BV(BIT_AE)), + dec2bcd(time->tm_hour) | (flags & PCF2131_ALARM_MATCH_HOUR ? 0 : BV(BIT_AE)), + dec2bcd(time->tm_mday) | (flags & PCF2131_ALARM_MATCH_DAY ? 0 : BV(BIT_AE)), + dec2bcd(time->tm_wday) | (flags & PCF2131_ALARM_MATCH_WEEKDAY ? 0 : BV(BIT_AE)), + }; + I2C_DEV_CHECK(dev, i2c_dev_write_reg(dev, REG_ALARM_MIN, data, 4)); + I2C_DEV_GIVE_MUTEX(dev); + + return ESP_OK; +} + +esp_err_t pcf2131_get_alarm(i2c_dev_t *dev, bool *int_enabled, uint32_t *flags, struct tm *time) +{ + CHECK_ARG(dev && int_enabled && flags && time); + + uint8_t data[4], s; + + I2C_DEV_TAKE_MUTEX(dev); + I2C_DEV_CHECK(dev, read_reg_nolock(dev, REG_CTRL_STATUS2, &s)); + I2C_DEV_CHECK(dev, i2c_dev_read_reg(dev, REG_ALARM_MIN, data, 4)); + I2C_DEV_GIVE_MUTEX(dev); + + *int_enabled = s & BV(BIT_CTRL_STATUS2_AIE) ? true : false; + *flags = 0; + if (!(data[0] & BV(BIT_AE))) + *flags |= PCF2131_ALARM_MATCH_MIN; + if (!(data[1] & BV(BIT_AE))) + *flags |= PCF2131_ALARM_MATCH_HOUR; + if (!(data[2] & BV(BIT_AE))) + *flags |= PCF2131_ALARM_MATCH_DAY; + if (!(data[3] & BV(BIT_AE))) + *flags |= PCF2131_ALARM_MATCH_WEEKDAY; + + time->tm_min = bcd2dec(data[0] & MASK_ALARM); + time->tm_hour = bcd2dec(data[1] & MASK_ALARM); + time->tm_mday = bcd2dec(data[2] & MASK_ALARM); + time->tm_wday = bcd2dec(data[3] & MASK_ALARM); + + return ESP_OK; +} + +esp_err_t pcf2131_get_alarm_flag(i2c_dev_t *dev, bool *alarm) +{ + CHECK_ARG(dev && alarm); + + uint8_t v; + CHECK(read_reg(dev, REG_CTRL_STATUS2, &v)); + *alarm = v & BIT_CTRL_STATUS2_AF ? true : false; + + return ESP_OK; +} + +esp_err_t pcf2131_clear_alarm_flag(i2c_dev_t *dev) +{ + CHECK_ARG(dev); + + return update_reg(dev, REG_CTRL_STATUS2, BV(BIT_CTRL_STATUS2_AF), 0); +} diff --git a/components/pcf2131/pcf2131.h b/components/pcf2131/pcf2131.h new file mode 100644 index 00000000..1a56c408 --- /dev/null +++ b/components/pcf2131/pcf2131.h @@ -0,0 +1,266 @@ +/* + * Copyright (c) 2020 Ruslan V. Uss + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of itscontributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file pcf2131.h + * @defgroup pcf2131 pcf2131 + * @{ + * + * ESP-IDF driver for PCF2131 (BM8563) real-time clock/calendar + * + * Copyright (c) 2020 Ruslan V. Uss + * + * BSD Licensed as described in the file LICENSE + */ +#ifndef __PCF2131_H__ +#define __PCF2131_H__ + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define PCF2131_I2C_ADDR 0x53 + +#define PCF2131_BATT_SWITCHOVER_EN 3 // enable battery switch over per Table 22 in datasheet (011 = batt. switch over en in direct, batt. low det. en) + +/** + * Frequency output at pin CLKOUT + */ +typedef enum { + PCF2131_DISABLED = 0, //!< CLKOUT output is inhibited and set high-impedance + PCF2131_32768HZ, //!< 32768 Hz + PCF2131_1024HZ, //!< 1024 Hz + PCF2131_32HZ, //!< 32 Hz + PCF2131_1HZ, //!< 1 Hz +} pcf2131_clkout_freq_t; + +/** + * Timer clock + */ +typedef enum { + PCF2131_TIMER_4096HZ = 0, //!< 4096 Hz + PCF2131_TIMER_64HZ, //!< 64 Hz + PCF2131_TIMER_1HZ, //!< 1 Hz + PCF2131_TIMER_1_60HZ //!< 1/60 Hz +} pcf2131_timer_clock_t; + +/** + * Flags to setup alarm + */ +typedef enum { + PCF2131_ALARM_MATCH_MIN = 0x01, //!< Alarm when minute matched + PCF2131_ALARM_MATCH_HOUR = 0x02, //!< Alarm when hour matched + PCF2131_ALARM_MATCH_DAY = 0x04, //!< Alarm when day matched + PCF2131_ALARM_MATCH_WEEKDAY = 0x08 //!< Alarm when weekday matched +} pcf2131_alarm_flags_t; + +/** + * @brief Initialize device descriptor + * + * @param dev I2C device descriptor + * @param port I2C port + * @param sda_gpio SDA GPIO + * @param scl_gpio SCL GPIO + * @return `ESP_OK` on success + */ +esp_err_t pcf2131_init_desc(i2c_dev_t *dev, i2c_port_t port, gpio_num_t sda_gpio, gpio_num_t scl_gpio); + +/** + * @brief Free device descriptor + * + * @param dev I2C device descriptor + * @return `ESP_OK` on success + */ +esp_err_t pcf2131_free_desc(i2c_dev_t *dev); + +/** + * @brief Initialize default device configuration in registers + * + * @param dev I2C device descriptor + * @return `ESP_OK` on success + */ +esp_err_t pcf2131_init_default_config(i2c_dev_t *dev); + +/** + * @brief Set the time on the RTC + * + * @param dev I2C device descriptor + * @param time Pointer to time struct + * @return `ESP_OK` on success + */ +esp_err_t pcf2131_set_time(i2c_dev_t *dev, struct tm *time); + +/** + * @brief Get the time from the RTC + * + * @param dev I2C device descriptor + * @param[out] time Pointer to time struct + * @param[out] valid Time validity, false when RTC had power failures + * @return `ESP_OK` on success + */ +esp_err_t pcf2131_get_time(i2c_dev_t *dev, struct tm *time, bool *valid); + +/** + * @brief Set output frequency on CLKOUT pin + * + * @param dev I2C device descriptor + * @param freq Frequency + * @return `ESP_OK` on success + */ +esp_err_t pcf2131_set_clkout(i2c_dev_t *dev, pcf2131_clkout_freq_t freq); + +/** + * @brief Get current frequency on CLKOUT pin + * + * @param dev I2C device descriptor + * @param[out] freq Frequency + * @return `ESP_OK` on success + */ +esp_err_t pcf2131_get_clkout(i2c_dev_t *dev, pcf2131_clkout_freq_t *freq); + +/** + * @brief Setup timer + * + * @param dev I2C device descriptor + * @param int_enable true for enable interrupt on timer + * @param clock Timer frequency + * @return `ESP_OK` on success + */ +esp_err_t pcf2131_set_timer_settings(i2c_dev_t *dev, bool int_enable, pcf2131_timer_clock_t clock); + +/** + * @brief Get timer settings + * + * @param dev I2C device descriptor + * @param[out] int_enabled true if timer interrupt is enabled + * @param[out] clock Timer frequency + * @return `ESP_OK` on success + */ +esp_err_t pcf2131_get_timer_settings(i2c_dev_t *dev, bool *int_enabled, pcf2131_timer_clock_t *clock); + +/** + * @brief Set timer register value + * + * @param dev I2C device descriptor + * @param value Value to set int timer register + * @return `ESP_OK` on success + */ +esp_err_t pcf2131_set_timer_value(i2c_dev_t *dev, uint8_t value); + +/** + * @brief Get timer register value + * + * @param dev I2C device descriptor + * @param[out] value Timer value + * @return `ESP_OK` on success + */ +esp_err_t pcf2131_get_timer_value(i2c_dev_t *dev, uint8_t *value); + +/** + * @brief Start timer + * + * @param dev I2C device descriptor + * @return `ESP_OK` on success + */ +esp_err_t pcf2131_start_timer(i2c_dev_t *dev); + +/** + * @brief Stop timer + * + * @param dev I2C device descriptor + * @return `ESP_OK` on success + */ +esp_err_t pcf2131_stop_timer(i2c_dev_t *dev); + +/** + * @brief Get state of the timer flag + * + * @param dev I2C device descriptor + * @param[out] timer true when flag is set + * @return `ESP_OK` on success + */ +esp_err_t pcf2131_get_timer_flag(i2c_dev_t *dev, bool *timer); + +/** + * @brief Clear timer flag + * + * @param dev I2C device descriptor + * @return `ESP_OK` on success + */ +esp_err_t pcf2131_clear_timer_flag(i2c_dev_t *dev); + +/** + * @brief Setup alarm + * + * @param dev I2C device descriptor + * @param int_enable true to enable alarm interrupt + * @param flags Alarm types, combination of pcf2131_alarm_flags_t values + * @param time Alarm time. Only tm_min, tm_hour, tm_mday and tm_wday are used + * @return `ESP_OK` on success + */ +esp_err_t pcf2131_set_alarm(i2c_dev_t *dev, bool int_enable, uint32_t flags, struct tm *time); + +/** + * @brief Get alarm settings + * + * @param dev I2C device descriptor + * @param[out] int_enabled true if alarm interrupt is enabled + * @param[out] flags Selected alarm types, combination of pcf2131_alarm_flags_t values + * @param[out] time Alarm time. Only tm_min, tm_hour, tm_mday and tm_wday are used + * @return `ESP_OK` on success + */ +esp_err_t pcf2131_get_alarm(i2c_dev_t *dev, bool *int_enabled, uint32_t *flags, struct tm *time); + +/** + * @brief Get alarm flag + * + * @param dev I2C device descriptor + * @param[out] alarm true if alarm occurred + * @return `ESP_OK` on success + */ +esp_err_t pcf2131_get_alarm_flag(i2c_dev_t *dev, bool *alarm); + +/** + * @brief Clear alarm flag + * + * @param dev I2C device descriptor + * @return `ESP_OK` on success + */ +esp_err_t pcf2131_clear_alarm_flag(i2c_dev_t *dev); + +#ifdef __cplusplus +} +#endif + +/**@}*/ + +#endif /* __PCF2131_H__ */