ChibiOS/os/hal/include/hal_sio.h

602 lines
19 KiB
C

/*
ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file hal_sio.h
* @brief SIO Driver macros and structures.
*
* @addtogroup SIO
* @{
*/
#ifndef HAL_SIO_H
#define HAL_SIO_H
#if (HAL_USE_SIO == TRUE) || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
/**
* @name SIO masks offsets
* @{
*/
#define SIO_EV_RXNOTEMPY_POS 2 /* CHN_INPUT_AVAILABLE */
#define SIO_EV_TXNOTFULL_POS 3 /* CHN_OUTPUT_EMPTY */
#define SIO_EV_TXDONE_POS 4 /* CHN_TRANSMISSION_END */
#define SIO_EV_ALL_ERRORS_POS SIO_EV_PARITY_ERR_POS
#define SIO_EV_PARITY_ERR_POS 5 /* CHN_PARITY_ERROR */
#define SIO_EV_FRAMING_ERR_POS 6 /* CHN_FRAMING_ERROR */
#define SIO_EV_NOISE_ERR_POS 7 /* CHN_NOISE_ERROR */
#define SIO_EV_OVERRUN_ERR_POS 8 /* CHN_OVERRUN_ERROR */
#define SIO_EV_RXIDLE_POS 9 /* CHN_IDLE_DETECTED */
#define SIO_EV_RXBREAK_POS 10 /* CHN_BREAK_DETECTED */
/** @} */
/**
* @name Event flags (compatible with channel and serial events)
* @{
*/
#define SIO_EV_NONE 0U
#define SIO_EV_RXNOTEMPY (1U << SIO_EV_RXNOTEMPY_POS)
#define SIO_EV_TXNOTFULL (1U << SIO_EV_TXNOTFULL_POS)
#define SIO_EV_ALL_DATA (SIO_EV_RXNOTEMPY | SIO_EV_TXNOTFULL)
#define SIO_EV_TXDONE (1U << SIO_EV_TXDONE_POS)
#define SIO_EV_PARITY_ERR (1U << SIO_EV_PARITY_ERR_POS)
#define SIO_EV_FRAMING_ERR (1U << SIO_EV_FRAMING_ERR_POS)
#define SIO_EV_NOISE_ERR (1U << SIO_EV_NOISE_ERR_POS)
#define SIO_EV_OVERRUN_ERR (1U << SIO_EV_OVERRUN_ERR_POS)
#define SIO_EV_RXIDLE (1U << SIO_EV_RXIDLE_POS)
#define SIO_EV_RXBREAK (1U << SIO_EV_RXBREAK_POS)
#define SIO_EV_ALL_ERRORS (SIO_EV_PARITY_ERR | \
SIO_EV_FRAMING_ERR | \
SIO_EV_OVERRUN_ERR | \
SIO_EV_NOISE_ERR | \
SIO_EV_RXBREAK)
#define SIO_EV_ALL_EVENTS (SIO_EV_ALL_DATA | \
SIO_EV_ALL_ERRORS | \
SIO_EV_TXDONE | \
SIO_EV_RXIDLE)
/** @} */
/**
* @name Additional messages
* @{
*/
#define SIO_MSG_ERRORS 1
/** @} */
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/**
* @name SIO configuration options
* @{
*/
/**
* @brief Default bit rate.
* @details Configuration parameter, this is the baud rate selected for the
* default configuration.
*/
#if !defined(SIO_DEFAULT_BITRATE) || defined(__DOXYGEN__)
#define SIO_DEFAULT_BITRATE 38400
#endif
/**
* @brief Support for thread synchronization API.
*/
#if !defined(SIO_USE_SYNCHRONIZATION) || defined(__DOXYGEN__)
#define SIO_USE_SYNCHRONIZATION TRUE
#endif
/**
* @brief Support for streams interfacwe.
*/
#if !defined(SIO_USE_STREAMS_INTERFACE) || defined(__DOXYGEN__)
#define SIO_USE_STREAMS_INTERFACE SIO_USE_SYNCHRONIZATION
#endif
/** @} */
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
#if (SIO_USE_STREAMS_INTERFACE == TRUE) && (SIO_USE_SYNCHRONIZATION == FALSE)
#error "SIO_USE_STREAMS_INTERFACE requires SIO_USE_SYNCHRONIZATION"
#endif
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @brief Type of event flags.
*/
typedef eventflags_t sioevents_t;
/**
* @brief Type of structure representing a SIO driver.
*/
typedef struct hal_sio_driver SIODriver;
/**
* @brief Type of structure representing a SIO configuration.
*/
typedef struct hal_sio_config SIOConfig;
/**
* @brief Generic SIO notification callback type.
*
* @param[in] siop pointer to the @p SIODriver object
*/
typedef void (*siocb_t)(SIODriver *siop);
/**
* @brief Driver state machine possible states.
*/
typedef enum {
SIO_UNINIT = 0, /**< Not initialized. */
SIO_STOP = 1, /**< Stopped. */
SIO_READY = 2, /**< Ready. */
} siostate_t;
#include "hal_sio_lld.h"
/**
* @brief Driver configuration structure.
* @note Implementations may extend this structure to contain more,
* architecture dependent, fields.
*/
struct hal_sio_config {
/* End of the mandatory fields.*/
sio_lld_config_fields;
#if defined(SIO_CONFIG_EXT_FIELS)
SIO_CONFIG_EXT_FIELDS
#endif
};
/**
* @brief @p SIODriver specific methods.
*/
#define _sio_driver_methods \
_base_channel_methods
/**
* @extends BaseChannelVMT
*
* @brief @p SIODriver virtual methods table.
*/
struct sio_driver_vmt {
_sio_driver_methods
};
/**
* @brief Structure representing a SIO driver.
* @note Implementations may extend this structure to contain more,
* architecture dependent, fields.
*/
struct hal_sio_driver {
#if (SIO_USE_STREAMS_INTERFACE == TRUE) || defined(__DOXYGEN__)
/**
* @brief Virtual Methods Table.
*/
const struct sio_driver_vmt *vmt;
#endif
/**
* @brief Driver state.
*/
siostate_t state;
/**
* @brief Current configuration data.
*/
const SIOConfig *config;
/**
* @brief Enabled event flags.
*/
sioevents_t enabled;
/**
* @brief Events callback.
* @note Can be @p NULL.
*/
siocb_t cb;
/**
* @brief User argument.
* @note Can be retrieved through the @p siop argument of the callback.
*/
void *arg;
#if (SIO_USE_SYNCHRONIZATION == TRUE) || defined(__DOXYGEN__)
/**
* @brief Synchronization point for RX.
*/
thread_reference_t sync_rx;
/**
* @brief Synchronization point for RX idle.
*/
thread_reference_t sync_rxidle;
/**
* @brief Synchronization point for TX.
*/
thread_reference_t sync_tx;
/**
* @brief Synchronization point for TX-end.
*/
thread_reference_t sync_txend;
#endif /* SIO_USE_SYNCHRONIZATION == TRUE */
#if defined(SIO_DRIVER_EXT_FIELS)
SIO_DRIVER_EXT_FIELDS
#endif
/* End of the mandatory fields.*/
sio_lld_driver_fields;
};
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/**
* @brief Associates a callback to the SIO instance.
*
* @param[in] siop pointer to the @p SIODriver object
* @param[in] f callback to be associated
*/
#define sioSetCallbackX(siop, f) (siop)->cb = (f)
/**
* @brief Determines the state of the RX FIFO.
*
* @param[in] siop pointer to the @p SIODriver object
* @return The RX FIFO state.
* @retval false if RX FIFO is not empty.
* @retval true if RX FIFO is empty.
*
* @xclass
*/
#define sioIsRXEmptyX(siop) sio_lld_is_rx_empty(siop)
/**
* @brief Determines the activity state of the receiver.
*
* @param[in] siop pointer to the @p SIODriver object
* @return The RX activity state.
* @retval false if RX is in active state.
* @retval true if RX is in idle state.
*
* @xclass
*/
#define sioIsRXIdleX(siop) sio_lld_is_rx_idle(siop)
/**
* @brief Determines if RX has pending errors to be read and cleared.
* @note Only errors are handled, data and idle events are not considered.
*
* @param[in] siop pointer to the @p SIODriver object
* @return The RX error events.
* @retval false if RX has no pending events.
* @retval true if RX has pending events.
*
* @xclass
*/
#define sioHasRXErrorsX(siop) sio_lld_has_rx_errors(siop)
/**
* @brief Determines the state of the TX FIFO.
*
* @param[in] siop pointer to the @p SIODriver object
* @return The TX FIFO state.
* @retval false if TX FIFO is not full.
* @retval true if TX FIFO is full.
*
* @xclass
*/
#define sioIsTXFullX(siop) sio_lld_is_tx_full(siop)
/**
* @brief Determines the transmission state.
*
* @param[in] siop pointer to the @p SIODriver object
* @return The TX FIFO state.
* @retval false if transmission is over.
* @retval true if transmission is ongoing.
*
* @xclass
*/
#define sioIsTXOngoingX(siop) sio_lld_is_tx_ongoing(siop)
/**
* @brief Writes the enabled events mask.
*
* @param[in] siop pointer to the @p SIODriver object
* @param[in] mask enabled events mask to be written
*
* @xclass
*/
#define sioWriteEnableFlagsX(siop, mask) do { \
(siop)->enabled = (mask); \
sio_lld_update_enable_flags(siop); \
} while (false)
/**
* @brief Sets flags into the enabled events flags mask.
*
* @param[in] siop pointer to the @p SIODriver object
* @param[in] mask enabled events mask to be set
*
* @xclass
*/
#define sioSetEnableFlagsX(siop, mask) do { \
(siop)->enabled |= (mask); \
sio_lld_update_enable_flags(siop); \
} while (false)
/**
* @brief Clears flags from the enabled events flags mask.
*
* @param[in] siop pointer to the @p SIODriver object
* @param[in] mask enabled events mask to be cleared
*
* @xclass
*/
#define sioClearEnableFlagsX(siop, mask) do { \
(siop)->enabled &= ~(mask); \
sio_lld_update_enable_flags(siop); \
} while (false)
/**
* @brief Return the enabled condition flags mask.
*
* @param[in] siop pointer to the @p SIODriver object
*
* @xclass
*/
#define sioGetEnableFlagsX(siop) (siop)->enabled
/**
* @brief Get and clears SIO error event flags.
*
* @param[in] siop pointer to the @p SIODriver object
* @return The pending error event flags.
*
* @xclass
*/
#define sioGetAndClearErrorsX(siop) sio_lld_get_and_clear_errors(siop)
/**
* @brief Get and clears SIO event flags.
*
* @param[in] siop pointer to the @p SIODriver object
* @return The pending event flags.
*
* @xclass
*/
#define sioGetAndClearEventsX(siop) sio_lld_get_and_clear_events(siop)
/**
* @brief Returns the pending SIO event flags.
*
* @param[in] siop pointer to the @p SIODriver object
* @return The pending event flags.
*
* @xclass
*/
#define sioGetEventsX(siop) sio_lld_get_events(siop)
/**
* @brief Returns one frame from the RX FIFO.
* @note If the FIFO is empty then the returned value is unpredictable.
*
* @param[in] siop pointer to the @p SIODriver object
* @return The frame from RX FIFO.
*
* @xclass
*/
#define sioGetX(siop) sio_lld_get(siop)
/**
* @brief Pushes one frame into the TX FIFO.
* @note If the FIFO is full then the behavior is unpredictable.
*
* @param[in] siop pointer to the @p SIODriver object
* @param[in] data frame to be written
*
* @xclass
*/
#define sioPutX(siop, data) sio_lld_put(siop, data)
/**
* @brief Reads data from the RX FIFO.
* @details This function is non-blocking, data is read if present and the
* effective amount is returned.
* @note This function can be called from any context but it is meant to
* be called from the @p rxne_cb callback handler.
*
* @param[in] siop pointer to the @p SIODriver object
* @param[in] size maximum number of frames to read
* @param[in] buffer buffer for the received data
* @return The number of received frames.
*
* @xclass
*/
#define sioAsyncReadX(siop, size, buffer) sio_lld_read(siop, size, buffer)
/**
* @brief Writes data into the TX FIFO.
* @details This function is non-blocking, data is written if there is space
* in the FIFO and the effective amount is returned.
* @note This function can be called from any context but it is meant to
* be called from the @p txnf_cb callback handler.
*
* @param[in] siop pointer to the @p SIODriver object
* @param[in] size maximum number of frames to read
* @param[out] buffer buffer containing the data to be transmitted
* @return The number of transmitted frames.
*
* @xclass
*/
#define sioAsyncWriteX(siop, size, buffer) sio_lld_write(siop, size, buffer)
/**
* @brief Control operation on a serial port.
*
* @param[in] siop pointer to the @p SIODriver object
* @param[in] operation control operation code
* @param[in,out] arg operation argument
*
* @return The control operation status.
* @retval MSG_OK in case of success.
* @retval MSG_TIMEOUT in case of operation timeout.
* @retval MSG_RESET in case of operation reset.
*
* @xclass
*/
#define sioControlX(siop, operation, arg) sio_lld_control(siop, operation, arg)
/**
* @name Low level driver helper macros
* @{
*/
/**
* @brief SIO callback.
*
* @param[in] siop pointer to the @p SIODriver object
*
* @notapi
*/
#define __sio_callback(siop) do { \
if ((siop)->cb != NULL) { \
(siop)->cb(siop); \
} \
} while (false)
#if (SIO_USE_SYNCHRONIZATION == TRUE) || defined(__DOXYGEN__)
/**
* @brief Wakes up because RX errors.
*
* @param[in] siop pointer to the @p SIODriver object
*
* @notapi
*/
#define __sio_wakeup_errors(siop) do { \
osalSysLockFromISR(); \
osalThreadResumeI(&(siop)->sync_rx, SIO_MSG_ERRORS); \
osalThreadResumeI(&(siop)->sync_rxidle, SIO_MSG_ERRORS); \
osalSysUnlockFromISR(); \
} while (false)
/**
* @brief Wakes up the RX-waiting thread.
*
* @param[in] siop pointer to the @p SIODriver object
*
* @notapi
*/
#define __sio_wakeup_rx(siop) do { \
osalSysLockFromISR(); \
osalThreadResumeI(&(siop)->sync_rx, MSG_OK); \
osalSysUnlockFromISR(); \
} while (false)
/**
* @brief Wakes up the RX-idle-waiting thread.
*
* @param[in] siop pointer to the @p SIODriver object
*
* @notapi
*/
#define __sio_wakeup_rxidle(siop) do { \
osalSysLockFromISR(); \
osalThreadResumeI(&(siop)->sync_rxidle, MSG_OK); \
osalSysUnlockFromISR(); \
} while (false)
/**
* @brief Wakes up the TX-waiting thread.
*
* @param[in] siop pointer to the @p SIODriver object
*
* @notapi
*/
#define __sio_wakeup_tx(siop) do { \
osalSysLockFromISR(); \
osalThreadResumeI(&(siop)->sync_tx, MSG_OK); \
osalSysUnlockFromISR(); \
} while (false)
/**
* @brief Wakes up the TXend-waiting thread.
*
* @param[in] siop pointer to the @p SIODriver object
*
* @notapi
*/
#define __sio_wakeup_txend(siop) do { \
osalSysLockFromISR(); \
osalThreadResumeI(&(siop)->sync_txend, MSG_OK); \
osalSysUnlockFromISR(); \
} while (false)
#else /* !SIO_USE_SYNCHRONIZATION */
#define __sio_wakeup_rx(siop, msg)
#define __sio_wakeup_tx(siop, msg)
#define __sio_wakeup_txend(siop, msg)
#endif /* !SIO_USE_SYNCHRONIZATION */
/** @} */
/**
* @brief Relocates a bit field.
*
* @param[in] v value
* @param[in] m mask of the bit field
* @param[in] s source bit offset
* @param[in] d destination bit offset
*/
#define __sio_reloc_field(v, m, s, d) ((((v) & m) >> (s)) << (d))
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#ifdef __cplusplus
extern "C" {
#endif
void sioInit(void);
void sioObjectInit(SIODriver *siop);
msg_t sioStart(SIODriver *siop, const SIOConfig *config);
void sioStop(SIODriver *siop);
void sioWriteEnableFlags(SIODriver *siop, sioevents_t mask);
void sioSetEnableFlags(SIODriver *siop, sioevents_t mask);
void sioClearEnableFlags(SIODriver *siop, sioevents_t mask);
sioevents_t sioGetAndClearErrors(SIODriver *siop);
sioevents_t sioGetAndClearEvents(SIODriver *siop);
sioevents_t sioGetEvents(SIODriver *siop);
size_t sioAsyncRead(SIODriver *siop, uint8_t *buffer, size_t n);
size_t sioAsyncWrite(SIODriver *siop, const uint8_t *buffer, size_t n);
#if (SIO_USE_SYNCHRONIZATION == TRUE) || defined(__DOXYGEN__)
msg_t sioSynchronizeRX(SIODriver *siop, sysinterval_t timeout);
msg_t sioSynchronizeRXIdle(SIODriver *siop, sysinterval_t timeout);
msg_t sioSynchronizeTX(SIODriver *siop, sysinterval_t timeout);
msg_t sioSynchronizeTXEnd(SIODriver *siop, sysinterval_t timeout);
#endif
#ifdef __cplusplus
}
#endif
#endif /* HAL_USE_SIO == TRUE */
#endif /* HAL_SIO_H */
/** @} */