diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index 22c207c6..cac92aa8 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -76,13 +76,7 @@ else() add_subdirectory(src/basic_battery) endif() -# TODO target_sources(app PRIVATE src/zsw_clock.c) -#if (CONFIG_RTC) -# target_sources(app PRIVATE src/zsw_rtc.c) -#else() -#endif() - target_sources(app PRIVATE src/main.c) target_sources(app PRIVATE src/zsw_cpu_freq.c) target_sources(app PRIVATE src/zsw_retained_ram_storage.c) diff --git a/app/boards/arm/zswatch_nrf5340/zswatch_nrf5340_cpuapp_5.conf b/app/boards/arm/zswatch_nrf5340/zswatch_nrf5340_cpuapp_5.conf index 6d28823e..fe588f02 100644 --- a/app/boards/arm/zswatch_nrf5340/zswatch_nrf5340_cpuapp_5.conf +++ b/app/boards/arm/zswatch_nrf5340/zswatch_nrf5340_cpuapp_5.conf @@ -44,6 +44,7 @@ CONFIG_DEBUG_COREDUMP_BACKEND_OTHER=y CONFIG_RTC=y CONFIG_RTC_UPDATE=y +CONFIG_RTC_ALARM=y CONFIG_MISC_ENABLE_SYSTEM_RESET=n # Implemented in nPM, hence not needed in FW diff --git a/app/boards/arm/zswatch_nrf5340/zswatch_nrf5340_cpuapp_5.overlay b/app/boards/arm/zswatch_nrf5340/zswatch_nrf5340_cpuapp_5.overlay index 60d3c70b..d81dd5c4 100644 --- a/app/boards/arm/zswatch_nrf5340/zswatch_nrf5340_cpuapp_5.overlay +++ b/app/boards/arm/zswatch_nrf5340/zswatch_nrf5340_cpuapp_5.overlay @@ -113,6 +113,7 @@ aliases { spi-flash0 = &mx25u51245g; buzzer-pwm = &buzzer_pwm; + rtc = &rv_8263_c8; }; longpress: longpress { diff --git a/app/lvgl_resources b/app/lvgl_resources new file mode 100644 index 00000000..1ea8e23b Binary files /dev/null and b/app/lvgl_resources differ diff --git a/app/patches/zephyr/rv8263_rtc.patch b/app/patches/zephyr/0001-drivers-rtc-Add-support-for-Micro-Crystal-RV-8263-C8.patch similarity index 84% rename from app/patches/zephyr/rv8263_rtc.patch rename to app/patches/zephyr/0001-drivers-rtc-Add-support-for-Micro-Crystal-RV-8263-C8.patch index 35fdada1..b89ce515 100644 --- a/app/patches/zephyr/rv8263_rtc.patch +++ b/app/patches/zephyr/0001-drivers-rtc-Add-support-for-Micro-Crystal-RV-8263-C8.patch @@ -1,125 +1,48 @@ -diff --git a/drivers/rtc/rtc_utils.h b/drivers/rtc/rtc_utils.c -new file mode 100644 -index 0000000000..035034da56 ---- /dev/null -+++ b/drivers/rtc/rtc_utils.c -@@ -0,0 +1,58 @@ -+/* -+ * Copyright (c) 2023 Bjarki Arge Andreasen -+ * Copyright (c) 2024 Andrew Featherstone -+ * -+ * SPDX-License-Identifier: Apache-2.0 -+ */ -+ -+#include -+#include -+ -+#include -+ -+#include "rtc_utils.h" -+ -+bool rtc_utils_validate_rtc_time(const struct rtc_time *timeptr, uint16_t mask) -+{ -+ if ((mask & RTC_ALARM_TIME_MASK_SECOND) && (timeptr->tm_sec < 0 || timeptr->tm_sec > 59)) { -+ return false; -+ } -+ -+ if ((mask & RTC_ALARM_TIME_MASK_MINUTE) && (timeptr->tm_min < 0 || timeptr->tm_min > 59)) { -+ return false; -+ } -+ -+ if ((mask & RTC_ALARM_TIME_MASK_HOUR) && (timeptr->tm_hour < 0 || timeptr->tm_hour > 23)) { -+ return false; -+ } -+ -+ if ((mask & RTC_ALARM_TIME_MASK_MONTH) && (timeptr->tm_mon < 0 || timeptr->tm_mon > 11)) { -+ return false; -+ } -+ -+ if ((mask & RTC_ALARM_TIME_MASK_MONTHDAY) && -+ (timeptr->tm_mday < 1 || timeptr->tm_mday > 31)) { -+ return false; -+ } -+ -+ if ((mask & RTC_ALARM_TIME_MASK_YEAR) && (timeptr->tm_year < 0 || timeptr->tm_year > 199)) { -+ return false; -+ } -+ -+ if ((mask & RTC_ALARM_TIME_MASK_WEEKDAY) && -+ (timeptr->tm_wday < 0 || timeptr->tm_wday > 6)) { -+ return false; -+ } -+ -+ if ((mask & RTC_ALARM_TIME_MASK_YEARDAY) && -+ (timeptr->tm_yday < 0 || timeptr->tm_yday > 365)) { -+ return false; -+ } -+ -+ if ((mask & RTC_ALARM_TIME_MASK_NSEC) && -+ (timeptr->tm_nsec < 0 || timeptr->tm_nsec > 999999999)) { -+ return false; -+ } -+ -+ return true; -+} -diff --git a/drivers/rtc/rtc_utils.h b/drivers/rtc/rtc_utils.h -new file mode 100644 -index 0000000000..035034da56 ---- /dev/null -+++ b/drivers/rtc/rtc_utils.h -@@ -0,0 +1,28 @@ -+/* -+ * Copyright (c) 2023 Bjarki Arge Andreasen -+ * Copyright (c) 2024 Andrew Featherstone -+ * -+ * SPDX-License-Identifier: Apache-2.0 -+ */ -+ -+#ifndef ZEPHYR_DRIVERS_RTC_RTC_UTILS_H_ -+#define ZEPHYR_DRIVERS_RTC_RTC_UTILS_H_ -+ -+#include -+#include -+ -+#include -+ -+/** -+ * @brief Validate a datetime with a mask -+ * -+ * Ensure that any fields selected by mask contain a valid value. -+ * -+ * @param timeptr The time to set -+ * @param mask Mask of fields to validate -+ * -+ * @return true if the required fields are valid. -+ */ -+bool rtc_utils_validate_rtc_time(const struct rtc_time *timeptr, uint16_t mask); -+ -+#endif /* ZEPHYR_DRIVERS_RTC_RTC_UTILS_H_ */ +From 37d6bc082782f0b66420c68f4ff57db5eb283d90 Mon Sep 17 00:00:00 2001 +From: Daniel Kampert +Date: Mon, 27 May 2024 22:00:48 +0200 +Subject: [PATCH] drivers: rtc: Add support for Micro Crystal RV-8263-C8 + +- Add Micro Crystal RV-8263-C8 RTC driver + +Signed-off-by: Daniel Kampert +--- + drivers/rtc/CMakeLists.txt | 1 + + drivers/rtc/Kconfig | 1 + + drivers/rtc/Kconfig.rv8263 | 11 + + drivers/rtc/rtc_rv8263.c | 787 ++++++++++++++++++ + dts/bindings/rtc/microcrystal,rv-8263-c8.yaml | 30 + + 5 files changed, 830 insertions(+) + create mode 100644 drivers/rtc/Kconfig.rv8263 + create mode 100644 drivers/rtc/rtc_rv8263.c + create mode 100644 dts/bindings/rtc/microcrystal,rv-8263-c8.yaml + diff --git a/drivers/rtc/CMakeLists.txt b/drivers/rtc/CMakeLists.txt -index 65d822d..4236ad5 100644 +index eb631cd5ac1..ff627641536 100644 --- a/drivers/rtc/CMakeLists.txt +++ b/drivers/rtc/CMakeLists.txt -@@ -5,6 +5,9 @@ zephyr_syscall_header(${ZEPHYR_BASE}/include/zephyr/drivers/rtc.h) +@@ -7,6 +7,7 @@ zephyr_library() - zephyr_library() + zephyr_library_sources(rtc_utils.c) -+zephyr_library_sources(rtc_utils.c) -+ +zephyr_library_sources_ifdef(CONFIG_RTC_RV8263 rtc_rv8263.c) zephyr_library_sources_ifdef(CONFIG_RTC_AM1805 rtc_am1805.c) zephyr_library_sources_ifdef(CONFIG_RTC_DS1307 rtc_ds1307.c) zephyr_library_sources_ifdef(CONFIG_USERSPACE rtc_handlers.c) -index 46bd2562dd..2a1d5fa05b 100644 +diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig +index 8dd4034ece1..b5e175f5bd6 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig -@@ -53,1 +53,2 @@ source "drivers/rtc/Kconfig.sam" +@@ -54,5 +54,6 @@ source "drivers/rtc/Kconfig.sam" + source "drivers/rtc/Kconfig.smartbond" + source "drivers/rtc/Kconfig.stm32" + source "drivers/rtc/Kconfig.numaker" +source "drivers/rtc/Kconfig.rv8263" endif # RTC diff --git a/drivers/rtc/Kconfig.rv8263 b/drivers/rtc/Kconfig.rv8263 new file mode 100644 -index 0000000000..035034da56 +index 00000000000..035034da56f --- /dev/null +++ b/drivers/rtc/Kconfig.rv8263 @@ -0,0 +1,11 @@ @@ -136,10 +59,10 @@ index 0000000000..035034da56 + Micro Crystal RV-8263-C8 RTC driver. diff --git a/drivers/rtc/rtc_rv8263.c b/drivers/rtc/rtc_rv8263.c new file mode 100644 -index 0000000000..bb82ed7d9b +index 00000000000..aa1ce3aca12 --- /dev/null +++ b/drivers/rtc/rtc_rv8263.c -@@ -0,0 +1,771 @@ +@@ -0,0 +1,787 @@ +/* Copyright (c) 2024 Daniel Kampert + * Author: Daniel Kampert + */ @@ -240,6 +163,9 @@ index 0000000000..bb82ed7d9b + +#if (CONFIG_RTC_ALARM || CONFIG_RTC_UPDATE) && DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios) + const struct device *dev; ++#endif ++ ++#if (CONFIG_RTC_ALARM || CONFIG_RTC_UPDATE) && DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios) + struct gpio_callback gpio_cb; +#endif + @@ -259,19 +185,19 @@ index 0000000000..bb82ed7d9b +static int rv8263c8_update_disable_timer(const struct device *dev) +{ + int err; -+ uint8_t buf[2]; ++ uint8_t reg; + const struct rv8263c8_config *config = dev->config; + + /* Value 0 disables the timer. */ -+ buf[0] = RV8263C8_REGISTER_TIMER_VALUE; -+ buf[1] = 0; -+ err = i2c_write_dt(&config->i2c_bus, buf, 2); ++ reg = 0; ++ err = i2c_burst_write_dt(&config->i2c_bus, RV8263C8_REGISTER_TIMER_VALUE, ®, ++ sizeof(reg)); + if (err < 0) { + return err; + } + -+ buf[0] = RV8263C8_REGISTER_TIMER_MODE; -+ return i2c_write_dt(&config->i2c_bus, buf, 2); ++ return i2c_burst_write_dt(&config->i2c_bus, RV8263C8_REGISTER_TIMER_MODE, ®, ++ sizeof(reg)); +} + +#if (CONFIG_RTC_ALARM || CONFIG_RTC_UPDATE) && DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios) @@ -283,11 +209,11 @@ index 0000000000..bb82ed7d9b + + struct rv8263c8_data *data = CONTAINER_OF(p_cb, struct rv8263c8_data, gpio_cb); + -+#if CONFIG_RTC_ALARM ++#if CONFIG_RTC_ALARM && DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios) + k_work_submit(&data->alarm_work); +#endif + -+#if CONFIG_RTC_UPDATE ++#if CONFIG_RTC_UPDATE && DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios) + k_work_submit(&data->update_work); +#endif +} @@ -322,21 +248,21 @@ index 0000000000..bb82ed7d9b +static int rv8263c8_update_enable_timer(const struct device *dev) +{ + int err; ++ uint8_t reg; + const struct rv8263c8_config *config = dev->config; -+ uint8_t buf[2]; + + /* Set the timer preload value for 1 second. */ -+ buf[0] = RV8263C8_REGISTER_TIMER_VALUE; -+ buf[1] = 1; -+ err = i2c_write_dt(&config->i2c_bus, buf, 2); ++ reg = 1; ++ err = i2c_burst_write_dt(&config->i2c_bus, RV8263C8_REGISTER_TIMER_VALUE, ®, ++ sizeof(reg)); + if (err < 0) { + return err; + } + -+ buf[0] = RV8263C8_REGISTER_TIMER_MODE; -+ buf[1] = RV8263_BM_TD_1HZ | RV8263_BM_TE_ENABLE | RV8263_BM_TIE_ENABLE | -+ RV8263_BM_TI_TP_PULSE; -+ return i2c_write_dt(&config->i2c_bus, buf, 2); ++ reg = RV8263_BM_TD_1HZ | RV8263_BM_TE_ENABLE | RV8263_BM_TIE_ENABLE | RV8263_BM_TI_TP_PULSE; ++ ++ return i2c_burst_write_dt(&config->i2c_bus, RV8263C8_REGISTER_TIMER_MODE, ®, ++ sizeof(reg)); +} + +static void rv8263c8_update_worker(struct k_work *p_work) @@ -364,7 +290,7 @@ index 0000000000..bb82ed7d9b + +static int rv8263c8_time_set(const struct device *dev, const struct rtc_time *timeptr) +{ -+ uint8_t regs[8]; ++ uint8_t regs[7]; + const struct rv8263c8_config *config = dev->config; + + if (timeptr == NULL || (timeptr->tm_year < RV8263_YEAR_OFFSET)) { @@ -377,16 +303,15 @@ index 0000000000..bb82ed7d9b + timeptr->tm_year, timeptr->tm_mon, timeptr->tm_mday, timeptr->tm_wday, + timeptr->tm_hour, timeptr->tm_min, timeptr->tm_sec); + -+ regs[0] = RV8263C8_REGISTER_SECONDS; -+ regs[1] = bin2bcd(timeptr->tm_sec) & SECONDS_BITS; -+ regs[2] = bin2bcd(timeptr->tm_min) & MINUTES_BITS; -+ regs[3] = bin2bcd(timeptr->tm_hour) & HOURS_BITS; -+ regs[4] = bin2bcd(timeptr->tm_mday) & DATE_BITS; -+ regs[5] = bin2bcd(timeptr->tm_wday) & WEEKDAY_BITS; -+ regs[6] = bin2bcd(timeptr->tm_mon) & MONTHS_BITS; -+ regs[7] = bin2bcd(timeptr->tm_year - RV8263_YEAR_OFFSET) & YEAR_BITS; ++ regs[0] = bin2bcd(timeptr->tm_sec) & SECONDS_BITS; ++ regs[1] = bin2bcd(timeptr->tm_min) & MINUTES_BITS; ++ regs[2] = bin2bcd(timeptr->tm_hour) & HOURS_BITS; ++ regs[3] = bin2bcd(timeptr->tm_mday) & DATE_BITS; ++ regs[4] = bin2bcd(timeptr->tm_wday) & WEEKDAY_BITS; ++ regs[5] = bin2bcd(timeptr->tm_mon) & MONTHS_BITS; ++ regs[6] = bin2bcd(timeptr->tm_year - RV8263_YEAR_OFFSET) & YEAR_BITS; + -+ return i2c_write_dt(&config->i2c_bus, regs, 8); ++ return i2c_burst_write_dt(&config->i2c_bus, RV8263C8_REGISTER_SECONDS, regs, sizeof(regs)); +} + +static int rv8263c8_time_get(const struct device *dev, struct rtc_time *timeptr) @@ -468,24 +393,38 @@ index 0000000000..bb82ed7d9b + return err; + } + -+ temp = config->clkout; ++ temp = 0x00; ++ if (config->clkout == 0) { ++ temp = 0x07; ++ } else if (config->clkout == 1) { ++ temp = 0x06; ++ } else if (config->clkout == 1024) { ++ temp = 0x05; ++ } else if (config->clkout == 2048) { ++ temp = 0x04; ++ } else if (config->clkout == 4096) { ++ temp = 0x03; ++ } else if (config->clkout == 8192) { ++ temp = 0x02; ++ } else if (config->clkout == 16384) { ++ temp = 0x01; ++ } ++ + LOG_DBG("Configure ClkOut: %u", temp); + + err = i2c_reg_write_byte_dt(&config->i2c_bus, RV8263C8_REGISTER_CONTROL_2, -+ RV8263C8_BM_AF | temp); ++ RV8263C8_BM_MINUTE_INT_DISABLE | ++ RV8263C8_BM_HALF_MINUTE_INT_DISABLE | temp); + if (err < 0) { + LOG_ERR("Error while writing CONTROL_2! Error: %i", err); + return err; + } + -+ LOG_DBG("Configure ClkOut: %u", temp); -+ +#if CONFIG_RTC_UPDATE && DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios) -+ uint8_t buf[2]; ++ uint8_t regs = 0; + -+ buf[0] = RV8263C8_REGISTER_TIMER_MODE; -+ buf[1] = 0; -+ err = i2c_write_dt(&config->i2c_bus, buf, 2); ++ err = i2c_burst_write_dt(&config->i2c_bus, RV8263C8_REGISTER_TIMER_MODE, ®s, ++ sizeof(regs)); + if (err < 0) { + LOG_ERR("Error while writing CONTROL2! Error: %i", err); + return err; @@ -903,8 +842,8 @@ index 0000000000..bb82ed7d9b + static struct rv8263c8_data rv8263c8_data_##inst; \ + static const struct rv8263c8_config rv8263c8_config_##inst = { \ + .i2c_bus = I2C_DT_SPEC_INST_GET(inst), \ -+ .clkout = DT_INST_ENUM_IDX(inst, clkout), \ -+ IF_ENABLED(1, \ ++ .clkout = DT_INST_PROP_OR(inst, clkout, 0), \ ++ IF_ENABLED(DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios), \ + (.int_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, int_gpios, {0})))}; \ + DEVICE_DT_INST_DEFINE(inst, &rv8263c8_init, NULL, &rv8263c8_data_##inst, \ + &rv8263c8_config_##inst, POST_KERNEL, CONFIG_RTC_INIT_PRIORITY, \ @@ -913,10 +852,10 @@ index 0000000000..bb82ed7d9b +DT_INST_FOREACH_STATUS_OKAY(RV8263_DEFINE) diff --git a/dts/bindings/rtc/microcrystal,rv-8263-c8.yaml b/dts/bindings/rtc/microcrystal,rv-8263-c8.yaml new file mode 100644 -index 0000000000..da6c246dbc +index 00000000000..6c9205f4881 --- /dev/null +++ b/dts/bindings/rtc/microcrystal,rv-8263-c8.yaml -@@ -0,0 +1,31 @@ +@@ -0,0 +1,30 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright (c) 2024 Daniel Kampert +# Author: Daniel Kampert @@ -935,16 +874,18 @@ index 0000000000..da6c246dbc + + clkout: + type: int -+ default: 0 ++ default: 32768 + enum: + - 32768 + - 16384 + - 8192 + - 4096 -+ - 2048 + - 1024 + - 1 + - 0 + description: -+ Enable CLKOUT at given frequency. When disabled, CLKOUT pin is LOW. -+ The default is 0 and corresponds to the disable the CLKOUT signal. ++ Enable CLKOUT at given frequency. When disabled, CLKOUT pin is LOW. Set to 0 to ++ disable the CLKOUT signal. +-- +2.34.1 + diff --git a/app/patches/zephyr/0001-drivers-rtc-Change-error-to-ENODATA-in-get-time-func.patch b/app/patches/zephyr/0001-drivers-rtc-Change-error-to-ENODATA-in-get-time-func.patch new file mode 100644 index 00000000..cf1d623c --- /dev/null +++ b/app/patches/zephyr/0001-drivers-rtc-Change-error-to-ENODATA-in-get-time-func.patch @@ -0,0 +1,28 @@ +From 3bf35ce696e1f3b0433bf3930dbd685daf952b35 Mon Sep 17 00:00:00 2001 +From: Daniel Kampert +Date: Wed, 31 Jul 2024 08:37:52 +0200 +Subject: [PATCH] drivers: rtc: Change error to ENODATA in get time function + +- Change the error type from ECANCELED to ENODATA + +Signed-off-by: Daniel Kampert +--- + drivers/rtc/rtc_rv8263.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/rtc/rtc_rv8263.c b/drivers/rtc/rtc_rv8263.c +index bb82ed7d9b7..bb3ae034e08 100644 +--- a/drivers/rtc/rtc_rv8263.c ++++ b/drivers/rtc/rtc_rv8263.c +@@ -264,7 +264,7 @@ static int rv8263c8_time_get(const struct device *dev, struct rtc_time *timeptr) + + /* Return an error when the oscillator is stopped. */ + if (regs[0] & RV8263_BM_OS) { +- return -ECANCELED; ++ return -ENODATA; + } + + timeptr->tm_sec = bcd2bin(regs[0] & SECONDS_BITS); +-- +2.34.1 + diff --git a/app/patches/zephyr/0001-drivers-rtc-OS-flag-is-never-cleared.patch b/app/patches/zephyr/0001-drivers-rtc-OS-flag-is-never-cleared.patch new file mode 100644 index 00000000..c6fc2d38 --- /dev/null +++ b/app/patches/zephyr/0001-drivers-rtc-OS-flag-is-never-cleared.patch @@ -0,0 +1,71 @@ +From cb74eddff74044ab50ed06c2e46e1eda48442758 Mon Sep 17 00:00:00 2001 +From: Daniel Kampert +Date: Tue, 27 Aug 2024 13:16:19 +0200 +Subject: [PATCH] drivers: rtc: OS flag is never cleared + +Clear the OS flag when reading the time +and when the flag is set. Also clear the +flag once during the initialization. + +Signed-off-by: Daniel Kampert +--- + drivers/rtc/rtc_rv8263.c | 22 +++++++++++++++++++--- + 1 file changed, 19 insertions(+), 3 deletions(-) + +diff --git a/drivers/rtc/rtc_rv8263.c b/drivers/rtc/rtc_rv8263.c +index f3cf86c6c7a..bd950d96b59 100644 +--- a/drivers/rtc/rtc_rv8263.c ++++ b/drivers/rtc/rtc_rv8263.c +@@ -249,6 +249,9 @@ static int rv8263c8_time_get(const struct device *dev, struct rtc_time *timeptr) + + /* Return an error when the oscillator is stopped. */ + if (regs[0] & RV8263_BM_OS) { ++ /* Clear the OS flag. */ ++ regs[0] &= ~RV8263_BM_OS; ++ i2c_reg_write_byte_dt(&config->i2c_bus, RV8263C8_REGISTER_SECONDS, regs[0]); + return -ENODATA; + } + +@@ -281,7 +284,7 @@ static int rv8263c8_time_get(const struct device *dev, struct rtc_time *timeptr) + static int rv8263c8_init(const struct device *dev) + { + int err; +- int temp; ++ uint8_t temp; + struct rv8263c8_data *data = dev->data; + const struct rv8263c8_config *config = dev->config; + +@@ -323,6 +326,20 @@ static int rv8263c8_init(const struct device *dev) + + LOG_DBG("Configure ClkOut: %u", temp); + ++ /* Clear the OS flag initialy. */ ++ err = i2c_reg_read_byte_dt(&config->i2c_bus, RV8263C8_REGISTER_SECONDS, &temp); ++ if (err < 0) { ++ return err; ++ } ++ ++ if (temp & RV8263_BM_OS) { ++ err = i2c_reg_write_byte_dt(&config->i2c_bus, RV8263C8_REGISTER_SECONDS, temp); ++ if (err < 0) { ++ LOG_ERR("Error while clearing OS flag! Error: %i", err); ++ return err; ++ } ++ } ++ + #if CONFIG_RTC_UPDATE && DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios) + uint8_t buf[2]; + +@@ -712,8 +729,7 @@ static const struct rtc_driver_api rv8263c8_driver_api = { + static const struct rv8263c8_config rv8263c8_config_##inst = { \ + .i2c_bus = I2C_DT_SPEC_INST_GET(inst), \ + .clkout = DT_INST_ENUM_IDX(inst, clkout), \ +- IF_ENABLED(DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios), \ +- (.int_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, int_gpios, {0})))}; \ ++ IF_ENABLED(1, (.int_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, int_gpios, {0})))}; \ + DEVICE_DT_INST_DEFINE(inst, &rv8263c8_init, NULL, &rv8263c8_data_##inst, \ + &rv8263c8_config_##inst, POST_KERNEL, CONFIG_RTC_INIT_PRIORITY, \ + &rv8263c8_driver_api); +-- +2.34.1 + diff --git a/app/patches/zephyr/0001-drivers-rtc-Wrong-alarm-mask-in-rtc_alarm_get_time.patch b/app/patches/zephyr/0001-drivers-rtc-Wrong-alarm-mask-in-rtc_alarm_get_time.patch new file mode 100644 index 00000000..b1e0bda8 --- /dev/null +++ b/app/patches/zephyr/0001-drivers-rtc-Wrong-alarm-mask-in-rtc_alarm_get_time.patch @@ -0,0 +1,268 @@ +From e5d4b66b933f64e4d2c23b383744f33a31392af1 Mon Sep 17 00:00:00 2001 +From: Daniel Kampert +Date: Sat, 3 Aug 2024 12:24:44 +0200 +Subject: [PATCH] drivers: rtc: Wrong alarm mask in rtc_alarm_get_time + +Fixing 3 issues: + +1. The mask can be wrong if the alarm register is +set to a MAX value because the alarm bit is the +highest in the alarm register. The mask is now +generated by checking the AE_x bits in the time +registers. + +2. Fixing possible NULL pointer exception in +alarm_set_time API. timeptr can be set to NULL +with mask 0 in the alarm_set_time function. +The regs variable for the I2C communication +is written with the correct value from timeptr +only when the right bit in the mask is set. + +3. rv8263c8_alarm_set_time() now resets the +alarm status. + +4. Interrupts are now enabled by using +rv8263c8_alarm_set_time() rather than when +setting an alarm callback. + +Signed-off-by: Daniel Kampert +--- + drivers/rtc/rtc_rv8263.c | 134 ++++++++++++--------------------------- + 1 file changed, 42 insertions(+), 92 deletions(-) + +diff --git a/drivers/rtc/rtc_rv8263.c b/drivers/rtc/rtc_rv8263.c +index bb3ae034e08..c1df2e2dec5 100644 +--- a/drivers/rtc/rtc_rv8263.c ++++ b/drivers/rtc/rtc_rv8263.c +@@ -65,21 +65,6 @@ + #define YEAR_BITS GENMASK(7, 0) + #define VALIDATE_24HR BIT(6) + +-#define MIN_SEC 0 +-#define MAX_SEC 59 +-#define MIN_MIN 0 +-#define MAX_MIN 59 +-#define MIN_HOUR 0 +-#define MAX_HOUR 23 +-#define MAX_WDAY 7 +-#define MIN_WDAY 1 +-#define MAX_MDAY 31 +-#define MIN_MDAY 1 +-#define MAX_MON 12 +-#define MIN_MON 1 +-#define MIN_YEAR_DIFF 0 +-#define MAX_YEAR_DIFF 99 +- + #define DT_DRV_COMPAT microcrystal_rv_8263_c8 + + LOG_MODULE_REGISTER(microcrystal_rv8263c8, CONFIG_RTC_LOG_LEVEL); +@@ -244,7 +229,7 @@ static int rv8263c8_time_set(const struct device *dev, const struct rtc_time *ti + regs[6] = bin2bcd(timeptr->tm_mon) & MONTHS_BITS; + regs[7] = bin2bcd(timeptr->tm_year - RV8263_YEAR_OFFSET) & YEAR_BITS; + +- return i2c_write_dt(&config->i2c_bus, regs, 8); ++ return i2c_write_dt(&config->i2c_bus, regs, sizeof(regs)); + } + + static int rv8263c8_time_get(const struct device *dev, struct rtc_time *timeptr) +@@ -413,7 +398,7 @@ static int rv8263c8_alarm_set_time(const struct device *dev, uint16_t id, uint16 + const struct rtc_time *timeptr) + { + int err; +- uint8_t regs[5]; ++ uint8_t regs[6]; + const struct rv8263c8_config *config = dev->config; + + ARG_UNUSED(id); +@@ -422,86 +407,69 @@ static int rv8263c8_alarm_set_time(const struct device *dev, uint16_t id, uint16 + return -EINVAL; + } + +- /* Disable the alarm when mask is zero. */ +- if (mask == 0) { +- return i2c_reg_update_byte_dt(&config->i2c_bus, RV8263C8_REGISTER_CONTROL_2, +- RV8263C8_BM_ALARM_INT_ENABLE, +- RV8263C8_BM_ALARM_INT_DISABLE); +- } +- + if (!rtc_utils_validate_rtc_time(timeptr, mask)) { + LOG_ERR("Invalid mask!"); + return -EINVAL; + } + +- regs[0] = bin2bcd(timeptr->tm_sec) & SECONDS_BITS; +- regs[1] = bin2bcd(timeptr->tm_min) & MINUTES_BITS; +- regs[2] = bin2bcd(timeptr->tm_hour) & HOURS_BITS; +- regs[3] = bin2bcd(timeptr->tm_mday) & DATE_BITS; +- regs[4] = bin2bcd(timeptr->tm_wday) & WEEKDAY_BITS; +- +- if (mask & RTC_ALARM_TIME_MASK_SECOND) { +- err = i2c_reg_write_byte_dt(&config->i2c_bus, RV8263C8_REGISTER_SECONDS_ALARM, +- RV8263C8_BM_ALARM_ENABLE | regs[0]); ++ if (mask == 0) { ++ err = i2c_reg_update_byte_dt(&config->i2c_bus, RV8263C8_REGISTER_CONTROL_2, ++ RV8263C8_BM_ALARM_INT_ENABLE | RV8263C8_BM_AF, ++ RV8263C8_BM_ALARM_INT_DISABLE); + } else { +- err = i2c_reg_write_byte_dt(&config->i2c_bus, RV8263C8_REGISTER_SECONDS_ALARM, +- RV8263C8_BM_ALARM_DISABLE); ++ /* Clear the AIE and AF bit to prevent false triggering of the alarm. */ ++ err = i2c_reg_update_byte_dt(&config->i2c_bus, RV8263C8_REGISTER_CONTROL_2, ++ RV8263C8_BM_ALARM_INT_ENABLE | RV8263C8_BM_AF, 0); + } + + if (err < 0) { +- LOG_ERR("Error while writing SECONDS alarm! Error: %i", err); ++ LOG_ERR("Error while enabling alarm! Error: %i", err); + return err; + } + +- if (mask & RTC_ALARM_TIME_MASK_MINUTE) { +- err = i2c_reg_write_byte_dt(&config->i2c_bus, RV8263C8_REGISTER_MINUTES_ALARM, +- RV8263C8_BM_ALARM_ENABLE | regs[1]); ++ regs[0] = RV8263C8_REGISTER_SECONDS_ALARM; ++ ++ if (mask & RTC_ALARM_TIME_MASK_SECOND) { ++ regs[1] = bin2bcd(timeptr->tm_sec) & SECONDS_BITS; + } else { +- err = i2c_reg_write_byte_dt(&config->i2c_bus, RV8263C8_REGISTER_MINUTES_ALARM, +- RV8263C8_BM_ALARM_DISABLE); ++ regs[1] = RV8263C8_BM_ALARM_DISABLE; + } + +- if (err < 0) { +- LOG_ERR("Error while writing MINUTE alarm! Error: %i", err); +- return err; ++ if (mask & RTC_ALARM_TIME_MASK_MINUTE) { ++ regs[2] = bin2bcd(timeptr->tm_min) & MINUTES_BITS; ++ } else { ++ regs[2] = RV8263C8_BM_ALARM_DISABLE; + } + + if (mask & RTC_ALARM_TIME_MASK_HOUR) { +- err = i2c_reg_write_byte_dt(&config->i2c_bus, RV8263C8_REGISTER_HOURS_ALARM, +- RV8263C8_BM_ALARM_ENABLE | regs[2]); ++ regs[3] = bin2bcd(timeptr->tm_min) & HOURS_BITS; + } else { +- err = i2c_reg_write_byte_dt(&config->i2c_bus, RV8263C8_REGISTER_HOURS_ALARM, +- RV8263C8_BM_ALARM_DISABLE); +- } +- +- if (err < 0) { +- LOG_ERR("Error while writing HOUR alarm! Error: %i", err); +- return err; ++ regs[3] = RV8263C8_BM_ALARM_DISABLE; + } + + if (mask & RTC_ALARM_TIME_MASK_MONTHDAY) { +- err = i2c_reg_write_byte_dt(&config->i2c_bus, RV8263C8_REGISTER_DATE_ALARM, +- RV8263C8_BM_ALARM_ENABLE | regs[3]); ++ regs[4] = bin2bcd(timeptr->tm_min) & DATE_BITS; + } else { +- err = i2c_reg_write_byte_dt(&config->i2c_bus, RV8263C8_REGISTER_DATE_ALARM, +- RV8263C8_BM_ALARM_DISABLE); +- } +- +- if (err < 0) { +- LOG_ERR("Error while writing MONTHDAY alarm! Error: %i", err); +- return err; ++ regs[4] = RV8263C8_BM_ALARM_DISABLE; + } + + if (mask & RTC_ALARM_TIME_MASK_WEEKDAY) { +- err = i2c_reg_write_byte_dt(&config->i2c_bus, RV8263C8_REGISTER_WEEKDAY_ALARM, +- RV8263C8_BM_ALARM_ENABLE | regs[4]); ++ regs[5] = bin2bcd(timeptr->tm_min) & WEEKDAY_BITS; + } else { +- err = i2c_reg_write_byte_dt(&config->i2c_bus, RV8263C8_REGISTER_WEEKDAY_ALARM, +- RV8263C8_BM_ALARM_DISABLE); ++ regs[5] = RV8263C8_BM_ALARM_DISABLE; + } + ++ err = i2c_write_dt(&config->i2c_bus, regs, sizeof(regs)); + if (err < 0) { +- LOG_ERR("Error while writing WEEKDAY alarm! Error: %i", err); ++ LOG_ERR("Error while setting alarm time! Error: %i", < err); ++ return err; ++ } ++ ++ if (mask != 0) { ++ /* Enable the alarm interrupt */ ++ err = i2c_reg_update_byte_dt(&config->i2c_bus, RV8263C8_REGISTER_CONTROL_2, ++ RV8263C8_BM_ALARM_INT_ENABLE, ++ RV8263C8_BM_ALARM_INT_ENABLE); + } + + return err; +@@ -529,27 +497,28 @@ static int rv8263c8_alarm_get_time(const struct device *dev, uint16_t id, uint16 + return err; + } + +- if (value[0] <= MAX_SEC) { ++ /* Check if the highest bit is not set. If so the alarm is enabled. */ ++ if ((value[0] & RV8263C8_BM_ALARM_DISABLE) == 0) { + timeptr->tm_sec = bcd2bin(value[0]) & SECONDS_BITS; + (*p_mask) |= RTC_ALARM_TIME_MASK_SECOND; + } + +- if (value[1] <= MAX_MIN) { ++ if ((value[1] & RV8263C8_BM_ALARM_DISABLE) == 0) { + timeptr->tm_min = bcd2bin(value[1]) & MINUTES_BITS; + (*p_mask) |= RTC_ALARM_TIME_MASK_MINUTE; + } + +- if (value[2] <= MAX_HOUR) { ++ if ((value[2] & RV8263C8_BM_ALARM_DISABLE) == 0) { + timeptr->tm_hour = bcd2bin(value[2]) & HOURS_BITS; + (*p_mask) |= RTC_ALARM_TIME_MASK_HOUR; + } + +- if (value[3] <= MAX_MDAY) { ++ if ((value[3] & RV8263C8_BM_ALARM_DISABLE) == 0) { + timeptr->tm_mday = bcd2bin(value[3]) & DATE_BITS; + (*p_mask) |= RTC_ALARM_TIME_MASK_MONTHDAY; + } + +- if (value[4] <= MAX_WDAY) { ++ if ((value[4] & RV8263C8_BM_ALARM_DISABLE) == 0) { + timeptr->tm_wday = bcd2bin(value[4]) & WEEKDAY_BITS; + (*p_mask) |= RTC_ALARM_TIME_MASK_WEEKDAY; + } +@@ -560,7 +529,6 @@ static int rv8263c8_alarm_get_time(const struct device *dev, uint16_t id, uint16 + static int rv8263c8_alarm_set_callback(const struct device *dev, uint16_t id, + rtc_alarm_callback callback, void *user_data) + { +- int err; + const struct rv8263c8_config *config = dev->config; + + #if DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios) +@@ -582,25 +550,7 @@ static int rv8263c8_alarm_set_callback(const struct device *dev, uint16_t id, + return -ENOTSUP; + #endif + +- if ((callback == NULL) && (user_data == NULL)) { +- LOG_DBG("Disable alarm function"); +- +- err = i2c_reg_update_byte_dt(&config->i2c_bus, RV8263C8_REGISTER_CONTROL_2, +- RV8263C8_BM_ALARM_INT_ENABLE, +- RV8263C8_BM_ALARM_INT_DISABLE); +- } else { +- LOG_DBG("Enable alarm function"); +- +- err = i2c_reg_update_byte_dt(&config->i2c_bus, RV8263C8_REGISTER_CONTROL_2, +- RV8263C8_BM_ALARM_INT_ENABLE | RV8263C8_BM_AF, +- RV8263C8_BM_ALARM_INT_ENABLE); +- } +- +- if (err < 0) { +- LOG_ERR("Error while writing CONTROL2! Error: %i", err); +- } +- +- return err; ++ return 0; + } + + static int rv8263c8_alarm_is_pending(const struct device *dev, uint16_t id) +-- +2.34.1 + diff --git a/app/patches/zephyr/0001-drivers-rtc-off-by-one-error-in-RV-8263-C8-driver.patch b/app/patches/zephyr/0001-drivers-rtc-off-by-one-error-in-RV-8263-C8-driver.patch new file mode 100644 index 00000000..ca2d2126 --- /dev/null +++ b/app/patches/zephyr/0001-drivers-rtc-off-by-one-error-in-RV-8263-C8-driver.patch @@ -0,0 +1,50 @@ +From 64c1d617d98157a218e7782e6785d293b5190251 Mon Sep 17 00:00:00 2001 +From: Daniel Kampert +Date: Tue, 20 Aug 2024 10:48:07 +0200 +Subject: [PATCH] drivers: rtc: off-by-one error in RV-8263-C8 driver + +tm_mon in rtc_time structure has a range [0, 11], +while the RTC expects [1, 12]. Add missing +increasing / decreasing of this value. + +Fix typo in debug log + +Signed-off-by: Daniel Kampert +--- + drivers/rtc/rtc_rv8263.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/rtc/rtc_rv8263.c b/drivers/rtc/rtc_rv8263.c +index c1df2e2dec5..f3cf86c6c7a 100644 +--- a/drivers/rtc/rtc_rv8263.c ++++ b/drivers/rtc/rtc_rv8263.c +@@ -226,7 +226,7 @@ static int rv8263c8_time_set(const struct device *dev, const struct rtc_time *ti + regs[3] = bin2bcd(timeptr->tm_hour) & HOURS_BITS; + regs[4] = bin2bcd(timeptr->tm_mday) & DATE_BITS; + regs[5] = bin2bcd(timeptr->tm_wday) & WEEKDAY_BITS; +- regs[6] = bin2bcd(timeptr->tm_mon) & MONTHS_BITS; ++ regs[6] = (bin2bcd(timeptr->tm_mon) & MONTHS_BITS) + 1; + regs[7] = bin2bcd(timeptr->tm_year - RV8263_YEAR_OFFSET) & YEAR_BITS; + + return i2c_write_dt(&config->i2c_bus, regs, sizeof(regs)); +@@ -257,7 +257,7 @@ static int rv8263c8_time_get(const struct device *dev, struct rtc_time *timeptr) + timeptr->tm_hour = bcd2bin(regs[2] & HOURS_BITS); + timeptr->tm_mday = bcd2bin(regs[3] & DATE_BITS); + timeptr->tm_wday = bcd2bin(regs[4] & WEEKDAY_BITS); +- timeptr->tm_mon = bcd2bin(regs[5] & MONTHS_BITS); ++ timeptr->tm_mon = bcd2bin(regs[5] & MONTHS_BITS) - 1; + timeptr->tm_year = bcd2bin(regs[6] & YEAR_BITS) + RV8263_YEAR_OFFSET; + + /* Unused. */ +@@ -461,7 +461,7 @@ static int rv8263c8_alarm_set_time(const struct device *dev, uint16_t id, uint16 + + err = i2c_write_dt(&config->i2c_bus, regs, sizeof(regs)); + if (err < 0) { +- LOG_ERR("Error while setting alarm time! Error: %i", < err); ++ LOG_ERR("Error while setting alarm time! Error: %i", err); + return err; + } + +-- +2.34.1 + diff --git a/app/src/ble/ble_transport.c b/app/src/ble/ble_transport.c index 727f2be5..786d3b52 100644 --- a/app/src/ble/ble_transport.c +++ b/app/src/ble/ble_transport.c @@ -54,10 +54,11 @@ BT_GATT_SERVICE_DEFINE(nus_service, NULL, NULL, NULL), BT_GATT_CCC(NULL, #if CONFIG_BLE_DISABLE_PAIRING_REQUIRED - BT_GATT_PERM_READ | BT_GATT_PERM_WRITE), + BT_GATT_PERM_READ | BT_GATT_PERM_WRITE #else - BT_GATT_PERM_READ_ENCRYPT | BT_GATT_PERM_WRITE_ENCRYPT), + BT_GATT_PERM_READ_ENCRYPT | BT_GATT_PERM_WRITE_ENCRYPT #endif + ), BT_GATT_CHARACTERISTIC(BLE_TRANSPORT_UUID_RX, BT_GATT_CHRC_WRITE | BT_GATT_CHRC_WRITE_WITHOUT_RESP, diff --git a/app/src/events/zsw_periodic_event.c b/app/src/events/zsw_periodic_event.c index 97bb3c56..feb957cd 100644 --- a/app/src/events/zsw_periodic_event.c +++ b/app/src/events/zsw_periodic_event.c @@ -1,19 +1,25 @@ -#include #include +#include #include +#include "zsw_clock.h" #include "events/periodic_event.h" #define PERIODIC_FAST_INTERVAL_MS 100 -#define PERIODIC_MID_INTERVAL_MS 1000 #define PERIODIC_SLOW_INTERVAL_MS 10000 -static void handle_slow_timeout(struct k_work *item); -static void handle_fast_timeout(struct k_work *item); -static void handle_mid_timeout(struct k_work *item); +#if CONFIG_RTC_UPDATE +#include + +static const struct device *const rtc = DEVICE_DT_GET(DT_ALIAS(rtc)); + +static void handle_mid_timeout(const struct device *dev, void *user_data); +#else +#define PERIODIC_MID_INTERVAL_MS 1000 +#endif -ZBUS_CHAN_DECLARE(periodic_event_10s_chan); ZBUS_CHAN_DECLARE(periodic_event_1s_chan); +ZBUS_CHAN_DECLARE(periodic_event_10s_chan); ZBUS_CHAN_DECLARE(periodic_event_100ms_chan); int zsw_periodic_chan_add_obs(const struct zbus_channel *chan, const struct zbus_observer *obs) @@ -34,7 +40,11 @@ int zsw_periodic_chan_add_obs(const struct zbus_channel *chan, const struct zbus if (chan == &periodic_event_10s_chan) { ret = k_work_reschedule(work, K_MSEC(PERIODIC_SLOW_INTERVAL_MS)); } else if (chan == &periodic_event_1s_chan) { +#if CONFIG_RTC_UPDATE + ret = rtc_update_set_callback(rtc, handle_mid_timeout, NULL); +#else ret = k_work_reschedule(work, K_MSEC(PERIODIC_MID_INTERVAL_MS)); +#endif } else if (chan == &periodic_event_100ms_chan) { ret = k_work_reschedule(work, K_MSEC(PERIODIC_FAST_INTERVAL_MS)); } else { @@ -48,12 +58,19 @@ int zsw_periodic_chan_add_obs(const struct zbus_channel *chan, const struct zbus int zsw_periodic_chan_rm_obs(const struct zbus_channel *chan, const struct zbus_observer *obs) { - struct k_work_delayable *work = NULL; int ret = zbus_chan_rm_obs(chan, obs, K_MSEC(100)); if (ret == 0 && sys_slist_is_empty(&chan->data->observers)) { - work = (struct k_work_delayable *)zbus_chan_user_data(chan); - __ASSERT(k_work_delayable_is_pending(work), "Periodic slow work is not pending"); - ret = k_work_cancel_delayable(work); +#if CONFIG_RTC_UPDATE + if (chan == &periodic_event_1s_chan) { + ret = rtc_update_set_callback(rtc, NULL, NULL); + } else +#endif + { + struct k_work_delayable *work = NULL; + work = (struct k_work_delayable *)zbus_chan_user_data(chan); + __ASSERT(k_work_delayable_is_pending(work), "Periodic slow work is not pending"); + ret = k_work_cancel_delayable(work); + } } return ret; } @@ -71,6 +88,15 @@ static void handle_slow_timeout(struct k_work *item) zbus_chan_pub(&periodic_event_10s_chan, &evt, K_MSEC(250)); } +#if CONFIG_RTC_UPDATE +static void handle_mid_timeout(const struct device *dev, void *user_data) +{ + struct periodic_event evt = { + }; + + zbus_chan_pub(&periodic_event_1s_chan, &evt, K_MSEC(250)); +} +#else static void handle_mid_timeout(struct k_work *item) { struct periodic_event evt = { @@ -83,6 +109,7 @@ static void handle_mid_timeout(struct k_work *item) zbus_chan_pub(&periodic_event_1s_chan, &evt, K_MSEC(250)); } +#endif static void handle_fast_timeout(struct k_work *item) { @@ -100,15 +127,18 @@ static void handle_fast_timeout(struct k_work *item) static int zsw_timer_init(void) { struct k_work_delayable *work = NULL; + work = (struct k_work_delayable *)zbus_chan_user_data(&periodic_event_10s_chan); k_work_init_delayable(work, handle_slow_timeout); - // TODO: Use the RTC instead of the timer in rev 5 to generate this +#ifndef CONFIG_RTC_UPDATE work = (struct k_work_delayable *)zbus_chan_user_data(&periodic_event_1s_chan); k_work_init_delayable(work, handle_mid_timeout); +#endif work = (struct k_work_delayable *)zbus_chan_user_data(&periodic_event_100ms_chan); k_work_init_delayable(work, handle_fast_timeout); + return 0; } diff --git a/app/src/ext_drivers/BMP5-Sensor-API b/app/src/ext_drivers/BMP5-Sensor-API index c779b44b..49ef5c49 160000 --- a/app/src/ext_drivers/BMP5-Sensor-API +++ b/app/src/ext_drivers/BMP5-Sensor-API @@ -1 +1 @@ -Subproject commit c779b44bf3c682d1fc06b5771378361650028223 +Subproject commit 49ef5c491b8434777353a7b53e5a7c8982810b11 diff --git a/app/src/main.c b/app/src/main.c index f765f794..333f80c8 100644 --- a/app/src/main.c +++ b/app/src/main.c @@ -287,6 +287,22 @@ static void run_wdt_work(struct k_work *item) int main(void) { + /* + while (1) { + struct i2c_msg msgs[1]; + uint8_t dst; + + for (uint8_t i = 0; i < 127; i++) { + msgs[0].buf = &dst; + msgs[0].len = 0U; + msgs[0].flags = I2C_MSG_WRITE | I2C_MSG_STOP; + if (i2c_transfer(i2c, &msgs[0], 1, i) == 0) { + LOG_INF("Found device at 0x%X", i); + } + } + + k_msleep(1000); + }*/ #ifdef CONFIG_SPI_FLASH_LOADER if (bootmode_check(ZSW_BOOT_MODE_RTT_FLASH_LOADER)) { LOG_WRN("SPI Flash Loader Boot Mode"); @@ -594,20 +610,16 @@ static void on_zbus_ble_data_callback(const struct zbus_channel *chan) switch (event->data.type) { case BLE_COMM_DATA_TYPE_SET_TIME: { if (event->data.data.time.seconds > 0) { - // TODO: Replace with set time - struct timespec tspec; - tspec.tv_sec = event->data.data.time.seconds; - tspec.tv_nsec = 0; - - clock_settime(CLOCK_REALTIME, &tspec); + zsw_timeval_t ztm; + memcpy(&ztm.tm, localtime((const time_t *)&event->data.data.time.seconds), sizeof(ztm.tm)); + zsw_clock_set_time(&ztm); } if (event->data.data.time.tz_offset != 0) { char tz[sizeof("UTC+01")] = { '\0' }; char sign = (event->data.data.time.tz_offset < 0) ? '+' : '-'; snprintf(tz, sizeof(tz), "UTC%c%d", sign, MIN(abs(event->data.data.time.tz_offset), 99)); - setenv("TZ", tz, 1); - tzset(); + zsw_clock_set_timezone(tz); } break; } diff --git a/app/src/zsw_clock.c b/app/src/zsw_clock.c index fc46a423..11aa6ec7 100644 --- a/app/src/zsw_clock.c +++ b/app/src/zsw_clock.c @@ -15,8 +15,8 @@ * along with this program. If not, see . */ -#include #include +#include #include #include #include @@ -27,31 +27,87 @@ #include #include "zsw_clock.h" -#include "zsw_retained_ram_storage.h" #include "events/zsw_periodic_event.h" +#if CONFIG_RTC +#include +#else +#include "zsw_retained_ram_storage.h" +#endif + +#if CONFIG_RTC +static const struct device *const rtc = DEVICE_DT_GET(DT_ALIAS(rtc)); +#else static void zbus_periodic_slow_callback(const struct zbus_channel *chan); ZBUS_CHAN_DECLARE(periodic_event_1s_chan); ZBUS_LISTENER_DEFINE(zsw_clock_lis, zbus_periodic_slow_callback); +#endif + +LOG_MODULE_REGISTER(zsw_clock, LOG_LEVEL_INF); + +#ifndef CONFIG_RTC + +static time_t zsw_clock_get_time_unix(void) +{ + struct timeval tv; + + gettimeofday(&tv, NULL); + + return tv.tv_sec; +} + +static void zbus_periodic_slow_callback(const struct zbus_channel *chan) +{ + retained.current_time_seconds = zsw_clock_get_time_unix(); + zsw_retained_ram_update(); +} +#endif void zsw_clock_set_time(zsw_timeval_t *ztm) { + // Substract one from the month because we want to count from December instead of January + ztm->tm.tm_mon -= 1; + + // Substract 1900 from the year because we want to count from 1900 + ztm->tm.tm_year -= 1900; + +#if CONFIG_RTC + rtc_set_time(rtc, &ztm->tm); +#else struct timespec tspec; - tspec.tv_sec = ztm->tm.tm_sec; +#warning "Not implemented" + tspec.tv_sec = 0; tspec.tv_nsec = 0; clock_settime(CLOCK_REALTIME, &tspec); + zsw_clock_set_timezone(retained.timezone); +#endif } void zsw_clock_get_time(zsw_timeval_t *ztm) { - struct timeval tv; +#if CONFIG_RTC + struct rtc_time tm; + + memset(&tm, 0, sizeof(struct rtc_time)); + if (rtc_get_time(rtc, &tm)) { + // Set the time struct to zero to prevent invalid values + // in case the time reading fails. + memset(ztm, 0, sizeof(zsw_timeval_t)); + + return; + } + memcpy(ztm, &tm, sizeof(struct rtc_time)); +#else struct tm *tm; + struct timeval tv; + gettimeofday(&tv, NULL); tm = localtime(&tv.tv_sec); memcpy(ztm, tm, sizeof(struct tm)); +#endif // Add one to the month because we want to count from December instead of January ztm->tm.tm_mon += 1; @@ -60,34 +116,32 @@ void zsw_clock_get_time(zsw_timeval_t *ztm) ztm->tm.tm_year += 1900; } -time_t zsw_clock_get_time_unix(void) -{ - struct timeval tv; - gettimeofday(&tv, NULL); - - return tv.tv_sec; -} - -static void zbus_periodic_slow_callback(const struct zbus_channel *chan) +void zsw_clock_set_timezone(char *tz) { - retained.current_time_seconds = zsw_clock_get_time_unix(); - zsw_retained_ram_update(); + if (strlen(tz) > 0) { + setenv("TZ", tz, 1); + tzset(); + } } static int zsw_clock_init(void) { +#if CONFIG_RTC + if (!device_is_ready(rtc)) { + LOG_ERR("Device not ready!"); + return -EBUSY; + } +#else struct timespec tspec; tspec.tv_sec = retained.current_time_seconds; tspec.tv_nsec = 0; clock_settime(CLOCK_REALTIME, &tspec); - if (strlen(retained.timezone) > 0) { - setenv("TZ", retained.timezone, 1); - tzset(); - } + zsw_clock_set_timezone(retained.timezone); zsw_periodic_chan_add_obs(&periodic_event_1s_chan, &zsw_clock_lis); +#endif return 0; } diff --git a/app/src/zsw_clock.h b/app/src/zsw_clock.h index cbfd188d..93be8e0f 100644 --- a/app/src/zsw_clock.h +++ b/app/src/zsw_clock.h @@ -17,20 +17,37 @@ #pragma once +#include + #include #include +#if CONFIG_RTC typedef void (*zsw_clock_on_update)(void); +#endif typedef struct { +#if CONFIG_RTC + struct rtc_time + tm; /**< Modified time object with 1900 added to the year and the month increased by one. */ +#else struct tm tm; /**< Modified time object with 1900 added to the year and the month increased by one. */ +#endif uint32_t tv_usec; } zsw_timeval_t; -void zsw_clock_add_update(zsw_clock_on_update callback); - +/** @brief + * NOTE: This function needs the time as seconds + * @param ztm + */ void zsw_clock_set_time(zsw_timeval_t *ztm); +/** @brief + * @param ztm + */ void zsw_clock_get_time(zsw_timeval_t *ztm); -time_t zsw_clock_get_time_unix(void); \ No newline at end of file +/** @brief + * @param tz + */ +void zsw_clock_set_timezone(char *tz); \ No newline at end of file diff --git a/app/src/zsw_retained_ram_storage.c b/app/src/zsw_retained_ram_storage.c index 9944b924..c231d15d 100644 --- a/app/src/zsw_retained_ram_storage.c +++ b/app/src/zsw_retained_ram_storage.c @@ -16,7 +16,7 @@ */ #include -#include +#include "zsw_retained_ram_storage.h" #ifndef CONFIG_BOARD_NATIVE_POSIX #include #include @@ -68,4 +68,3 @@ void zsw_retained_ram_reset(void) { } #endif - diff --git a/app/src/zsw_rtc.c b/app/src/zsw_rtc.c deleted file mode 100644 index 33977beb..00000000 --- a/app/src/zsw_rtc.c +++ /dev/null @@ -1,98 +0,0 @@ -/* - * This file is part of ZSWatch project . - * Copyright (c) 2023 Jakob Krantz. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 3. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "zsw_clock.h" -#include "events/zsw_periodic_event.h" - -const struct device *const rtc = DEVICE_DT_GET(DT_NODELABEL(rv_8263_c8)); - -LOG_MODULE_REGISTER(zsw_clock, LOG_LEVEL_DBG); - -void zsw_clock_add_update(zsw_clock_on_update callback) -{ - -} - -void zsw_clock_set_time(zsw_timeval_t *ztm) -{ - struct rtc_time time; - - time.tm_sec = ztm->tm.tm_sec; - time.tm_min = ztm->tm.tm_min; - time.tm_hour = ztm->tm.tm_hour; - time.tm_wday = ztm->tm.tm_wday; - time.tm_mday = ztm->tm.tm_mday; - time.tm_mon = ztm->tm.tm_mon - 1; - time.tm_year = ztm->tm.tm_year - 1900; - - //rtc_set_time(rtc, &time); -} - -void zsw_clock_get_time(zsw_timeval_t *ztm) -{ - struct rtc_time time; - - //rtc_get_time(rtc, &time); - - ztm->tm.tm_sec = time.tm_sec; - ztm->tm.tm_min = time.tm_min; - ztm->tm.tm_hour = time.tm_hour; - ztm->tm.tm_wday = time.tm_wday; - ztm->tm.tm_mday = time.tm_mday; - - // Add one to the month because we want to count from December instead of January - ztm->tm.tm_mon = time.tm_mon + 1; - - // Add 1900 to the year because we want to count from 0 - ztm->tm.tm_year = time.tm_year + 1900; -} - -time_t zsw_clock_get_time_unix(void) -{ - // TODO: - return 0; -} - -void on_rtc_update(const struct device *dev, void *user_data) -{ -} - -static int zsw_clock_init(void) -{ - if (!device_is_ready(rtc)) { - LOG_ERR("Device not ready!"); - return -1; - } - - rtc_update_set_callback(rtc, on_rtc_update, NULL); - - return 0; -} - -SYS_INIT(zsw_clock_init, APPLICATION, 2); \ No newline at end of file