602 lines
19 KiB
C
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 */
|
|
|
|
/** @} */
|