diff --git a/drivers/at86rf215/Kconfig b/drivers/at86rf215/Kconfig index caad2dae7d..8a2d2458a9 100644 --- a/drivers/at86rf215/Kconfig +++ b/drivers/at86rf215/Kconfig @@ -12,6 +12,24 @@ menuconfig KCONFIG_USEMODULE_AT86RF215 if KCONFIG_USEMODULE_AT86RF215 +menuconfig KCONFIG_USEMODULE_AT86RF215_BATMON + bool "AT86RF215 Battery Monitor" + depends on USEMODULE_AT86RF215 + help + Configure the AT86RF215 battery monitor using Kconfig. + +config AT86RF215_BATMON_THRESHOLD + int "Treshold voltage (in mV) of the battery monitor" + range 1700 3675 + default 1800 + depends on KCONFIG_USEMODULE_AT86RF215_BATMON + help + If the supply voltage falls below the configured threshold + a SYS_BUS_POWER_EVENT_LOW_VOLTAGE event is generated on the + SYS_BUS_POWER bus. + + Battery Monitoring is disabled when the device is in Deep Sleep. + config AT86RF215_USE_CLOCK_OUTPUT bool "Enable clock output" help diff --git a/drivers/at86rf215/Makefile.dep b/drivers/at86rf215/Makefile.dep index 0b399d26ab..3c75425d6a 100644 --- a/drivers/at86rf215/Makefile.dep +++ b/drivers/at86rf215/Makefile.dep @@ -9,6 +9,10 @@ ifeq (,$(filter at86rf215_subghz at86rf215_24ghz,$(USEMODULE))) DEFAULT_MODULE += at86rf215_24ghz endif +ifneq (,$(filter at86rf215_batmon,$(USEMODULE))) + USEMODULE += sys_bus_power +endif + DEFAULT_MODULE += netdev_ieee802154_multimode DEFAULT_MODULE += netdev_ieee802154_oqpsk diff --git a/drivers/at86rf215/at86rf215_getset.c b/drivers/at86rf215/at86rf215_getset.c index 35950be32d..473139a72c 100644 --- a/drivers/at86rf215/at86rf215_getset.c +++ b/drivers/at86rf215/at86rf215_getset.c @@ -396,3 +396,49 @@ bool at86rf215_set_idle_from_rx(at86rf215_t *dev, uint8_t state) return false; } + +int at86rf215_enable_batmon(at86rf215_t *dev, unsigned voltage) +{ + uint8_t bmdvc; + + /* only configure BATMON on one interface */ + if (!is_subGHz(dev) && dev->sibling != NULL) { + dev = dev->sibling; + } + + /* ensure valid range */ + if (voltage < 1700 || voltage > 3675) { + return -ERANGE; + } + + if (voltage > 2500) { + /* high range */ + bmdvc = (voltage - 2550 + 37) / 75; + DEBUG("[at86rf215] BATMON set to %u mV\n", 2550 + 75 * bmdvc); + + bmdvc |= BMDVC_BMHR_MASK; + } else { + /* low range */ + bmdvc = (voltage - 1700 + 25) / 50; + DEBUG("[at86rf215] BATMON set to %u mV\n", 1700 + 50 * bmdvc); + } + + /* set batmon threshold */ + at86rf215_reg_write(dev, RG_RF_BMDVC, bmdvc); + + /* enable interrupt */ + at86rf215_reg_or(dev, dev->RF->RG_IRQM, RF_IRQ_BATLOW); + + return 0; +} + +void at86rf215_disable_batmon(at86rf215_t *dev) +{ + /* only configure BATMON on one interface */ + if (!is_subGHz(dev) && dev->sibling != NULL) { + dev = dev->sibling; + } + + /* disable interrupt */ + at86rf215_reg_and(dev, dev->RF->RG_IRQM, ~RF_IRQ_BATLOW); +} diff --git a/drivers/at86rf215/at86rf215_internal.c b/drivers/at86rf215/at86rf215_internal.c index 0592d787a2..2ee9ffda59 100644 --- a/drivers/at86rf215/at86rf215_internal.c +++ b/drivers/at86rf215/at86rf215_internal.c @@ -69,6 +69,11 @@ int at86rf215_hardware_reset(at86rf215_t *dev) return -ENODEV; } + /* enable battery monitor */ + if (IS_ACTIVE(MODULE_AT86RF215_BATMON)) { + at86rf215_enable_batmon(dev, CONFIG_AT86RF215_BATMON_THRESHOLD); + } + /* clear interrupts */ at86rf215_reg_read(dev, RG_RF09_IRQS); at86rf215_reg_read(dev, RG_RF24_IRQS); diff --git a/drivers/at86rf215/at86rf215_netdev.c b/drivers/at86rf215/at86rf215_netdev.c index fbd1713d49..baf87da98b 100644 --- a/drivers/at86rf215/at86rf215_netdev.c +++ b/drivers/at86rf215/at86rf215_netdev.c @@ -30,6 +30,8 @@ #include "net/netdev/ieee802154.h" #include "net/gnrc/netif/internal.h" +#include "sys/bus.h" + #include "at86rf215.h" #include "at86rf215_netdev.h" #include "at86rf215_internal.h" @@ -551,6 +553,22 @@ static int _set(netdev_t *netdev, netopt_t opt, const void *val, size_t len) res = sizeof(netopt_enable_t); break; +#ifdef MODULE_AT86RF215_BATMON + case NETOPT_BATMON: + assert(len <= sizeof(uint16_t)); + { + uint16_t mV = *(const uint16_t *)val; + if (mV) { + res = at86rf215_enable_batmon(dev, mV); + res = (res == 0) ? (int)sizeof(uint16_t) : res; + } else { + at86rf215_disable_batmon(dev); + res = sizeof(uint16_t); + } + } + break; +#endif + case NETOPT_RETRANS: assert(len <= sizeof(uint8_t)); dev->retries_max = *((const uint8_t *)val); @@ -1052,6 +1070,14 @@ static void _isr(netdev_t *netdev) } } + /* Handle Low Battery IRQ */ +#if MODULE_AT86RF215_BATMON + if ((rf_irq_mask & RF_IRQ_BATLOW)) { + msg_bus_t *bus = sys_bus_get(SYS_BUS_POWER); + msg_bus_post(bus, SYS_BUS_POWER_EVENT_LOW_VOLTAGE, NULL); + } +#endif + /* exit early if the interrupt was not for this interface */ if (!((bb_irq_mask & bb_irqs_enabled) || (rf_irq_mask & (RF_IRQ_EDC | RF_IRQ_TRXRDY)) || timeout)) { diff --git a/drivers/include/at86rf215.h b/drivers/include/at86rf215.h index f3978a55c6..022d23cdba 100644 --- a/drivers/include/at86rf215.h +++ b/drivers/include/at86rf215.h @@ -123,6 +123,16 @@ enum { #endif /** @} */ +/** + * @name Default Battery Monitor trigger threshold (in mV) + * if battery monitoring is enabled + * @{ + */ +#ifndef CONFIG_AT86RF215_BATMON_THRESHOLD +#define CONFIG_AT86RF215_BATMON_THRESHOLD (1800) +#endif +/** @} */ + /** * @name Default PHY Mode * @{ @@ -591,6 +601,24 @@ void at86rf215_tx_done(at86rf215_t *dev); */ bool at86rf215_cca(at86rf215_t *dev); +/** + * @brief Generate an interrupt if supply voltage drops below the configured + * threshold. + * + * @param[in] dev device to configure + * @param[in] voltage Threshold voltage in mV + * + * @return 0 on success, error otherwise + */ +int at86rf215_enable_batmon(at86rf215_t *dev, unsigned voltage); + +/** + * @brief Disable the Battery Monitor interrupt. + * + * @param[in] dev device to configure + */ +void at86rf215_disable_batmon(at86rf215_t *dev); + #ifdef __cplusplus } #endif diff --git a/makefiles/pseudomodules.inc.mk b/makefiles/pseudomodules.inc.mk index 022308340d..7672cb5189 100644 --- a/makefiles/pseudomodules.inc.mk +++ b/makefiles/pseudomodules.inc.mk @@ -131,6 +131,7 @@ PSEUDOMODULES += stm32_eth_link_up PSEUDOMODULES += stm32mp1_eng_mode PSEUDOMODULES += suit_transport_% PSEUDOMODULES += suit_storage_% +PSEUDOMODULES += sys_bus_% PSEUDOMODULES += wakaama_objects_% PSEUDOMODULES += wifi_enterprise PSEUDOMODULES += xtimer_on_ztimer diff --git a/sys/Makefile b/sys/Makefile index e2216b74a1..f174755a58 100644 --- a/sys/Makefile +++ b/sys/Makefile @@ -158,6 +158,9 @@ endif ifneq (,$(filter suit%,$(USEMODULE))) DIRS += suit endif +ifneq (,$(filter sys_bus,$(USEMODULE))) + DIRS += bus +endif ifneq (,$(filter tcp,$(USEMODULE))) DIRS += net/transport_layer/tcp endif diff --git a/sys/Makefile.dep b/sys/Makefile.dep index e8c33fffdf..4da65f9e8a 100644 --- a/sys/Makefile.dep +++ b/sys/Makefile.dep @@ -45,6 +45,11 @@ ifneq (,$(filter crypto_%,$(USEMODULE))) USEMODULE += crypto endif +ifneq (,$(filter sys_bus_%,$(USEMODULE))) + USEMODULE += sys_bus + USEMODULE += core_msg_bus +endif + ifneq (,$(filter rtt_cmd,$(USEMODULE))) FEATURES_REQUIRED += periph_rtt endif diff --git a/sys/auto_init/auto_init.c b/sys/auto_init/auto_init.c index c24c0d4209..3479ff3602 100644 --- a/sys/auto_init/auto_init.c +++ b/sys/auto_init/auto_init.c @@ -58,6 +58,11 @@ void auto_init(void) extern void auto_init_event_thread(void); auto_init_event_thread(); } + if (IS_USED(MODULE_SYS_BUS)) { + LOG_DEBUG("Auto init system buses.\n"); + extern void auto_init_sys_bus(void); + auto_init_sys_bus(); + } if (IS_USED(MODULE_MCI)) { LOG_DEBUG("Auto init mci.\n"); extern void mci_initialize(void); diff --git a/sys/bus/Makefile b/sys/bus/Makefile new file mode 100644 index 0000000000..d66bde0cec --- /dev/null +++ b/sys/bus/Makefile @@ -0,0 +1,3 @@ +MODULE = sys_bus + +include $(RIOTBASE)/Makefile.base diff --git a/sys/bus/sys_bus_init.c b/sys/bus/sys_bus_init.c new file mode 100644 index 0000000000..eaba0d3e95 --- /dev/null +++ b/sys/bus/sys_bus_init.c @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2020 ML!PA Consulting GmbH + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup sys_bus + * @{ + * + * @file + * @brief System Buses + * + * @author Benjamin Valentin + * @} + */ + +#include "sys/bus.h" + +msg_bus_t _sys_bus[SYS_BUS_NUMOF]; + +void auto_init_sys_bus(void) +{ + for (unsigned i = 0; i < SYS_BUS_NUMOF; ++i) { + msg_bus_init(&_sys_bus[i]); + } +} diff --git a/sys/include/net/netopt.h b/sys/include/net/netopt.h index c11cf855e0..60a7f701a6 100644 --- a/sys/include/net/netopt.h +++ b/sys/include/net/netopt.h @@ -767,6 +767,16 @@ typedef enum { */ NETOPT_RSSI, + /** + * @brief (uint16_t) Set the battery monitor voltage (in mV). + * + * When set, a @ref SYS_BUS_POWER_EVENT_LOW_VOLTAGE event is generated + * on the SYS_BUS_POWER bus if the supply voltage falls below the set value. + * + * Set to 0 to disable battery monitoring. + */ + NETOPT_BATMON, + /** * @brief (array of byte array) get link layer multicast groups as array * of byte arrays (length of each byte array corresponds to the diff --git a/sys/include/sys/bus.h b/sys/include/sys/bus.h new file mode 100644 index 0000000000..f6d29a1ff4 --- /dev/null +++ b/sys/include/sys/bus.h @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2020 ML!PA Consulting GmbH + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup sys + * @defgroup sys_bus System Buses for common events + * @{ + * + * @file + * @brief This provides System Buses for common events. + * + * @warning Bus Events will be lost if receiver message queue is full. + * + * @author Benjamin Valentin + */ + +#ifndef SYS_BUS_H +#define SYS_BUS_H + +#include +#include "msg_bus.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief System Bus types + */ +typedef enum { +#if MODULE_SYS_BUS_POWER + SYS_BUS_POWER, /**< Events related to system power */ +#endif + SYS_BUS_NUMOF /**< Number of enabled system buses */ +} sys_bus_t; + +/** + * @brief Power Bus Events + */ +typedef enum { + /** + * @brief Supply voltage fallen below threshold + */ + SYS_BUS_POWER_EVENT_LOW_VOLTAGE, + + /* add more if needed, but not more than 32 */ +} sys_bus_power_event_t; + +/** + * @brief The System Bus array - do not use directly + */ +extern msg_bus_t _sys_bus[SYS_BUS_NUMOF]; + +/** + * @brief Get a System Bus for a category of events. + * + * @param[in] bus The event category of the the user + * is interested in + * + * @return The message bus for those events + */ +static inline msg_bus_t *sys_bus_get(sys_bus_t bus) +{ + return &_sys_bus[bus]; +} + +#ifdef __cplusplus +} +#endif + +#endif /* SYS_BUS_H */ +/** @} */ diff --git a/sys/net/crosslayer/netopt/netopt.c b/sys/net/crosslayer/netopt/netopt.c index 27e635c21b..e10aab73a5 100644 --- a/sys/net/crosslayer/netopt/netopt.c +++ b/sys/net/crosslayer/netopt/netopt.c @@ -126,6 +126,7 @@ static const char *_netopt_strmap[] = { [NETOPT_NUM_GATEWAYS] = "NETOPT_NUM_GATEWAYS", [NETOPT_LINK_CHECK] = "NETOPT_LINK_CHECK", [NETOPT_RSSI] = "NETOPT_RSSI", + [NETOPT_BATMON] = "NETOPT_BATMON", [NETOPT_L2_GROUP] = "NETOPT_L2_GROUP", [NETOPT_L2_GROUP_LEAVE] = "NETOPT_L2_GROUP_LEAVE", [NETOPT_NUMOF] = "NETOPT_NUMOF", diff --git a/tests/driver_at86rf215/Makefile b/tests/driver_at86rf215/Makefile index 78f6cdfa3a..f54d6765b5 100644 --- a/tests/driver_at86rf215/Makefile +++ b/tests/driver_at86rf215/Makefile @@ -2,5 +2,6 @@ BOARD ?= openmote-b # the radio driver to test USEMODULE += at86rf215 +USEMODULE += at86rf215_batmon include ../driver_netdev_common/Makefile.netdev.mk diff --git a/tests/driver_at86rf215/main.c b/tests/driver_at86rf215/main.c deleted file mode 120000 index a3f88db08e..0000000000 --- a/tests/driver_at86rf215/main.c +++ /dev/null @@ -1 +0,0 @@ -../driver_netdev_common/main.c \ No newline at end of file diff --git a/tests/driver_at86rf215/main.c b/tests/driver_at86rf215/main.c new file mode 100644 index 0000000000..c558eeb2de --- /dev/null +++ b/tests/driver_at86rf215/main.c @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2020 ML!PA Consulting GmbH + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup tests + * @{ + * + * @file + * @brief Test application for at86rf215 driver + * + * @author Benjamin Valentin + * @} + */ + +#include + +#include "at86rf215.h" +#include "thread.h" +#include "shell.h" +#include "shell_commands.h" +#include "sys/bus.h" + +#include "net/gnrc/pktdump.h" +#include "net/gnrc.h" + +static char batmon_stack[THREAD_STACKSIZE_MAIN]; + +void *batmon_thread(void *arg) +{ + (void) arg; + + msg_t msg; + msg_bus_entry_t sub; + msg_bus_t *bus = sys_bus_get(SYS_BUS_POWER); + + msg_bus_attach(bus, &sub); + msg_bus_subscribe(&sub, SYS_BUS_POWER_EVENT_LOW_VOLTAGE); + + while (1) { + msg_receive(&msg); + puts("NA NA NA NA NA NA NA NA NA NA NA NA NA BATMON"); + } +} + +static int cmd_enable_batmon(int argc, char **argv) +{ + int res; + uint16_t voltage; + gnrc_netif_t* netif = gnrc_netif_iter(NULL); + + if (argc < 2) { + printf("usage: %s \n", argv[0]); + return -1; + } + + if (netif == NULL) { + puts("no netif found"); + return -1; + } + + voltage = atoi(argv[1]); + res = gnrc_netapi_set(netif->pid, NETOPT_BATMON, 0, + &voltage, sizeof(voltage)); + + if (res != sizeof(voltage)) { + puts("value out of range"); + } + + return res; +} + +static const shell_command_t shell_commands[] = { + { "batmon", "Enable the battery monitor", cmd_enable_batmon }, + { NULL, NULL, NULL } +}; + +int main(void) +{ + /* enable pktdump output */ + gnrc_netreg_entry_t dump = GNRC_NETREG_ENTRY_INIT_PID(GNRC_NETREG_DEMUX_CTX_ALL, + gnrc_pktdump_pid); + gnrc_netreg_register(GNRC_NETTYPE_UNDEF, &dump); + + /* create battery monitor thread */ + thread_create(batmon_stack, sizeof(batmon_stack), THREAD_PRIORITY_MAIN - 1, + THREAD_CREATE_STACKTEST, batmon_thread, NULL, "batmon"); + + /* start the shell */ + char line_buf[SHELL_DEFAULT_BUFSIZE]; + shell_run(shell_commands, line_buf, SHELL_DEFAULT_BUFSIZE); + + return 0; +} diff --git a/tests/unittests/Makefile.ci b/tests/unittests/Makefile.ci index c2324e90cc..fe7cb1a50d 100644 --- a/tests/unittests/Makefile.ci +++ b/tests/unittests/Makefile.ci @@ -45,8 +45,10 @@ BOARD_INSUFFICIENT_MEMORY := \ lsn50 \ maple-mini \ mega-xplained \ + mcb2388 \ microbit \ microduino-corerf \ + msba2 \ msb-430 \ msb-430h \ nrf51dk \