diff --git a/drivers/include/slipdev.h b/drivers/include/slipdev.h index 9c9c6984b6c5..6740216b491b 100644 --- a/drivers/include/slipdev.h +++ b/drivers/include/slipdev.h @@ -72,6 +72,14 @@ enum { * @brief Device writes received data to stdin */ SLIPDEV_STATE_STDIN, + /** + * @brief Device is in standby, will wake up when sending data + */ + SLIPDEV_STATE_STANDBY, + /** + * @brief Device is in sleep mode + */ + SLIPDEV_STATE_SLEEP, }; /** @} */ diff --git a/drivers/slipdev/slipdev.c b/drivers/slipdev/slipdev.c index 6cb7cd78a06c..68494571717a 100644 --- a/drivers/slipdev/slipdev.c +++ b/drivers/slipdev/slipdev.c @@ -32,6 +32,8 @@ #include "mutex.h" #include "stdio_uart.h" +static int _check_state(slipdev_t *dev); + static inline void slipdev_lock(void) { if (IS_USED(MODULE_SLIPDEV_STDIO)) { @@ -73,6 +75,23 @@ static void _slip_rx_cb(void *arg, uint8_t byte) } } +static void _poweron(slipdev_t *dev) +{ + if ((dev->state != SLIPDEV_STATE_STANDBY) || + (dev->state != SLIPDEV_STATE_SLEEP)) { + return; + } + + dev->state = 0; + uart_init(dev->config.uart, dev->config.baudrate, _slip_rx_cb, dev); +} + +static inline void _poweroff(slipdev_t *dev, uint8_t state) +{ + uart_poweroff(dev->config.uart); + dev->state = state; +} + static int _init(netdev_t *netdev) { slipdev_t *dev = (slipdev_t *)netdev; @@ -145,10 +164,33 @@ unsigned slipdev_unstuff_readbyte(uint8_t *buf, uint8_t byte, bool *escaped) return res; } +static int _check_state(slipdev_t *dev) +{ + /* power states not supported when multiplexing stdio */ + if (IS_USED(MODULE_SLIPDEV_STDIO)) { + return 0; + } + + /* discard data when interface is in SLEEP mode */ + if (dev->state == SLIPDEV_STATE_SLEEP) { + return -ENETDOWN; + } + + /* sending data wakes the interface from STANDBY */ + if (dev->state == SLIPDEV_STATE_STANDBY) { + _poweron(dev); + } + + return 0; +} + static int _send(netdev_t *netdev, const iolist_t *iolist) { slipdev_t *dev = (slipdev_t *)netdev; - int bytes = 0; + int bytes = _check_state(dev); + if (bytes) { + return bytes; + } DEBUG("slipdev: sending iolist\n"); slipdev_lock(); @@ -220,6 +262,45 @@ static void _isr(netdev_t *netdev) } } +#if !IS_USED(MODULE_SLIPDEV_STDIO) +static int _set_state(slipdev_t *dev, netopt_state_t state) +{ + if (IS_USED(MODULE_SLIPDEV_STDIO)) { + return -ENOTSUP; + } + + switch (state) { + case NETOPT_STATE_STANDBY: + _poweroff(dev, SLIPDEV_STATE_STANDBY); + break; + case NETOPT_STATE_SLEEP: + _poweroff(dev, SLIPDEV_STATE_SLEEP); + break; + case NETOPT_STATE_IDLE: + _poweron(dev); + break; + default: + return -ENOTSUP; + } + + return sizeof(netopt_state_t); +} + +static int _set(netdev_t *netdev, netopt_t opt, const void *value, size_t max_len) +{ + (void)max_len; + + slipdev_t *dev = (slipdev_t *)netdev; + switch (opt) { + case NETOPT_STATE: + assert(max_len <= sizeof(netopt_state_t)); + return _set_state(dev, *((const netopt_state_t *)value)); + default: + return -ENOTSUP; + } +} +#endif /* !MODULE_SLIPDEV_STDIO */ + static int _get(netdev_t *netdev, netopt_t opt, void *value, size_t max_len) { (void)netdev; @@ -249,7 +330,11 @@ static const netdev_driver_t slip_driver = { .init = _init, .isr = _isr, .get = _get, +#if IS_USED(MODULE_SLIPDEV_STDIO) .set = netdev_set_notsup, +#else + .set = _set, +#endif }; void slipdev_setup(slipdev_t *dev, const slipdev_params_t *params, uint8_t index)