diff --git a/arch/arm/src/stm32/stm32_1wire.c b/arch/arm/src/stm32/stm32_1wire.c new file mode 100644 index 00000000000..d81feb7999e --- /dev/null +++ b/arch/arm/src/stm32/stm32_1wire.c @@ -0,0 +1,1333 @@ +/**************************************************************************** + * arch/arm/src/stm32/stm32_1wire.c + * + * Copyright (C) 2016 Aleksandr Vyhovanec. All rights reserved. + * Author: Aleksandr Vyhovanec + * + * 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 NuttX nor the names of its contributors 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 OWNER 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. + * + ****************************************************************************/ + +/* Links: + * https://www.maximintegrated.com/en/app-notes/index.mvp/id/214 + */ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include "up_arch.h" + +#include "stm32_rcc.h" +#include "stm32_1wire.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define BUS_TIMEOUT 5 /* tv_sec */ + +#define RESET_BAUD 9600 +#define RESET_TX 0xF0 +#define TIMESLOT_BAUD 115200 +#define READ_TX 0xFF +#define READ_RX1 0xFF +#define WRITE_TX0 0x00 +#define WRITE_TX1 0xFF + +#define PIN_OPENDRAIN(GPIO) ((GPIO) | GPIO_OPENDRAIN) + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* 1-Wire bus task */ + +enum stm32_1wire_msg_e +{ + ONEWIRETASK_NONE = 0, + ONEWIRETASK_RESET, + ONEWIRETASK_WRITE, + ONEWIRETASK_READ +}; + +struct stm32_1wire_msg_s +{ + enum stm32_1wire_msg_e task; /* Task */ + uint8_t *buffer; /* Task buffer */ + int buflen; /* Buffer length */ +}; + +/* 1-Wire device hardware configuration */ + +struct stm32_1wire_config_s +{ + const uint32_t usartbase; /* Base address of USART registers */ + const uint32_t apbclock; /* PCLK 1 or 2 frequency */ + const uint32_t data_pin; /* GPIO configuration for DATA */ + const uint8_t irq; /* IRQ associated with this USART */ + int (*const vector)(int irq, void *context); /* Interrupt handler */ +}; + +/* 1-Wire device Private Data */ + +struct stm32_1wire_priv_s +{ + const struct stm32_1wire_config_s *config; /* Port configuration */ + volatile int refs; /* Referernce count */ + sem_t sem_excl; /* Mutual exclusion semaphore */ + sem_t sem_isr; /* Interrupt wait semaphore */ + int baud; /* Baud rate */ + const struct stm32_1wire_msg_s *msgs; /* Messages data */ + uint8_t *byte; /* Current byte */ + uint8_t bit; /* Current bit */ + volatile int result; /* Exchange result */ +}; + +/* 1-Wire device, Instance */ + +struct stm32_1wire_inst_s +{ + const struct onewire_ops_s *ops; /* Standard 1-Wire operations */ + struct stm32_1wire_priv_s *priv; /* Common driver private data structure */ +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static inline uint32_t stm32_1wire_in(struct stm32_1wire_priv_s *priv, int offset); +static inline void stm32_1wire_out(struct stm32_1wire_priv_s *priv, int offset, uint32_t value); +static int stm32_1wire_recv(struct stm32_1wire_priv_s *priv); +static void stm32_1wire_send(struct stm32_1wire_priv_s *priv, int ch); +static void stm32_1wire_set_baud(struct stm32_1wire_priv_s *priv); +static void stm32_1wire_set_apb_clock(struct stm32_1wire_priv_s *priv, bool on); +static int stm32_1wire_init(FAR struct stm32_1wire_priv_s *priv); +static int stm32_1wire_deinit(FAR struct stm32_1wire_priv_s *priv); +static inline void stm32_1wire_sem_init(FAR struct stm32_1wire_priv_s *priv); +static inline void stm32_1wire_sem_destroy(FAR struct stm32_1wire_priv_s *priv); +static inline void stm32_1wire_sem_wait(FAR struct stm32_1wire_priv_s *priv); +static inline void stm32_1wire_sem_post(FAR struct stm32_1wire_priv_s *priv); +static int stm32_1wire_process(struct stm32_1wire_priv_s *priv, + FAR const struct stm32_1wire_msg_s *msgs, int count); +static int stm32_1wire_isr(struct stm32_1wire_priv_s *priv); + +#ifdef CONFIG_STM32_1WIRE1 +static int up_interrupt_1wire1(int irq, void *context); +#endif +#ifdef CONFIG_STM32_1WIRE2 +static int up_interrupt_1wire2(int irq, void *context); +#endif +#ifdef CONFIG_STM32_1WIRE3 +static int up_interrupt_1wire3(int irq, void *context); +#endif +#ifdef CONFIG_STM32_1WIRE4 +static int up_interrupt_1wire4(int irq, void *context); +#endif +#ifdef CONFIG_STM32_1WIRE5 +static int up_interrupt_1wire5(int irq, void *context); +#endif +#ifdef CONFIG_STM32_1WIRE6 +static int up_interrupt_1wire6(int irq, void *context); +#endif +#ifdef CONFIG_STM32_1WIRE7 +static int up_interrupt_1wire7(int irq, void *context); +#endif +#ifdef CONFIG_STM32_1WIRE8 +static int up_interrupt_1wire8(int irq, void *context); +#endif + +static int stm32_1wire_reset(FAR struct onewire_dev_s *dev); +static int stm32_1wire_write(FAR struct onewire_dev_s *dev, + const uint8_t *buffer, int buflen); +static int stm32_1wire_read(FAR struct onewire_dev_s *dev, uint8_t *buffer, + int buflen); +static int stm32_1wire_exchange(FAR struct onewire_dev_s *dev, bool reset, + const uint8_t *txbuffer, int txbuflen, + uint8_t *rxbuffer, int rxbuflen); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* 1-Wire device structures */ + +#ifdef CONFIG_STM32_1WIRE1 + +static const struct stm32_1wire_config_s stm32_1wire1_config = +{ + .usartbase = STM32_USART1_BASE, + .apbclock = STM32_PCLK2_FREQUENCY, + .data_pin = PIN_OPENDRAIN(GPIO_USART1_TX), + .irq = STM32_IRQ_USART1, + .vector = up_interrupt_1wire1, +}; + +static struct stm32_1wire_priv_s stm32_1wire1_priv = +{ + .config = &stm32_1wire1_config, + .refs = 0, + .msgs = NULL +}; + +#endif + +#ifdef CONFIG_STM32_1WIRE2 + +static const struct stm32_1wire_config_s stm32_1wire2_config = +{ + .usartbase = STM32_USART2_BASE, + .apbclock = STM32_PCLK1_FREQUENCY, + .data_pin = PIN_OPENDRAIN(GPIO_USART2_TX), + .irq = STM32_IRQ_USART2, + .vector = up_interrupt_1wire2, +}; + +static struct stm32_1wire_priv_s stm32_1wire2_priv = +{ + .config = &stm32_1wire2_config, + .refs = 0, + .msgs = NULL +}; + +#endif + +#ifdef CONFIG_STM32_1WIRE3 + +static const struct stm32_1wire_config_s stm32_1wire3_config = +{ + .usartbase = STM32_USART3_BASE, + .apbclock = STM32_PCLK1_FREQUENCY, + .data_pin = PIN_OPENDRAIN(GPIO_USART3_TX), + .irq = STM32_IRQ_USART3, + .vector = up_interrupt_1wire3, +}; + +static struct stm32_1wire_priv_s stm32_1wire3_priv = +{ + .config = &stm32_1wire3_config, + .refs = 0, + .msgs = NULL +}; + +#endif + +#ifdef CONFIG_STM32_1WIRE4 + +static const struct stm32_1wire_config_s stm32_1wire4_config = +{ + .usartbase = STM32_USART4_BASE, + .apbclock = STM32_PCLK1_FREQUENCY, + .data_pin = PIN_OPENDRAIN(GPIO_USART4_TX), + .irq = STM32_IRQ_USART4, + .vector = up_interrupt_1wire4, +}; + +static struct stm32_1wire_priv_s stm32_1wire4_priv = +{ + .config = &stm32_1wire4_config, + .refs = 0, + .msgs = NULL +}; + +#endif + +#ifdef CONFIG_STM32_1WIRE5 + +static const struct stm32_1wire_config_s stm32_1wire5_config = +{ + .usartbase = STM32_USART5_BASE, + .apbclock = STM32_PCLK1_FREQUENCY, + .data_pin = PIN_OPENDRAIN(GPIO_USART5_TX), + .irq = STM32_IRQ_USART5, + .vector = up_interrupt_1wire5, +}; + +static struct stm32_1wire_priv_s stm32_1wire5_priv = +{ + .config = &stm32_1wire5_config, + .refs = 0, + .msgs = NULL +}; + +#endif + +#ifdef CONFIG_STM32_1WIRE6 + +static const struct stm32_1wire_config_s stm32_1wire6_config = +{ + .usartbase = STM32_USART6_BASE, + .apbclock = STM32_PCLK2_FREQUENCY, + .data_pin = PIN_OPENDRAIN(GPIO_USART6_TX), + .irq = STM32_IRQ_USART6, + .vector = up_interrupt_1wire6, +}; + +static struct stm32_1wire_priv_s stm32_1wire6_priv = +{ + .config = &stm32_1wire6_config, + .refs = 0, + .msgs = NULL +}; + +#endif + +#ifdef CONFIG_STM32_1WIRE7 + +static const struct stm32_1wire_config_s stm32_1wire7_config = +{ + .usartbase = STM32_USART7_BASE, + .apbclock = STM32_PCLK1_FREQUENCY, + .data_pin = PIN_OPENDRAIN(GPIO_USART7_TX), + .irq = STM32_IRQ_USART7, + .vector = up_interrupt_1wire7, +}; + +static struct stm32_1wire_priv_s stm32_1wire7_priv = +{ + .config = &stm32_1wire7_config, + .refs = 0, + .msgs = NULL +}; + +#endif + +#ifdef CONFIG_STM32_1WIRE8 + +static const struct stm32_1wire_config_s stm32_1wire8_config = +{ + .usartbase = STM32_USART8_BASE, + .apbclock = STM32_PCLK1_FREQUENCY, + .data_pin = PIN_OPENDRAIN(GPIO_USART8_TX), + .irq = STM32_IRQ_USART8, + .vector = up_interrupt_1wire8, +}; + +static struct stm32_1wire_priv_s stm32_1wire8_priv = +{ + .config = &stm32_1wire8_config, + .refs = 0, + .msgs = NULL +}; + +#endif + +/* Device Structures, Instantiation */ + +static const struct onewire_ops_s stm32_1wire_ops = +{ + .reset = stm32_1wire_reset, + .write = stm32_1wire_write, + .read = stm32_1wire_read, + .exchange = stm32_1wire_exchange +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: stm32_1wire_in + ****************************************************************************/ + +static inline uint32_t stm32_1wire_in(struct stm32_1wire_priv_s *priv, + int offset) +{ + return getreg32(priv->config->usartbase + offset); +} + +/**************************************************************************** + * Name: stm32_1wire_out + ****************************************************************************/ + +static inline void stm32_1wire_out(struct stm32_1wire_priv_s *priv, + int offset, uint32_t value) +{ + putreg32(value, priv->config->usartbase + offset); +} + +/**************************************************************************** + * Name: stm32_1wire_recv + * + * Description: + * This method will recv one byte on the USART + * + ****************************************************************************/ + +static int stm32_1wire_recv(struct stm32_1wire_priv_s *priv) +{ + return stm32_1wire_in(priv, STM32_USART_RDR_OFFSET) & 0xff; +} + +/**************************************************************************** + * Name: stm32_1wire_send + * + * Description: + * This method will send one byte on the USART + * + ****************************************************************************/ + +static void stm32_1wire_send(struct stm32_1wire_priv_s *priv, int ch) +{ + stm32_1wire_out(priv, STM32_USART_TDR_OFFSET, (uint32_t)(ch & 0xff)); +} + +/**************************************************************************** + * Name: stm32_1wire_set_baud + * + * Description: + * Set the serial line baud. + * + ****************************************************************************/ + +static void stm32_1wire_set_baud(struct stm32_1wire_priv_s *priv) +{ +#if defined(CONFIG_STM32_STM32F30XX) || defined(CONFIG_STM32_STM32F37XX) + /* This first implementation is for U[S]ARTs that support oversampling + * by 8 in additional to the standard oversampling by 16. + */ + + uint32_t usartdiv8; + uint32_t cr1; + uint32_t brr; + + /* In case of oversampling by 8, the equation is: + * + * baud = 2 * fCK / usartdiv8 + * usartdiv8 = 2 * fCK / baud + */ + + usartdiv8 = ((priv->config->apbclock << 1) + (priv->baud >> 1)) / priv->baud; + + /* Baud rate for standard USART (SPI mode included): + * + * In case of oversampling by 16, the equation is: + * baud = fCK / usartdiv16 + * usartdiv16 = fCK / baud + * = 2 * usartdiv8 + */ + + /* Use oversamply by 8 only if the divisor is small. But what is small? */ + + cr1 = stm32_1wire_in(priv, STM32_USART_CR1_OFFSET); + if (usartdiv8 > 100) + { + /* Use usartdiv16 */ + + brr = (usartdiv8 + 1) >> 1; + + /* Clear oversampling by 8 to enable oversampling by 16 */ + + cr1 &= ~USART_CR1_OVER8; + } + else + { + DEBUGASSERT(usartdiv8 >= 8); + + /* Perform mysterious operations on bits 0-3 */ + + brr = ((usartdiv8 & 0xfff0) | ((usartdiv8 & 0x000f) >> 1)); + + /* Set oversampling by 8 */ + + cr1 |= USART_CR1_OVER8; + } + + stm32_1wire_out(priv, STM32_USART_CR1_OFFSET, cr1); + stm32_1wire_out(priv, STM32_USART_BRR_OFFSET, brr); + +#else + + /* This second implementation is for U[S]ARTs that support fractional + * dividers. + */ + + uint32_t usartdiv32; + uint32_t mantissa; + uint32_t fraction; + uint32_t brr; + + /* Configure the USART Baud Rate. The baud rate for the receiver and + * transmitter (Rx and Tx) are both set to the same value as programmed + * in the Mantissa and Fraction values of USARTDIV. + * + * baud = fCK / (16 * usartdiv) + * usartdiv = fCK / (16 * baud) + * + * Where fCK is the input clock to the peripheral (PCLK1 for USART2, 3, 4, 5 + * or PCLK2 for USART1) + * + * First calculate (NOTE: all stand baud values are even so dividing by two + * does not lose precision): + * + * usartdiv32 = 32 * usartdiv = fCK / (baud/2) + */ + + usartdiv32 = priv->config->apbclock / (priv->baud >> 1); + + /* The mantissa part is then */ + + mantissa = usartdiv32 >> 5; + brr = mantissa << USART_BRR_MANT_SHIFT; + + /* The fractional remainder (with rounding) */ + + fraction = (usartdiv32 - (mantissa << 5) + 1) >> 1; + brr |= fraction << USART_BRR_FRAC_SHIFT; + stm32_1wire_out(priv, STM32_USART_BRR_OFFSET, brr); +#endif +} + +/**************************************************************************** + * Name: stm32_1wire_set_apb_clock + * + * Description: + * Enable or disable APB clock for the USART peripheral + * + * Input parameters: + * priv - A reference to the 1-Wire driver state structure + * on - Enable clock if 'on' is 'true' and disable if 'false' + * + ****************************************************************************/ + +static void stm32_1wire_set_apb_clock(struct stm32_1wire_priv_s *priv, + bool on) +{ + const struct stm32_1wire_config_s *config = priv->config; + uint32_t rcc_en; + uint32_t regaddr; + + /* Determine which USART to configure */ + + switch (config->usartbase) + { + default: + return; + +#ifdef CONFIG_STM32_1WIRE1 + case STM32_USART1_BASE: + rcc_en = RCC_APB2ENR_USART1EN; + regaddr = STM32_RCC_APB2ENR; + break; +#endif +#ifdef CONFIG_STM32_1WIRE2 + case STM32_USART2_BASE: + rcc_en = RCC_APB1ENR_USART2EN; + regaddr = STM32_RCC_APB1ENR; + break; +#endif +#ifdef CONFIG_STM32_1WIRE3 + case STM32_USART3_BASE: + rcc_en = RCC_APB1ENR_USART3EN; + regaddr = STM32_RCC_APB1ENR; + break; +#endif +#ifdef CONFIG_STM32_UART4 + case STM32_UART4_BASE: + rcc_en = RCC_APB1ENR_UART4EN; + regaddr = STM32_RCC_APB1ENR; + break; +#endif +#ifdef CONFIG_STM32_UART5 + case STM32_UART5_BASE: + rcc_en = RCC_APB1ENR_UART5EN; + regaddr = STM32_RCC_APB1ENR; + break; +#endif +#ifdef CONFIG_STM32_1WIRE6 + case STM32_USART6_BASE: + rcc_en = RCC_APB2ENR_USART6EN; + regaddr = STM32_RCC_APB2ENR; + break; +#endif +#ifdef CONFIG_STM32_UART7 + case STM32_UART7_BASE: + rcc_en = RCC_APB1ENR_UART7EN; + regaddr = STM32_RCC_APB1ENR; + break; +#endif +#ifdef CONFIG_STM32_UART8 + case STM32_UART8_BASE: + rcc_en = RCC_APB1ENR_UART8EN; + regaddr = STM32_RCC_APB1ENR; + break; +#endif + } + + /* Enable/disable APB 1/2 clock for USART */ + + if (on) + { + modifyreg32(regaddr, 0, rcc_en); + } + else + { + modifyreg32(regaddr, rcc_en, 0); + } +} + +/**************************************************************************** + * Name: stm32_1wire_init + * + * Description: + * Setup the 1-Wire hardware, ready for operation with defaults + * + ****************************************************************************/ + +static int stm32_1wire_init(FAR struct stm32_1wire_priv_s *priv) +{ + const struct stm32_1wire_config_s *config = priv->config; + uint32_t regval; + int ret; + + /* Enable USART APB1/2 clock */ + + stm32_1wire_set_apb_clock(priv, true); + + /* Configure CR2 */ + /* Clear STOP, CLKEN, CPOL, CPHA, LBCL, and interrupt enable bits */ + /* Set LBDIE */ + + regval = stm32_1wire_in(priv, STM32_USART_CR2_OFFSET); + regval &= ~(USART_CR2_STOP_MASK | USART_CR2_CLKEN | USART_CR2_CPOL | + USART_CR2_CPHA | USART_CR2_LBCL | USART_CR2_LBDIE); + regval |= USART_CR2_LBDIE; + stm32_1wire_out(priv, STM32_USART_CR2_OFFSET, regval); + + /* Configure CR1 */ + /* Clear TE, REm, all interrupt enable bits, PCE, PS and M */ + /* Set RXNEIE */ + + regval = stm32_1wire_in(priv, STM32_USART_CR1_OFFSET); + regval &= ~(USART_CR1_TE | USART_CR1_RE | USART_CR1_ALLINTS | + USART_CR1_PCE | USART_CR1_PS | USART_CR1_M); + regval |= USART_CR1_RXNEIE; + stm32_1wire_out(priv, STM32_USART_CR1_OFFSET, regval); + + /* Configure CR3 */ + /* Clear CTSE, RTSE, and all interrupt enable bits */ + /* Set ONEBIT, HDSEL and EIE */ + + regval = stm32_1wire_in(priv, STM32_USART_CR3_OFFSET); + regval &= ~(USART_CR3_CTSIE | USART_CR3_CTSE | USART_CR3_RTSE | USART_CR3_EIE); + regval |= (USART_CR3_ONEBIT | USART_CR3_HDSEL | USART_CR3_EIE); + stm32_1wire_out(priv, STM32_USART_CR3_OFFSET, regval); + + /* Set baud rate */ + + priv->baud = RESET_BAUD; + stm32_1wire_set_baud(priv); + + /* Enable Rx, Tx, and the USART */ + + regval = stm32_1wire_in(priv, STM32_USART_CR1_OFFSET); + regval |= (USART_CR1_UE | USART_CR1_TE | USART_CR1_RE); + stm32_1wire_out(priv, STM32_USART_CR1_OFFSET, regval); + + /* Configure pins for USART use */ + + stm32_configgpio(config->data_pin); + + ret = irq_attach(config->irq, config->vector); + if (ret == OK) + { + up_enable_irq(config->irq); + } + + return ret; +} + +/**************************************************************************** + * Name: stm32_1wire_deinit + * + * Description: + * Shutdown the 1-Wire hardware + * + ****************************************************************************/ + +static int stm32_1wire_deinit(FAR struct stm32_1wire_priv_s *priv) +{ + const struct stm32_1wire_config_s *config = priv->config; + uint32_t regval; + + up_disable_irq(config->irq); + irq_detach(config->irq); + + /* Unconfigure GPIO pins */ + + stm32_unconfiggpio(config->data_pin); + + /* Disable RXNEIE, Rx, Tx, and the USART */ + + regval = stm32_1wire_in(priv, STM32_USART_CR1_OFFSET); + regval &= ~(USART_CR1_UE | USART_CR1_TE | USART_CR1_RE | USART_CR1_RXNEIE); + stm32_1wire_out(priv, STM32_USART_CR1_OFFSET, regval); + + /* Clear LBDIE */ + + regval = stm32_1wire_in(priv, STM32_USART_CR2_OFFSET); + regval &= ~USART_CR2_LBDIE; + stm32_1wire_out(priv, STM32_USART_CR2_OFFSET, regval); + + /* Clear ONEBIT, HDSEL and EIE */ + + regval = stm32_1wire_in(priv, STM32_USART_CR3_OFFSET); + regval &= ~(USART_CR3_ONEBIT | USART_CR3_HDSEL | USART_CR3_EIE); + stm32_1wire_out(priv, STM32_USART_CR3_OFFSET, regval); + + /* Disable USART APB1/2 clock */ + + stm32_1wire_set_apb_clock(priv, false); + + return OK; +} + +/**************************************************************************** + * Name: stm32_1wire_sem_init + * + * Description: + * Initialize semaphores + * + ****************************************************************************/ + +static inline void stm32_1wire_sem_init(FAR struct stm32_1wire_priv_s *priv) +{ + sem_init(&priv->sem_excl, 0, 1); + sem_init(&priv->sem_isr, 0, 0); +} + +/**************************************************************************** + * Name: stm32_1wire_sem_destroy + * + * Description: + * Destroy semaphores. + * + ****************************************************************************/ + +static inline void stm32_1wire_sem_destroy(FAR struct stm32_1wire_priv_s *priv) +{ + sem_destroy(&priv->sem_excl); + sem_destroy(&priv->sem_isr); +} + +/**************************************************************************** + * Name: stm32_1wire_sem_wait + * + * Description: + * Take the exclusive access, waiting as necessary + * + ****************************************************************************/ + +static inline void stm32_1wire_sem_wait(FAR struct stm32_1wire_priv_s *priv) +{ + while (sem_wait(&priv->sem_excl) != 0) + { + ASSERT(errno == EINTR); + } +} + +/**************************************************************************** + * Name: stm32_1wire_sem_post + * + * Description: + * Release the mutual exclusion semaphore + * + ****************************************************************************/ + +static inline void stm32_1wire_sem_post(FAR struct stm32_1wire_priv_s *priv) +{ + sem_post(&priv->sem_excl); +} + +/**************************************************************************** + * Name: stm32_1wire_exec + * + * Description: + * Execute 1-Wire task + ****************************************************************************/ +static int stm32_1wire_process(struct stm32_1wire_priv_s *priv, + FAR const struct stm32_1wire_msg_s *msgs, + int count) +{ + irqstate_t irqs; + struct timespec abstime; + int ret; + + /* Lock out other clients */ + + stm32_1wire_sem_wait(priv); + + priv->result = ERROR; + + for (int indx = 0; indx < count; indx++) + { + switch (msgs[indx].task) + { + case ONEWIRETASK_NONE: + priv->result = OK; + break; + + case ONEWIRETASK_RESET: + /* Set baud rate */ + + priv->baud = RESET_BAUD; + stm32_1wire_set_baud(priv); + + /* Atomic */ + + irqs = irqsave(); + priv->msgs = &msgs[indx]; + stm32_1wire_send(priv, RESET_TX); + irqrestore(irqs); + + /* Wait */ + + clock_gettime(CLOCK_REALTIME, &abstime); + abstime.tv_sec += BUS_TIMEOUT; + sem_timedwait(&priv->sem_isr, &abstime); /* break on timeout if TX line closed to GND */ + break; + + case ONEWIRETASK_WRITE: + /* Set baud rate */ + + priv->baud = TIMESLOT_BAUD; + stm32_1wire_set_baud(priv); + + /* Atomic */ + + irqs = irqsave(); + priv->msgs = &msgs[indx]; + priv->byte = priv->msgs->buffer; + priv->bit = 0; + stm32_1wire_send(priv, (*priv->byte & (1 << priv->bit)) ? WRITE_TX1 : WRITE_TX0); + irqrestore(irqs); + + /* Wait */ + + clock_gettime(CLOCK_REALTIME, &abstime); + abstime.tv_sec += BUS_TIMEOUT; + sem_timedwait(&priv->sem_isr, &abstime); /* break on timeout if TX line closed to GND */ + break; + + case ONEWIRETASK_READ: + /* Set baud rate */ + + priv->baud = TIMESLOT_BAUD; + stm32_1wire_set_baud(priv); + + /* Atomic */ + + irqs = irqsave(); + priv->msgs = &msgs[indx]; + priv->byte = priv->msgs->buffer; + priv->bit = 0; + stm32_1wire_send(priv, READ_TX); + irqrestore(irqs); + + /* Wait */ + + clock_gettime(CLOCK_REALTIME, &abstime); + abstime.tv_sec += BUS_TIMEOUT; + sem_timedwait(&priv->sem_isr, &abstime); /* break on timeout if TX line closed to GND */ + break; + } + + if (priv->result != OK) /* break if error */ + { + break; + } + } + + /* Atomic */ + + irqs = irqsave(); + priv->msgs = NULL; + ret = priv->result; + irqrestore(irqs); + + /* Release the port for re-use by other clients */ + + stm32_1wire_sem_post(priv); + + return ret; +} + +/**************************************************************************** + * Name: stm32_1wire_isr + * + * Description: + * Common Interrupt Service Routine + ****************************************************************************/ + +static int stm32_1wire_isr(struct stm32_1wire_priv_s *priv) +{ + uint32_t sr, dr; + + /* Get the masked USART status word. */ + + sr = stm32_1wire_in(priv, STM32_USART_SR_OFFSET); + + /* Receive loop */ + + if ((sr & USART_SR_RXNE) != 0) + { + dr = stm32_1wire_recv(priv); + + if (priv->msgs != NULL) + { + switch (priv->msgs->task) + { + case ONEWIRETASK_NONE: + break; + + case ONEWIRETASK_RESET: + priv->msgs = NULL; + priv->result = (dr != RESET_TX) ? OK : -ENODEV; /* if read RESET_TX then no slave */ + sem_post(&priv->sem_isr); + break; + + case ONEWIRETASK_WRITE: + if (++priv->bit >= 8) + { + priv->bit = 0; + if (++priv->byte >= (priv->msgs->buffer + priv->msgs->buflen)) /* Done? */ + { + priv->msgs = NULL; + priv->result = OK; + sem_post(&priv->sem_isr); + break; + } + } + + /* Send next bit */ + + stm32_1wire_send(priv, (*priv->byte & (1 << priv->bit)) ? WRITE_TX1 : WRITE_TX0); + break; + + case ONEWIRETASK_READ: + if (dr == READ_RX1) + { + *priv->byte |= (1 << priv->bit); + } + else + { + *priv->byte &= ~(1 << priv->bit); + } + + if (++priv->bit >= 8) + { + priv->bit = 0; + if (++priv->byte >= (priv->msgs->buffer + priv->msgs->buflen)) /* Done? */ + { + priv->msgs = NULL; + priv->result = OK; + sem_post(&priv->sem_isr); + break; + } + } + + /* Recv next bit */ + + stm32_1wire_send(priv, READ_TX); + break; + } + } + } + + /* Bounce check. */ + + if ((sr & (USART_SR_ORE | USART_SR_NE | USART_SR_FE)) != 0) + { +#if defined(CONFIG_STM32_STM32F30XX) || defined(CONFIG_STM32_STM32F37XX) + /* These errors are cleared by writing the corresponding bit to the + * interrupt clear register (ICR). + */ + + stm32_1wire_out(priv, STM32_USART_ICR_OFFSET, + (USART_ICR_NCF | USART_ICR_ORECF | USART_ICR_FECF)); +#else + /* If an error occurs, read from DR to clear the error (data has + * been lost). If ORE is set along with RXNE then it tells you + * that the byte *after* the one in the data register has been + * lost, but the data register value is correct. That case will + * be handled above if interrupts are enabled. Otherwise, that + * good byte will be lost. + */ + + (void)stm32_1wire_recv(priv); +#endif + + if (priv->msgs != NULL) + { + priv->msgs = NULL; + priv->result = ERROR; + sem_post(&priv->sem_isr); + } + } + + /* Bounce check. LIN break detection */ + + if ((sr & USART_SR_LBD) != 0) + { + sr &= ~USART_SR_LBD; + stm32_1wire_out(priv, STM32_USART_SR_OFFSET, sr); + + if (priv->msgs != NULL) + { + priv->msgs = NULL; + priv->result = ERROR; + sem_post(&priv->sem_isr); + } + } + + return OK; +} + +#ifdef CONFIG_STM32_1WIRE1 +static int up_interrupt_1wire1(int irq, void *context) +{ + return stm32_1wire_isr(&stm32_1wire1_priv); +} +#endif +#ifdef CONFIG_STM32_1WIRE2 +static int up_interrupt_1wire2(int irq, void *context) +{ + return stm32_1wire_isr(&stm32_1wire2_priv); +} +#endif +#ifdef CONFIG_STM32_1WIRE3 +static int up_interrupt_1wire3(int irq, void *context) +{ + return stm32_1wire_isr(&stm32_1wire3_priv); +} +#endif +#ifdef CONFIG_STM32_1WIRE4 +static int up_interrupt_1wire4(int irq, void *context) +{ + return stm32_1wire_isr(&stm32_1wire4_priv); +} +#endif +#ifdef CONFIG_STM32_1WIRE5 +static int up_interrupt_1wire5(int irq, void *context) +{ + return stm32_1wire_isr(&stm32_1wire5_priv); +} +#endif +#ifdef CONFIG_STM32_1WIRE6 +static int up_interrupt_1wire6(int irq, void *context) +{ + return stm32_1wire_isr(&stm32_1wire6_priv); +} +#endif +#ifdef CONFIG_STM32_1WIRE7 +static int up_interrupt_1wire7(int irq, void *context) +{ + return stm32_1wire_isr(&stm32_1wire7_priv); +} +#endif +#ifdef CONFIG_STM32_1WIRE8 +static int up_interrupt_1wire8(int irq, void *context) +{ + return stm32_1wire_isr(&stm32_1wire8_priv); +} +#endif + +/**************************************************************************** + * Name: stm32_1wire_reset + * + * Description: + * 1-Wire reset pulse and presence detect. + * + ****************************************************************************/ + +static int stm32_1wire_reset(FAR struct onewire_dev_s *dev) +{ + struct stm32_1wire_priv_s *priv = ((struct stm32_1wire_inst_s *)dev)->priv; + const struct stm32_1wire_msg_s msgs[1] = + { + [0].task = ONEWIRETASK_RESET + }; + + return stm32_1wire_process(priv, msgs, 1); +} + +/**************************************************************************** + * Name: stm32_1wire_write + * + * Description: + * Write 1-Wire data + * + ****************************************************************************/ + +static int stm32_1wire_write(FAR struct onewire_dev_s *dev, const uint8_t *buffer, + int buflen) +{ + struct stm32_1wire_priv_s *priv = ((struct stm32_1wire_inst_s *)dev)->priv; + const struct stm32_1wire_msg_s msgs[1] = + { + [0].task = ONEWIRETASK_WRITE, + [0].buffer = (uint8_t *)buffer, + [0].buflen = buflen + }; + + return stm32_1wire_process(priv, msgs, 1); +} + +/**************************************************************************** + * Name: stm32_1wire_read + * + * Description: + * Read 1-Wire data + * + ****************************************************************************/ + +static int stm32_1wire_read(FAR struct onewire_dev_s *dev, uint8_t *buffer, int buflen) +{ + struct stm32_1wire_priv_s *priv = ((struct stm32_1wire_inst_s *)dev)->priv; + const struct stm32_1wire_msg_s msgs[1] = + { + [0].task = ONEWIRETASK_READ, + [0].buffer = buffer, + [0].buflen = buflen + }; + + return stm32_1wire_process(priv, msgs, 1); +} + +/**************************************************************************** + * Name: stm32_1wire_exchange + * + * Description: + * 1-Wire reset pulse and presence detect, + * Write 1-Wire data, + * Read 1-Wire data + * + ****************************************************************************/ + +static int stm32_1wire_exchange(FAR struct onewire_dev_s *dev, bool reset, + const uint8_t *txbuffer, int txbuflen, + uint8_t *rxbuffer, int rxbuflen) + +{ + int result = ERROR; + struct stm32_1wire_priv_s *priv = ((struct stm32_1wire_inst_s *)dev)->priv; + + if (reset) + { + const struct stm32_1wire_msg_s msgs[3] = + { + [0].task = ONEWIRETASK_RESET, + + [1].task = ONEWIRETASK_WRITE, + [1].buffer = (uint8_t *)txbuffer, + [1].buflen = txbuflen, + + [2].task = ONEWIRETASK_READ, + [2].buffer = rxbuffer, + [2].buflen = rxbuflen + }; + + result = stm32_1wire_process(priv, msgs, 3); + } + else + { + const struct stm32_1wire_msg_s msgs[2] = + { + [0].task = ONEWIRETASK_WRITE, + [0].buffer = (uint8_t *)txbuffer, + [0].buflen = txbuflen, + + [1].task = ONEWIRETASK_READ, + [1].buffer = rxbuffer, + [1].buflen = rxbuflen + }; + + result = stm32_1wire_process(priv, msgs, 2); + } + return result; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_1wireinitialize + * + * Description: + * Initialize one 1-Wire port + * + ****************************************************************************/ + +FAR struct onewire_dev_s *up_1wireinitialize(int port) +{ + struct stm32_1wire_priv_s *priv = NULL; /* Private data of device with multiple instances */ + struct stm32_1wire_inst_s *inst = NULL; /* Device, single instance */ + int irqs; + + /* Get 1-Wire private structure */ + + switch (port) + { +#ifdef CONFIG_STM32_1WIRE1 + case 1: + priv = &stm32_1wire1_priv; + break; +#endif +#ifdef CONFIG_STM32_1WIRE2 + case 2: + priv = &stm32_1wire2_priv; + break; +#endif +#ifdef CONFIG_STM32_1WIRE3 + case 3: + priv = &stm32_1wire3_priv; + break; +#endif +#ifdef CONFIG_STM32_1WIRE4 + case 4: + priv = &stm32_1wire4_priv; + break; +#endif +#ifdef CONFIG_STM32_1WIRE5 + case 5: + priv = &stm32_1wire5_priv; + break; +#endif +#ifdef CONFIG_STM32_1WIRE6 + case 6: + priv = &stm32_1wire6_priv; + break; +#endif +#ifdef CONFIG_STM32_1WIRE7 + case 7: + priv = &stm32_1wire7_priv; + break; +#endif +#ifdef CONFIG_STM32_1WIRE8 + case 8: + priv = &stm32_1wire8_priv; + break; +#endif + default: + return NULL; + } + + /* Allocate instance */ + + if (!(inst = kmm_malloc(sizeof(struct stm32_1wire_inst_s)))) + { + return NULL; + } + + /* Initialize instance */ + + inst->ops = &stm32_1wire_ops; + inst->priv = priv; + + /* Initialize private data for the first time, increment reference count, + * power-up hardware and configure GPIOs. + */ + + irqs = irqsave(); + + if (priv->refs++ == 0) + { + stm32_1wire_sem_init(priv); + stm32_1wire_init(priv); + } + + irqrestore(irqs); + return (struct onewire_dev_s *)inst; +} + +/**************************************************************************** + * Name: up_1wireuninitialize + * + * Description: + * Uninitialize an 1-Wire port + * + ****************************************************************************/ + +int up_1wireuninitialize(FAR struct onewire_dev_s *dev) +{ + struct stm32_1wire_priv_s *priv = ((struct stm32_1wire_inst_s *)dev)->priv; + int irqs; + + ASSERT(dev); + + /* Decrement reference count and check for underflow */ + + if (priv->refs == 0) + { + return ERROR; + } + + irqs = irqsave(); + + if (--priv->refs) + { + irqrestore(irqs); + kmm_free(priv); + return OK; + } + + irqrestore(irqs); + + /* Disable power and other HW resource (GPIO's) */ + + stm32_1wire_deinit(priv); + + /* Release unused resources */ + + stm32_1wire_sem_destroy(priv); + + /* Free instance */ + + kmm_free(dev); + return OK; +} diff --git a/arch/arm/src/stm32/stm32_1wire.h b/arch/arm/src/stm32/stm32_1wire.h new file mode 100644 index 00000000000..3052849ac05 --- /dev/null +++ b/arch/arm/src/stm32/stm32_1wire.h @@ -0,0 +1,113 @@ +/************************************************************************************ + * arch/arm/src/stm32/stm32_1wire.h + * + * Copyright (C) 2016 Aleksandr Vyhovanec. All rights reserved. + * Author: Aleksandr Vyhovanec + * + * 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 NuttX nor the names of its contributors 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 OWNER 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. + * + ************************************************************************************/ + +#ifndef __ARCH_ARM_SRC_STM32_STM32_1WIRE_H +#define __ARCH_ARM_SRC_STM32_STM32_1WIRE_H + +/************************************************************************************ + * Included Files + ************************************************************************************/ + +#include + +#include "chip.h" + +#if defined(CONFIG_STM32_STM32L15XX) +# include "chip/stm32l15xxx_uart.h" +#elif defined(CONFIG_STM32_STM32F10XX) +# include "chip/stm32f10xxx_uart.h" +#elif defined(CONFIG_STM32_STM32F20XX) +# include "chip/stm32f20xxx_uart.h" +#elif defined(CONFIG_STM32_STM32F30XX) || defined(CONFIG_STM32_STM32F37XX) +# include "chip/stm32f30xxx_uart.h" +#elif defined(CONFIG_STM32_STM32F40XX) +# include "chip/stm32f40xxx_uart.h" +#else +# error "Unsupported STM32 UART" +#endif + +/************************************************************************************ + * Pre-processor Definitions + ************************************************************************************/ + +/* Check 1-Wire and U(S)ART conflicting */ + +#if defined(CONFIG_STM32_1WIRE1) && defined(CONFIG_STM32_USART1) +# undef CONFIG_STM32_1WIRE1 +#endif +#if defined(CONFIG_STM32_1WIRE2) && defined(CONFIG_STM32_USART2) +# undef CONFIG_STM32_1WIRE2 +#endif +#if defined(CONFIG_STM32_1WIRE3) && defined(CONFIG_STM32_USART3) +# undef CONFIG_STM32_1WIRE3 +#endif +#if defined(CONFIG_STM32_1WIRE4) && defined(CONFIG_STM32_UART4) +# undef CONFIG_STM32_1WIRE4 +#endif +#if defined(CONFIG_STM32_1WIRE5) && defined(CONFIG_STM32_UART5) +# undef CONFIG_STM32_1WIRE5 +#endif +#if defined(CONFIG_STM32_1WIRE6) && defined(CONFIG_STM32_USART6) +# undef CONFIG_STM32_1WIRE6 +#endif +#if defined(CONFIG_STM32_1WIRE7) && defined(CONFIG_STM32_UART7) +# undef CONFIG_STM32_1WIRE7 +#endif +#if defined(CONFIG_STM32_1WIRE8) && defined(CONFIG_STM32_UART8) +# undef CONFIG_STM32_1WIRE8 +#endif + +/* Is there a 1-Wire enabled? */ + +#if defined(CONFIG_STM32_1WIRE1) || defined(CONFIG_STM32_1WIRE2) || \ + defined(CONFIG_STM32_1WIRE3) || defined(CONFIG_STM32_1WIRE4) || \ + defined(CONFIG_STM32_1WIRE5) || defined(CONFIG_STM32_1WIRE6) || \ + defined(CONFIG_STM32_1WIRE7) || defined(CONFIG_STM32_1WIRE8) +# define HAVE_1WIRE 1 +#endif + +/************************************************************************************ + * Public Types + ************************************************************************************/ + +/************************************************************************************ + * Public Data + ************************************************************************************/ + +/************************************************************************************ + * Public Functions + ************************************************************************************/ + +#endif /* __ARCH_ARM_SRC_STM32_STM32_1WIRE_H */ diff --git a/include/nuttx/1wire.h b/include/nuttx/1wire.h new file mode 100644 index 00000000000..fe2dd87a7b7 --- /dev/null +++ b/include/nuttx/1wire.h @@ -0,0 +1,215 @@ +/**************************************************************************** + * include/nuttx/1wire.h + * + * Copyright (C) 2016 Aleksandr Vyhovanec. All rights reserved. + * Author: Aleksandr Vyhovanec + * + * 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 NuttX nor the names of its contributors 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 OWNER 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. + * + ****************************************************************************/ + +#ifndef __INCLUDE_NUTTX_1WIRE_H +#define __INCLUDE_NUTTX_1WIRE_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Name: ONEWIRE_RESET + * + * Description: + * Reset pulse and presence detect. Each write operational will be an 'atomic' + * operation in the sense that any other 1-Wire actions will be serialized + * and pend until this write completes. + * + * Input Parameters: + * dev - Device-specific state data + * + * Returned Value: + * 0: success, <0: A negated errno + * + ****************************************************************************/ + +#define ONEWIRE_RESET(d) ((d)->ops->reset(d)) + +/**************************************************************************** + * Name: ONEWIRE_WRITE + * + * Description: + * Send a block of data on 1-Wire. Each write operational will be an 'atomic' + * operation in the sense that any other 1-Wire actions will be serialized + * and pend until this write completes. + * + * Input Parameters: + * dev - Device-specific state data + * buffer - A pointer to the read-only buffer of data to be written to device + * buflen - The number of bytes to send from the buffer + * + * Returned Value: + * 0: success, <0: A negated errno + * + ****************************************************************************/ + +#define ONEWIRE_WRITE(d,b,l) ((d)->ops->write(d,b,l)) + +/**************************************************************************** + * Name: ONEWIRE_READ + * + * Description: + * Receive a block of data from 1-Wire. Each read operational will be an 'atomic' + * operation in the sense that any other 1-Wire actions will be serialized + * and pend until this read completes. + * + * Input Parameters: + * dev - Device-specific state data + * buffer - A pointer to a buffer of data to receive the data from the device + * buflen - The requested number of bytes to be read + * + * Returned Value: + * 0: success, <0: A negated errno + * + ****************************************************************************/ + +#define ONEWIRE_READ(d,b,l) ((d)->ops->read(d,b,l)) + +/**************************************************************************** + * Name: ONEWIRE_EXCHANGE + * + * Description: + * Reset pulse and presence detect, send a block of data and receive a block + * of data from 1-Wir. Each write operational will be an 'atomic' + * operation in the sense that any other 1-Wire actions will be serialized + * and pend until this write completes. + * + * Input Parameters: + * dev - Device-specific state data + * reset - Reset pulse and presence detect + * txbuffer - A pointer to the read-only buffer of data to be written to device + * txbuflen - The number of bytes to send from the buffer + * rxbuffer - A pointer to a buffer of data to receive the data from the device + * rxbuflen - The requested number of bytes to be read + * + * Returned Value: + * 0: success, <0: A negated errno + * + ****************************************************************************/ + +#define ONEWIRE_EXCHANGE(d,r,tx,tl,rx,rl) ((d)->ops->exchange(d,r,tx,tl,rx,rl)) + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/* The 1-Wire vtable */ + +struct onewire_dev_s; +struct onewire_ops_s +{ + int (*reset)(FAR struct onewire_dev_s *dev); + int (*write)(FAR struct onewire_dev_s *dev, FAR const uint8_t *buffer, + int buflen); + int (*read)(FAR struct onewire_dev_s *dev, FAR uint8_t *buffer, + int buflen); + int (*exchange)(FAR struct onewire_dev_s *dev, bool reset, + FAR const uint8_t *txbuffer, int txbuflen, + FAR uint8_t *rxbuffer, int rxbuflen); +}; + +/* 1-Wire private data. This structure only defines the initial fields of the + * structure visible to the 1-Wire client. The specific implementation may + * add additional, device specific fields after the vtable. + */ + +struct onewire_dev_s +{ + const struct onewire_ops_s *ops; /* 1-Wire vtable */ +}; + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Name: up_1wireinitialize + * + * Description: + * Initialize the selected 1-Wire port. And return a unique instance of struct + * struct onewire_dev_s. This function may be called to obtain multiple + * instances of the interface, each of which may be set up with a + * different frequency and slave address. + * + * Input Parameter: + * Port number (for hardware that has multiple 1-Wire interfaces) + * + * Returned Value: + * Valid 1-Wire device structure reference on succcess; a NULL on failure + * + ****************************************************************************/ + +FAR struct onewire_dev_s *up_1wireinitialize(int port); + +/**************************************************************************** + * Name: up_1wireuninitialize + * + * Description: + * De-initialize the selected 1-Wire port, and power down the device. + * + * Input Parameter: + * Device structure as returned by the up_1wireinitialize() + * + * Returned Value: + * OK on success, ERROR when internal reference count mismatch or dev + * points to invalid hardware device. + * + ****************************************************************************/ + +int up_1wireuninitialize(FAR struct onewire_dev_s *dev); + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __INCLUDE_NUTTX_1WIRE_H */