From 4edc5aeca7251e69dfa772dfdd5b2e012375a809 Mon Sep 17 00:00:00 2001 From: Giovanni Di Sirio Date: Wed, 23 Mar 2016 12:36:05 +0000 Subject: Mass renaming of HAL files. git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@9151 35acf78f-673a-0410-8e92-d51de3d6d3f4 --- os/hal/src/adc.c | 321 -------------- os/hal/src/can.c | 361 ---------------- os/hal/src/dac.c | 349 --------------- os/hal/src/ext.c | 202 --------- os/hal/src/gpt.c | 262 ----------- os/hal/src/hal.c | 144 ------- os/hal/src/hal_adc.c | 321 ++++++++++++++ os/hal/src/hal_can.c | 361 ++++++++++++++++ os/hal/src/hal_dac.c | 349 +++++++++++++++ os/hal/src/hal_ext.c | 202 +++++++++ os/hal/src/hal_gpt.c | 262 +++++++++++ os/hal/src/hal_hal.c | 144 +++++++ os/hal/src/hal_i2c.c | 283 ++++++++++++ os/hal/src/hal_i2s.c | 155 +++++++ os/hal/src/hal_icu.c | 225 ++++++++++ os/hal/src/hal_mac.c | 268 ++++++++++++ os/hal/src/hal_mmc_spi.c | 918 +++++++++++++++++++++++++++++++++++++++ os/hal/src/hal_pal.c | 122 ++++++ os/hal/src/hal_pwm.c | 309 +++++++++++++ os/hal/src/hal_rtc.c | 321 ++++++++++++++ os/hal/src/hal_sdc.c | 1005 +++++++++++++++++++++++++++++++++++++++++++ os/hal/src/hal_serial.c | 289 +++++++++++++ os/hal/src/hal_serial_usb.c | 502 +++++++++++++++++++++ os/hal/src/hal_spi.c | 416 ++++++++++++++++++ os/hal/src/hal_st.c | 130 ++++++ os/hal/src/hal_uart.c | 515 ++++++++++++++++++++++ os/hal/src/hal_usb.c | 950 ++++++++++++++++++++++++++++++++++++++++ os/hal/src/hal_wdg.c | 120 ++++++ os/hal/src/i2c.c | 283 ------------ os/hal/src/i2s.c | 155 ------- os/hal/src/icu.c | 225 ---------- os/hal/src/mac.c | 268 ------------ os/hal/src/mmc_spi.c | 918 --------------------------------------- os/hal/src/pal.c | 122 ------ os/hal/src/pwm.c | 309 ------------- os/hal/src/rtc.c | 321 -------------- os/hal/src/sdc.c | 1005 ------------------------------------------- os/hal/src/serial.c | 289 ------------- os/hal/src/serial_usb.c | 502 --------------------- os/hal/src/spi.c | 416 ------------------ os/hal/src/st.c | 130 ------ os/hal/src/uart.c | 515 ---------------------- os/hal/src/usb.c | 950 ---------------------------------------- os/hal/src/wdg.c | 120 ------ 44 files changed, 8167 insertions(+), 8167 deletions(-) delete mode 100644 os/hal/src/adc.c delete mode 100644 os/hal/src/can.c delete mode 100644 os/hal/src/dac.c delete mode 100644 os/hal/src/ext.c delete mode 100644 os/hal/src/gpt.c delete mode 100644 os/hal/src/hal.c create mode 100644 os/hal/src/hal_adc.c create mode 100644 os/hal/src/hal_can.c create mode 100644 os/hal/src/hal_dac.c create mode 100644 os/hal/src/hal_ext.c create mode 100644 os/hal/src/hal_gpt.c create mode 100644 os/hal/src/hal_hal.c create mode 100644 os/hal/src/hal_i2c.c create mode 100644 os/hal/src/hal_i2s.c create mode 100644 os/hal/src/hal_icu.c create mode 100644 os/hal/src/hal_mac.c create mode 100644 os/hal/src/hal_mmc_spi.c create mode 100644 os/hal/src/hal_pal.c create mode 100644 os/hal/src/hal_pwm.c create mode 100644 os/hal/src/hal_rtc.c create mode 100644 os/hal/src/hal_sdc.c create mode 100644 os/hal/src/hal_serial.c create mode 100644 os/hal/src/hal_serial_usb.c create mode 100644 os/hal/src/hal_spi.c create mode 100644 os/hal/src/hal_st.c create mode 100644 os/hal/src/hal_uart.c create mode 100644 os/hal/src/hal_usb.c create mode 100644 os/hal/src/hal_wdg.c delete mode 100644 os/hal/src/i2c.c delete mode 100644 os/hal/src/i2s.c delete mode 100644 os/hal/src/icu.c delete mode 100644 os/hal/src/mac.c delete mode 100644 os/hal/src/mmc_spi.c delete mode 100644 os/hal/src/pal.c delete mode 100644 os/hal/src/pwm.c delete mode 100644 os/hal/src/rtc.c delete mode 100644 os/hal/src/sdc.c delete mode 100644 os/hal/src/serial.c delete mode 100644 os/hal/src/serial_usb.c delete mode 100644 os/hal/src/spi.c delete mode 100644 os/hal/src/st.c delete mode 100644 os/hal/src/uart.c delete mode 100644 os/hal/src/usb.c delete mode 100644 os/hal/src/wdg.c (limited to 'os/hal/src') diff --git a/os/hal/src/adc.c b/os/hal/src/adc.c deleted file mode 100644 index 9bfb1b0d0..000000000 --- a/os/hal/src/adc.c +++ /dev/null @@ -1,321 +0,0 @@ -/* - ChibiOS - Copyright (C) 2006..2016 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 adc.c - * @brief ADC Driver code. - * - * @addtogroup ADC - * @{ - */ - -#include "hal.h" - -#if (HAL_USE_ADC == TRUE) || defined(__DOXYGEN__) - -/*===========================================================================*/ -/* Driver local definitions. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver exported variables. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver local variables and types. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver local functions. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver exported functions. */ -/*===========================================================================*/ - -/** - * @brief ADC Driver initialization. - * @note This function is implicitly invoked by @p halInit(), there is - * no need to explicitly initialize the driver. - * - * @init - */ -void adcInit(void) { - - adc_lld_init(); -} - -/** - * @brief Initializes the standard part of a @p ADCDriver structure. - * - * @param[out] adcp pointer to the @p ADCDriver object - * - * @init - */ -void adcObjectInit(ADCDriver *adcp) { - - adcp->state = ADC_STOP; - adcp->config = NULL; - adcp->samples = NULL; - adcp->depth = 0; - adcp->grpp = NULL; -#if ADC_USE_WAIT == TRUE - adcp->thread = NULL; -#endif -#if ADC_USE_MUTUAL_EXCLUSION == TRUE - osalMutexObjectInit(&adcp->mutex); -#endif -#if defined(ADC_DRIVER_EXT_INIT_HOOK) - ADC_DRIVER_EXT_INIT_HOOK(adcp); -#endif -} - -/** - * @brief Configures and activates the ADC peripheral. - * - * @param[in] adcp pointer to the @p ADCDriver object - * @param[in] config pointer to the @p ADCConfig object. Depending on - * the implementation the value can be @p NULL. - * - * @api - */ -void adcStart(ADCDriver *adcp, const ADCConfig *config) { - - osalDbgCheck(adcp != NULL); - - osalSysLock(); - osalDbgAssert((adcp->state == ADC_STOP) || (adcp->state == ADC_READY), - "invalid state"); - adcp->config = config; - adc_lld_start(adcp); - adcp->state = ADC_READY; - osalSysUnlock(); -} - -/** - * @brief Deactivates the ADC peripheral. - * - * @param[in] adcp pointer to the @p ADCDriver object - * - * @api - */ -void adcStop(ADCDriver *adcp) { - - osalDbgCheck(adcp != NULL); - - osalSysLock(); - osalDbgAssert((adcp->state == ADC_STOP) || (adcp->state == ADC_READY), - "invalid state"); - adc_lld_stop(adcp); - adcp->state = ADC_STOP; - osalSysUnlock(); -} - -/** - * @brief Starts an ADC conversion. - * @details Starts an asynchronous conversion operation. - * @note The buffer is organized as a matrix of M*N elements where M is the - * channels number configured into the conversion group and N is the - * buffer depth. The samples are sequentially written into the buffer - * with no gaps. - * - * @param[in] adcp pointer to the @p ADCDriver object - * @param[in] grpp pointer to a @p ADCConversionGroup object - * @param[out] samples pointer to the samples buffer - * @param[in] depth buffer depth (matrix rows number). The buffer depth - * must be one or an even number. - * - * @api - */ -void adcStartConversion(ADCDriver *adcp, - const ADCConversionGroup *grpp, - adcsample_t *samples, - size_t depth) { - - osalSysLock(); - adcStartConversionI(adcp, grpp, samples, depth); - osalSysUnlock(); -} - -/** - * @brief Starts an ADC conversion. - * @details Starts an asynchronous conversion operation. - * @post The callbacks associated to the conversion group will be invoked - * on buffer fill and error events. - * @note The buffer is organized as a matrix of M*N elements where M is the - * channels number configured into the conversion group and N is the - * buffer depth. The samples are sequentially written into the buffer - * with no gaps. - * - * @param[in] adcp pointer to the @p ADCDriver object - * @param[in] grpp pointer to a @p ADCConversionGroup object - * @param[out] samples pointer to the samples buffer - * @param[in] depth buffer depth (matrix rows number). The buffer depth - * must be one or an even number. - * - * @iclass - */ -void adcStartConversionI(ADCDriver *adcp, - const ADCConversionGroup *grpp, - adcsample_t *samples, - size_t depth) { - - osalDbgCheckClassI(); - osalDbgCheck((adcp != NULL) && (grpp != NULL) && (samples != NULL) && - (depth > 0U) && ((depth == 1U) || ((depth & 1U) == 0U))); - osalDbgAssert((adcp->state == ADC_READY) || - (adcp->state == ADC_COMPLETE) || - (adcp->state == ADC_ERROR), - "not ready"); - - adcp->samples = samples; - adcp->depth = depth; - adcp->grpp = grpp; - adcp->state = ADC_ACTIVE; - adc_lld_start_conversion(adcp); -} - -/** - * @brief Stops an ongoing conversion. - * @details This function stops the currently ongoing conversion and returns - * the driver in the @p ADC_READY state. If there was no conversion - * being processed then the function does nothing. - * - * @param[in] adcp pointer to the @p ADCDriver object - * - * @api - */ -void adcStopConversion(ADCDriver *adcp) { - - osalDbgCheck(adcp != NULL); - - osalSysLock(); - osalDbgAssert((adcp->state == ADC_READY) || (adcp->state == ADC_ACTIVE), - "invalid state"); - if (adcp->state != ADC_READY) { - adc_lld_stop_conversion(adcp); - adcp->grpp = NULL; - adcp->state = ADC_READY; - _adc_reset_s(adcp); - } - osalSysUnlock(); -} - -/** - * @brief Stops an ongoing conversion. - * @details This function stops the currently ongoing conversion and returns - * the driver in the @p ADC_READY state. If there was no conversion - * being processed then the function does nothing. - * - * @param[in] adcp pointer to the @p ADCDriver object - * - * @iclass - */ -void adcStopConversionI(ADCDriver *adcp) { - - osalDbgCheckClassI(); - osalDbgCheck(adcp != NULL); - osalDbgAssert((adcp->state == ADC_READY) || - (adcp->state == ADC_ACTIVE) || - (adcp->state == ADC_COMPLETE), - "invalid state"); - - if (adcp->state != ADC_READY) { - adc_lld_stop_conversion(adcp); - adcp->grpp = NULL; - adcp->state = ADC_READY; - _adc_reset_i(adcp); - } -} - -#if (ADC_USE_WAIT == TRUE) || defined(__DOXYGEN__) -/** - * @brief Performs an ADC conversion. - * @details Performs a synchronous conversion operation. - * @note The buffer is organized as a matrix of M*N elements where M is the - * channels number configured into the conversion group and N is the - * buffer depth. The samples are sequentially written into the buffer - * with no gaps. - * - * @param[in] adcp pointer to the @p ADCDriver object - * @param[in] grpp pointer to a @p ADCConversionGroup object - * @param[out] samples pointer to the samples buffer - * @param[in] depth buffer depth (matrix rows number). The buffer depth - * must be one or an even number. - * @return The operation result. - * @retval MSG_OK Conversion finished. - * @retval MSG_RESET The conversion has been stopped using - * @p acdStopConversion() or @p acdStopConversionI(), - * the result buffer may contain incorrect data. - * @retval MSG_TIMEOUT The conversion has been stopped because an hardware - * error. - * - * @api - */ -msg_t adcConvert(ADCDriver *adcp, - const ADCConversionGroup *grpp, - adcsample_t *samples, - size_t depth) { - msg_t msg; - - osalSysLock(); - osalDbgAssert(adcp->thread == NULL, "already waiting"); - adcStartConversionI(adcp, grpp, samples, depth); - msg = osalThreadSuspendS(&adcp->thread); - osalSysUnlock(); - return msg; -} -#endif /* ADC_USE_WAIT == TRUE */ - -#if (ADC_USE_MUTUAL_EXCLUSION == TRUE) || defined(__DOXYGEN__) -/** - * @brief Gains exclusive access to the ADC peripheral. - * @details This function tries to gain ownership to the ADC bus, if the bus - * is already being used then the invoking thread is queued. - * @pre In order to use this function the option - * @p ADC_USE_MUTUAL_EXCLUSION must be enabled. - * - * @param[in] adcp pointer to the @p ADCDriver object - * - * @api - */ -void adcAcquireBus(ADCDriver *adcp) { - - osalDbgCheck(adcp != NULL); - - osalMutexLock(&adcp->mutex); -} - -/** - * @brief Releases exclusive access to the ADC peripheral. - * @pre In order to use this function the option - * @p ADC_USE_MUTUAL_EXCLUSION must be enabled. - * - * @param[in] adcp pointer to the @p ADCDriver object - * - * @api - */ -void adcReleaseBus(ADCDriver *adcp) { - - osalDbgCheck(adcp != NULL); - - osalMutexUnlock(&adcp->mutex); -} -#endif /* ADC_USE_MUTUAL_EXCLUSION == TRUE */ - -#endif /* HAL_USE_ADC == TRUE */ - -/** @} */ diff --git a/os/hal/src/can.c b/os/hal/src/can.c deleted file mode 100644 index eecfdb7ce..000000000 --- a/os/hal/src/can.c +++ /dev/null @@ -1,361 +0,0 @@ -/* - ChibiOS - Copyright (C) 2006..2016 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 can.c - * @brief CAN Driver code. - * - * @addtogroup CAN - * @{ - */ - -#include "hal.h" - -#if (HAL_USE_CAN == TRUE) || defined(__DOXYGEN__) - -/*===========================================================================*/ -/* Driver local definitions. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver exported variables. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver local variables and types. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver local functions. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver exported functions. */ -/*===========================================================================*/ - -/** - * @brief CAN Driver initialization. - * @note This function is implicitly invoked by @p halInit(), there is - * no need to explicitly initialize the driver. - * - * @init - */ -void canInit(void) { - - can_lld_init(); -} - -/** - * @brief Initializes the standard part of a @p CANDriver structure. - * - * @param[out] canp pointer to the @p CANDriver object - * - * @init - */ -void canObjectInit(CANDriver *canp) { - - canp->state = CAN_STOP; - canp->config = NULL; - osalThreadQueueObjectInit(&canp->txqueue); - osalThreadQueueObjectInit(&canp->rxqueue); - osalEventObjectInit(&canp->rxfull_event); - osalEventObjectInit(&canp->txempty_event); - osalEventObjectInit(&canp->error_event); -#if CAN_USE_SLEEP_MODE == TRUE - osalEventObjectInit(&canp->sleep_event); - osalEventObjectInit(&canp->wakeup_event); -#endif -} - -/** - * @brief Configures and activates the CAN peripheral. - * @note Activating the CAN bus can be a slow operation. - * @note Unlike other drivers it is not possible to restart the CAN - * driver without first stopping it using canStop(). - * - * @param[in] canp pointer to the @p CANDriver object - * @param[in] config pointer to the @p CANConfig object. Depending on - * the implementation the value can be @p NULL. - * - * @api - */ -void canStart(CANDriver *canp, const CANConfig *config) { - - osalDbgCheck(canp != NULL); - - osalSysLock(); - osalDbgAssert(canp->state == CAN_STOP, "invalid state"); - - /* Entering initialization mode. */ - canp->state = CAN_STARTING; - canp->config = config; - - /* Low level initialization, could be a slow process and sleeps could - be performed inside.*/ - can_lld_start(canp); - - /* The driver finally goes into the ready state.*/ - canp->state = CAN_READY; - osalSysUnlock(); -} - -/** - * @brief Deactivates the CAN peripheral. - * - * @param[in] canp pointer to the @p CANDriver object - * - * @api - */ -void canStop(CANDriver *canp) { - - osalDbgCheck(canp != NULL); - - osalSysLock(); - osalDbgAssert((canp->state == CAN_STOP) || (canp->state == CAN_READY), - "invalid state"); - - /* The low level driver is stopped.*/ - can_lld_stop(canp); - canp->state = CAN_STOP; - - /* Threads waiting on CAN APIs are notified that the driver has been - stopped in order to not have stuck threads.*/ - osalThreadDequeueAllI(&canp->rxqueue, MSG_RESET); - osalThreadDequeueAllI(&canp->txqueue, MSG_RESET); - osalOsRescheduleS(); - osalSysUnlock(); -} - -/** - * @brief Can frame transmission attempt. - * @details The specified frame is queued for transmission, if the hardware - * queue is full then the function fails. - * - * @param[in] canp pointer to the @p CANDriver object - * @param[in] mailbox mailbox number, @p CAN_ANY_MAILBOX for any mailbox - * @param[in] ctfp pointer to the CAN frame to be transmitted - * @return The operation result. - * @retval false Frame transmitted. - * @retval true Mailbox full. - * - * @iclass - */ -bool canTryTransmitI(CANDriver *canp, - canmbx_t mailbox, - const CANTxFrame *ctfp) { - - osalDbgCheckClassI(); - osalDbgCheck((canp != NULL) && (ctfp != NULL) && - (mailbox <= (canmbx_t)CAN_TX_MAILBOXES)); - osalDbgAssert((canp->state == CAN_READY) || (canp->state == CAN_SLEEP), - "invalid state"); - - /* If the RX mailbox is full then the function fails.*/ - if (!can_lld_is_tx_empty(canp, mailbox)) { - return true; - } - - /* Transmitting frame.*/ - can_lld_transmit(canp, mailbox, ctfp); - - return false; -} - -/** - * @brief Can frame receive attempt. - * @details The function tries to fetch a frame from a mailbox. - * - * @param[in] canp pointer to the @p CANDriver object - * @param[in] mailbox mailbox number, @p CAN_ANY_MAILBOX for any mailbox - * @param[out] crfp pointer to the buffer where the CAN frame is copied - * @return The operation result. - * @retval false Frame fetched. - * @retval true Mailbox empty. - * - * @iclass - */ -bool canTryReceiveI(CANDriver *canp, - canmbx_t mailbox, - CANRxFrame *crfp) { - - osalDbgCheckClassI(); - osalDbgCheck((canp != NULL) && (crfp != NULL) && - (mailbox <= (canmbx_t)CAN_RX_MAILBOXES)); - osalDbgAssert((canp->state == CAN_READY) || (canp->state == CAN_SLEEP), - "invalid state"); - - /* If the RX mailbox is empty then the function fails.*/ - if (!can_lld_is_rx_nonempty(canp, mailbox)) { - return true; - } - - /* Fetching the frame.*/ - can_lld_receive(canp, mailbox, crfp); - - return false; -} - -/** - * @brief Can frame transmission. - * @details The specified frame is queued for transmission, if the hardware - * queue is full then the invoking thread is queued. - * @note Trying to transmit while in sleep mode simply enqueues the thread. - * - * @param[in] canp pointer to the @p CANDriver object - * @param[in] mailbox mailbox number, @p CAN_ANY_MAILBOX for any mailbox - * @param[in] ctfp pointer to the CAN frame to be transmitted - * @param[in] timeout the number of ticks before the operation timeouts, - * the following special values are allowed: - * - @a TIME_IMMEDIATE immediate timeout. - * - @a TIME_INFINITE no timeout. - * . - * @return The operation result. - * @retval MSG_OK the frame has been queued for transmission. - * @retval MSG_TIMEOUT The operation has timed out. - * @retval MSG_RESET The driver has been stopped while waiting. - * - * @api - */ -msg_t canTransmit(CANDriver *canp, - canmbx_t mailbox, - const CANTxFrame *ctfp, - systime_t timeout) { - - osalDbgCheck((canp != NULL) && (ctfp != NULL) && - (mailbox <= (canmbx_t)CAN_TX_MAILBOXES)); - - osalSysLock(); - osalDbgAssert((canp->state == CAN_READY) || (canp->state == CAN_SLEEP), - "invalid state"); - - /*lint -save -e9007 [13.5] Right side is supposed to be pure.*/ - while ((canp->state == CAN_SLEEP) || !can_lld_is_tx_empty(canp, mailbox)) { - /*lint -restore*/ - msg_t msg = osalThreadEnqueueTimeoutS(&canp->txqueue, timeout); - if (msg != MSG_OK) { - osalSysUnlock(); - return msg; - } - } - can_lld_transmit(canp, mailbox, ctfp); - osalSysUnlock(); - return MSG_OK; -} - -/** - * @brief Can frame receive. - * @details The function waits until a frame is received. - * @note Trying to receive while in sleep mode simply enqueues the thread. - * - * @param[in] canp pointer to the @p CANDriver object - * @param[in] mailbox mailbox number, @p CAN_ANY_MAILBOX for any mailbox - * @param[out] crfp pointer to the buffer where the CAN frame is copied - * @param[in] timeout the number of ticks before the operation timeouts, - * the following special values are allowed: - * - @a TIME_IMMEDIATE immediate timeout (useful in an - * event driven scenario where a thread never blocks - * for I/O). - * - @a TIME_INFINITE no timeout. - * . - * @return The operation result. - * @retval MSG_OK a frame has been received and placed in the buffer. - * @retval MSG_TIMEOUT The operation has timed out. - * @retval MSG_RESET The driver has been stopped while waiting. - * - * @api - */ -msg_t canReceive(CANDriver *canp, - canmbx_t mailbox, - CANRxFrame *crfp, - systime_t timeout) { - - osalDbgCheck((canp != NULL) && (crfp != NULL) && - (mailbox <= (canmbx_t)CAN_RX_MAILBOXES)); - - osalSysLock(); - osalDbgAssert((canp->state == CAN_READY) || (canp->state == CAN_SLEEP), - "invalid state"); - - /*lint -save -e9007 [13.5] Right side is supposed to be pure.*/ - while ((canp->state == CAN_SLEEP) || !can_lld_is_rx_nonempty(canp, mailbox)) { - /*lint -restore*/ - msg_t msg = osalThreadEnqueueTimeoutS(&canp->rxqueue, timeout); - if (msg != MSG_OK) { - osalSysUnlock(); - return msg; - } - } - can_lld_receive(canp, mailbox, crfp); - osalSysUnlock(); - return MSG_OK; -} - -#if (CAN_USE_SLEEP_MODE == TRUE) || defined(__DOXYGEN__) -/** - * @brief Enters the sleep mode. - * @details This function puts the CAN driver in sleep mode and broadcasts - * the @p sleep_event event source. - * @pre In order to use this function the option @p CAN_USE_SLEEP_MODE must - * be enabled and the @p CAN_SUPPORTS_SLEEP mode must be supported - * by the low level driver. - * - * @param[in] canp pointer to the @p CANDriver object - * - * @api - */ -void canSleep(CANDriver *canp) { - - osalDbgCheck(canp != NULL); - - osalSysLock(); - osalDbgAssert((canp->state == CAN_READY) || (canp->state == CAN_SLEEP), - "invalid state"); - if (canp->state == CAN_READY) { - can_lld_sleep(canp); - canp->state = CAN_SLEEP; - osalEventBroadcastFlagsI(&canp->sleep_event, (eventflags_t)0); - osalOsRescheduleS(); - } - osalSysUnlock(); -} - -/** - * @brief Enforces leaving the sleep mode. - * @note The sleep mode is supposed to be usually exited automatically by - * an hardware event. - * - * @param[in] canp pointer to the @p CANDriver object - */ -void canWakeup(CANDriver *canp) { - - osalDbgCheck(canp != NULL); - - osalSysLock(); - osalDbgAssert((canp->state == CAN_READY) || (canp->state == CAN_SLEEP), - "invalid state"); - if (canp->state == CAN_SLEEP) { - can_lld_wakeup(canp); - canp->state = CAN_READY; - osalEventBroadcastFlagsI(&canp->wakeup_event, (eventflags_t)0); - osalOsRescheduleS(); - } - osalSysUnlock(); -} -#endif /* CAN_USE_SLEEP_MODE == TRUE */ - -#endif /* HAL_USE_CAN == TRUE */ - -/** @} */ diff --git a/os/hal/src/dac.c b/os/hal/src/dac.c deleted file mode 100644 index 0feb4308f..000000000 --- a/os/hal/src/dac.c +++ /dev/null @@ -1,349 +0,0 @@ -/* - ChibiOS - Copyright (C) 2006..2016 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 dac.c - * @brief DAC Driver code. - * - * @addtogroup DAC - * @{ - */ - -#include "hal.h" - -#if (HAL_USE_DAC == TRUE) || defined(__DOXYGEN__) - -/*===========================================================================*/ -/* Driver local definitions. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver exported variables. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver local variables. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver local functions. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver exported functions. */ -/*===========================================================================*/ - -/** - * @brief DAC Driver initialization. - * @note This function is implicitly invoked by @p halInit(), there is - * no need to explicitly initialize the driver. - * - * @init - */ -void dacInit(void) { - - dac_lld_init(); -} - -/** - * @brief Initializes the standard part of a @p DACDriver structure. - * - * @param[out] dacp pointer to the @p DACDriver object - * - * @init - */ -void dacObjectInit(DACDriver *dacp) { - - dacp->state = DAC_STOP; - dacp->config = NULL; -#if DAC_USE_WAIT - dacp->thread = NULL; -#endif -#if DAC_USE_MUTUAL_EXCLUSION - osalMutexObjectInit(&dacp->mutex); -#endif -#if defined(DAC_DRIVER_EXT_INIT_HOOK) - DAC_DRIVER_EXT_INIT_HOOK(dacp); -#endif -} - -/** - * @brief Configures and activates the DAC peripheral. - * - * @param[in] dacp pointer to the @p DACDriver object - * @param[in] config pointer to the @p DACConfig object, it can be - * @p NULL if the low level driver implementation - * supports a default configuration - * - * @api - */ -void dacStart(DACDriver *dacp, const DACConfig *config) { - - osalDbgCheck(dacp != NULL); - - osalSysLock(); - - osalDbgAssert((dacp->state == DAC_STOP) || (dacp->state == DAC_READY), - "invalid state"); - - dacp->config = config; - dac_lld_start(dacp); - dacp->state = DAC_READY; - - osalSysUnlock(); -} - -/** - * @brief Deactivates the DAC peripheral. - * @note Deactivating the peripheral also enforces a release of the slave - * select line. - * - * @param[in] dacp pointer to the @p DACDriver object - * - * @api - */ -void dacStop(DACDriver *dacp) { - - osalDbgCheck(dacp != NULL); - - osalSysLock(); - - osalDbgAssert((dacp->state == DAC_STOP) || (dacp->state == DAC_READY), - "invalid state"); - - dac_lld_stop(dacp); - dacp->state = DAC_STOP; - - osalSysUnlock(); -} - -/** - * @brief Outputs a value directly on a DAC channel. - * - * @param[in] dacp pointer to the @p DACDriver object - * @param[in] channel DAC channel number - * @param[in] sample value to be output - * - * @xclass - */ -void dacPutChannelX(DACDriver *dacp, dacchannel_t channel, dacsample_t sample) { - - osalDbgCheck(channel < DAC_MAX_CHANNELS); - osalDbgAssert(dacp->state == DAC_READY, "invalid state"); - - dac_lld_put_channel(dacp, channel, sample); -} - -/** - * @brief Starts a DAC conversion. - * @details Starts an asynchronous conversion operation. - * @note The buffer is organized as a matrix of M*N elements where M is the - * channels number configured into the conversion group and N is the - * buffer depth. The samples are sequentially written into the buffer - * with no gaps. - * - * @param[in] dacp pointer to the @p DACDriver object - * @param[in] grpp pointer to a @p DACConversionGroup object - * @param[in] samples pointer to the samples buffer - * @param[in] depth buffer depth (matrix rows number). The buffer depth - * must be one or an even number. - * - * @api - */ -void dacStartConversion(DACDriver *dacp, - const DACConversionGroup *grpp, - const dacsample_t *samples, - size_t depth) { - - osalSysLock(); - dacStartConversionI(dacp, grpp, samples, depth); - osalSysUnlock(); -} - -/** - * @brief Starts a DAC conversion. - * @details Starts an asynchronous conversion operation. - * @post The callbacks associated to the conversion group will be invoked - * on buffer fill and error events. - * @note The buffer is organized as a matrix of M*N elements where M is the - * channels number configured into the conversion group and N is the - * buffer depth. The samples are sequentially written into the buffer - * with no gaps. - * - * @param[in] dacp pointer to the @p DACDriver object - * @param[in] grpp pointer to a @p DACConversionGroup object - * @param[in] samples pointer to the samples buffer - * @param[in] depth buffer depth (matrix rows number). The buffer depth - * must be one or an even number. - * - * @iclass - */ -void dacStartConversionI(DACDriver *dacp, - const DACConversionGroup *grpp, - const dacsample_t *samples, - size_t depth) { - - osalDbgCheckClassI(); - osalDbgCheck((dacp != NULL) && (grpp != NULL) && (samples != NULL) && - ((depth == 1) || ((depth & 1) == 0))); - osalDbgAssert((dacp->state == DAC_READY) || - (dacp->state == DAC_COMPLETE) || - (dacp->state == DAC_ERROR), - "not ready"); - - dacp->samples = samples; - dacp->depth = depth; - dacp->grpp = grpp; - dacp->state = DAC_ACTIVE; - dac_lld_start_conversion(dacp); -} - -/** - * @brief Stops an ongoing conversion. - * @details This function stops the currently ongoing conversion and returns - * the driver in the @p DAC_READY state. If there was no conversion - * being processed then the function does nothing. - * - * @param[in] dacp pointer to the @p DACDriver object - * - * @api - */ -void dacStopConversion(DACDriver *dacp) { - - osalDbgCheck(dacp != NULL); - - osalSysLock(); - - osalDbgAssert((dacp->state == DAC_READY) || - (dacp->state == DAC_ACTIVE), - "invalid state"); - - if (dacp->state != DAC_READY) { - dac_lld_stop_conversion(dacp); - dacp->grpp = NULL; - dacp->state = DAC_READY; - _dac_reset_s(dacp); - } - - osalSysUnlock(); -} - -/** - * @brief Stops an ongoing conversion. - * @details This function stops the currently ongoing conversion and returns - * the driver in the @p DAC_READY state. If there was no conversion - * being processed then the function does nothing. - * - * @param[in] dacp pointer to the @p DACDriver object - * - * @iclass - */ -void dacStopConversionI(DACDriver *dacp) { - - osalDbgCheckClassI(); - osalDbgCheck(dacp != NULL); - osalDbgAssert((dacp->state == DAC_READY) || - (dacp->state == DAC_ACTIVE) || - (dacp->state == DAC_COMPLETE), - "invalid state"); - - if (dacp->state != DAC_READY) { - dac_lld_stop_conversion(dacp); - dacp->grpp = NULL; - dacp->state = DAC_READY; - _dac_reset_i(dacp); - } -} - -#if (DAC_USE_WAIT == TRUE) || defined(__DOXYGEN__) -/** - * @brief Performs a DAC conversion. - * @details Performs a synchronous conversion operation. - * @note The buffer is organized as a matrix of M*N elements where M is the - * channels number configured into the conversion group and N is the - * buffer depth. The samples are sequentially written into the buffer - * with no gaps. - * - * @param[in] dacp pointer to the @p DACDriver object - * @param[in] grpp pointer to a @p DACConversionGroup object - * @param[out] samples pointer to the samples buffer - * @param[in] depth buffer depth (matrix rows number). The buffer depth - * must be one or an even number. - * @return The operation result. - * @retval MSG_OK Conversion finished. - * @retval MSG_RESET The conversion has been stopped using - * @p acdStopConversion() or @p acdStopConversionI(), - * the result buffer may contain incorrect data. - * @retval MSG_TIMEOUT The conversion has been stopped because an hardware - * error. - * - * @api - */ -msg_t dacConvert(DACDriver *dacp, - const DACConversionGroup *grpp, - const dacsample_t *samples, - size_t depth) { - msg_t msg; - - osalSysLock(); - - dacStartConversionI(dacp, grpp, samples, depth); - msg = osalThreadSuspendS(&dacp->thread); - - osalSysUnlock(); - return msg; -} -#endif /* DAC_USE_WAIT == TRUE */ - -#if (DAC_USE_MUTUAL_EXCLUSION == TRUE) || defined(__DOXYGEN__) -/** - * @brief Gains exclusive access to the DAC bus. - * @details This function tries to gain ownership to the DAC bus, if the bus - * is already being used then the invoking thread is queued. - * @pre In order to use this function the option @p DAC_USE_MUTUAL_EXCLUSION - * must be enabled. - * - * @param[in] dacp pointer to the @p DACDriver object - * - * @api - */ -void dacAcquireBus(DACDriver *dacp) { - - osalDbgCheck(dacp != NULL); - - osalMutexLock(&dacp->mutex); -} - -/** - * @brief Releases exclusive access to the DAC bus. - * @pre In order to use this function the option @p DAC_USE_MUTUAL_EXCLUSION - * must be enabled. - * - * @param[in] dacp pointer to the @p DACDriver object - * - * @api - */ -void dacReleaseBus(DACDriver *dacp) { - - osalDbgCheck(dacp != NULL); - - osalMutexUnlock(&dacp->mutex); -} -#endif /* DAC_USE_MUTUAL_EXCLUSION == TRUE */ - -#endif /* HAL_USE_DAC == TRUE */ - -/** @} */ diff --git a/os/hal/src/ext.c b/os/hal/src/ext.c deleted file mode 100644 index fa25e41a4..000000000 --- a/os/hal/src/ext.c +++ /dev/null @@ -1,202 +0,0 @@ -/* - ChibiOS - Copyright (C) 2006..2016 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 ext.c - * @brief EXT Driver code. - * - * @addtogroup EXT - * @{ - */ - -#include "hal.h" - -#if (HAL_USE_EXT == TRUE) || defined(__DOXYGEN__) - -/*===========================================================================*/ -/* Driver local definitions. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver exported variables. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver local variables and types. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver local functions. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver exported functions. */ -/*===========================================================================*/ - -/** - * @brief EXT Driver initialization. - * @note This function is implicitly invoked by @p halInit(), there is - * no need to explicitly initialize the driver. - * - * @init - */ -void extInit(void) { - - ext_lld_init(); -} - -/** - * @brief Initializes the standard part of a @p EXTDriver structure. - * - * @param[out] extp pointer to the @p EXTDriver object - * - * @init - */ -void extObjectInit(EXTDriver *extp) { - - extp->state = EXT_STOP; - extp->config = NULL; -} - -/** - * @brief Configures and activates the EXT peripheral. - * @post After activation all EXT channels are in the disabled state, - * use @p extChannelEnable() in order to activate them. - * - * @param[in] extp pointer to the @p EXTDriver object - * @param[in] config pointer to the @p EXTConfig object - * - * @api - */ -void extStart(EXTDriver *extp, const EXTConfig *config) { - - osalDbgCheck((extp != NULL) && (config != NULL)); - - osalSysLock(); - osalDbgAssert((extp->state == EXT_STOP) || (extp->state == EXT_ACTIVE), - "invalid state"); - extp->config = config; - ext_lld_start(extp); - extp->state = EXT_ACTIVE; - osalSysUnlock(); -} - -/** - * @brief Deactivates the EXT peripheral. - * - * @param[in] extp pointer to the @p EXTDriver object - * - * @api - */ -void extStop(EXTDriver *extp) { - - osalDbgCheck(extp != NULL); - - osalSysLock(); - osalDbgAssert((extp->state == EXT_STOP) || (extp->state == EXT_ACTIVE), - "invalid state"); - ext_lld_stop(extp); - extp->state = EXT_STOP; - osalSysUnlock(); -} - -/** - * @brief Enables an EXT channel. - * @pre The channel must not be in @p EXT_CH_MODE_DISABLED mode. - * - * @param[in] extp pointer to the @p EXTDriver object - * @param[in] channel channel to be enabled - * - * @api - */ -void extChannelEnable(EXTDriver *extp, expchannel_t channel) { - - osalDbgCheck((extp != NULL) && (channel < (expchannel_t)EXT_MAX_CHANNELS)); - - osalSysLock(); - osalDbgAssert((extp->state == EXT_ACTIVE) && - ((extp->config->channels[channel].mode & - EXT_CH_MODE_EDGES_MASK) != EXT_CH_MODE_DISABLED), - "invalid state"); - extChannelEnableI(extp, channel); - osalSysUnlock(); -} - -/** - * @brief Disables an EXT channel. - * @pre The channel must not be in @p EXT_CH_MODE_DISABLED mode. - * - * @param[in] extp pointer to the @p EXTDriver object - * @param[in] channel channel to be disabled - * - * @api - */ -void extChannelDisable(EXTDriver *extp, expchannel_t channel) { - - osalDbgCheck((extp != NULL) && (channel < (expchannel_t)EXT_MAX_CHANNELS)); - - osalSysLock(); - osalDbgAssert((extp->state == EXT_ACTIVE) && - ((extp->config->channels[channel].mode & - EXT_CH_MODE_EDGES_MASK) != EXT_CH_MODE_DISABLED), - "invalid state"); - extChannelDisableI(extp, channel); - osalSysUnlock(); -} - -/** - * @brief Changes the operation mode of a channel. - * @note This function attempts to write over the current configuration - * structure that must have been not declared constant. This - * violates the @p const qualifier in @p extStart() but it is - * intentional. - * @note This function cannot be used if the configuration structure is - * declared @p const. - * @note The effect of this function on constant configuration structures - * is not defined. - * - * @param[in] extp pointer to the @p EXTDriver object - * @param[in] channel channel to be changed - * @param[in] extcp new configuration for the channel - * - * @iclass - */ -void extSetChannelModeI(EXTDriver *extp, - expchannel_t channel, - const EXTChannelConfig *extcp) { - EXTChannelConfig *oldcp; - - osalDbgCheck((extp != NULL) && - (channel < (expchannel_t)EXT_MAX_CHANNELS) && - (extcp != NULL)); - - osalDbgAssert(extp->state == EXT_ACTIVE, "invalid state"); - - /* Note that here the access is enforced as non-const, known access - violation.*/ - /*lint -save -e9005 [11.8] Known issue, the driver needs rework here.*/ - oldcp = (EXTChannelConfig *)&extp->config->channels[channel]; - /*lint -restore*/ - - /* Overwriting the old channels configuration then the channel is - reconfigured by the low level driver.*/ - *oldcp = *extcp; - ext_lld_channel_enable(extp, channel); -} - -#endif /* HAL_USE_EXT == TRUE */ - -/** @} */ diff --git a/os/hal/src/gpt.c b/os/hal/src/gpt.c deleted file mode 100644 index b83ffa1c1..000000000 --- a/os/hal/src/gpt.c +++ /dev/null @@ -1,262 +0,0 @@ -/* - ChibiOS - Copyright (C) 2006..2016 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 gpt.c - * @brief GPT Driver code. - * - * @addtogroup GPT - * @{ - */ - -#include "hal.h" - -#if (HAL_USE_GPT == TRUE) || defined(__DOXYGEN__) - -/*===========================================================================*/ -/* Driver local definitions. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver exported variables. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver local variables and types. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver local functions. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver exported functions. */ -/*===========================================================================*/ - -/** - * @brief GPT Driver initialization. - * @note This function is implicitly invoked by @p halInit(), there is - * no need to explicitly initialize the driver. - * - * @init - */ -void gptInit(void) { - - gpt_lld_init(); -} - -/** - * @brief Initializes the standard part of a @p GPTDriver structure. - * - * @param[out] gptp pointer to the @p GPTDriver object - * - * @init - */ -void gptObjectInit(GPTDriver *gptp) { - - gptp->state = GPT_STOP; - gptp->config = NULL; -} - -/** - * @brief Configures and activates the GPT peripheral. - * - * @param[in] gptp pointer to the @p GPTDriver object - * @param[in] config pointer to the @p GPTConfig object - * - * @api - */ -void gptStart(GPTDriver *gptp, const GPTConfig *config) { - - osalDbgCheck((gptp != NULL) && (config != NULL)); - - osalSysLock(); - osalDbgAssert((gptp->state == GPT_STOP) || (gptp->state == GPT_READY), - "invalid state"); - gptp->config = config; - gpt_lld_start(gptp); - gptp->state = GPT_READY; - osalSysUnlock(); -} - -/** - * @brief Deactivates the GPT peripheral. - * - * @param[in] gptp pointer to the @p GPTDriver object - * - * @api - */ -void gptStop(GPTDriver *gptp) { - - osalDbgCheck(gptp != NULL); - - osalSysLock(); - osalDbgAssert((gptp->state == GPT_STOP) || (gptp->state == GPT_READY), - "invalid state"); - gpt_lld_stop(gptp); - gptp->state = GPT_STOP; - osalSysUnlock(); -} - -/** - * @brief Changes the interval of GPT peripheral. - * @details This function changes the interval of a running GPT unit. - * @pre The GPT unit must be running in continuous mode. - * @post The GPT unit interval is changed to the new value. - * - * @param[in] gptp pointer to a @p GPTDriver object - * @param[in] interval new cycle time in timer ticks - * - * @api - */ -void gptChangeInterval(GPTDriver *gptp, gptcnt_t interval) { - - osalDbgCheck(gptp != NULL); - - osalSysLock(); - osalDbgAssert(gptp->state == GPT_CONTINUOUS, - "invalid state"); - gptChangeIntervalI(gptp, interval); - osalSysUnlock(); -} - -/** - * @brief Starts the timer in continuous mode. - * - * @param[in] gptp pointer to the @p GPTDriver object - * @param[in] interval period in ticks - * - * @api - */ -void gptStartContinuous(GPTDriver *gptp, gptcnt_t interval) { - - osalSysLock(); - gptStartContinuousI(gptp, interval); - osalSysUnlock(); -} - -/** - * @brief Starts the timer in continuous mode. - * - * @param[in] gptp pointer to the @p GPTDriver object - * @param[in] interval period in ticks - * - * @iclass - */ -void gptStartContinuousI(GPTDriver *gptp, gptcnt_t interval) { - - osalDbgCheckClassI(); - osalDbgCheck(gptp != NULL); - osalDbgAssert(gptp->state == GPT_READY, - "invalid state"); - - gptp->state = GPT_CONTINUOUS; - gpt_lld_start_timer(gptp, interval); -} - -/** - * @brief Starts the timer in one shot mode. - * - * @param[in] gptp pointer to the @p GPTDriver object - * @param[in] interval time interval in ticks - * - * @api - */ -void gptStartOneShot(GPTDriver *gptp, gptcnt_t interval) { - - osalSysLock(); - gptStartOneShotI(gptp, interval); - osalSysUnlock(); -} - -/** - * @brief Starts the timer in one shot mode. - * - * @param[in] gptp pointer to the @p GPTDriver object - * @param[in] interval time interval in ticks - * - * @api - */ -void gptStartOneShotI(GPTDriver *gptp, gptcnt_t interval) { - - osalDbgCheckClassI(); - osalDbgCheck(gptp != NULL); - osalDbgCheck(gptp->config->callback != NULL); - osalDbgAssert(gptp->state == GPT_READY, - "invalid state"); - - gptp->state = GPT_ONESHOT; - gpt_lld_start_timer(gptp, interval); -} - -/** - * @brief Stops the timer. - * - * @param[in] gptp pointer to the @p GPTDriver object - * - * @api - */ -void gptStopTimer(GPTDriver *gptp) { - - osalSysLock(); - gptStopTimerI(gptp); - osalSysUnlock(); -} - -/** - * @brief Stops the timer. - * - * @param[in] gptp pointer to the @p GPTDriver object - * - * @api - */ -void gptStopTimerI(GPTDriver *gptp) { - - osalDbgCheckClassI(); - osalDbgCheck(gptp != NULL); - osalDbgAssert((gptp->state == GPT_READY) || (gptp->state == GPT_CONTINUOUS) || - (gptp->state == GPT_ONESHOT), - "invalid state"); - - gptp->state = GPT_READY; - gpt_lld_stop_timer(gptp); -} - -/** - * @brief Starts the timer in one shot mode and waits for completion. - * @details This function specifically polls the timer waiting for completion - * in order to not have extra delays caused by interrupt servicing, - * this function is only recommended for short delays. - * @note The configured callback is not invoked when using this function. - * - * @param[in] gptp pointer to the @p GPTDriver object - * @param[in] interval time interval in ticks - * - * @api - */ -void gptPolledDelay(GPTDriver *gptp, gptcnt_t interval) { - - osalDbgAssert(gptp->state == GPT_READY, - "invalid state"); - - gptp->state = GPT_ONESHOT; - gpt_lld_polled_delay(gptp, interval); - gptp->state = GPT_READY; -} - -#endif /* HAL_USE_GPT == TRUE */ - -/** @} */ diff --git a/os/hal/src/hal.c b/os/hal/src/hal.c deleted file mode 100644 index 04cd0b2c5..000000000 --- a/os/hal/src/hal.c +++ /dev/null @@ -1,144 +0,0 @@ -/* - ChibiOS - Copyright (C) 2006..2016 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.c - * @brief HAL subsystem code. - * - * @addtogroup HAL - * @{ - */ - -#include "hal.h" - -/*===========================================================================*/ -/* Driver local definitions. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver exported variables. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver local variables and types. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver local functions. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver exported functions. */ -/*===========================================================================*/ - -/** - * @brief HAL initialization. - * @details This function invokes the low level initialization code then - * initializes all the drivers enabled in the HAL. Finally the - * board-specific initialization is performed by invoking - * @p boardInit() (usually defined in @p board.c). - * - * @init - */ -void halInit(void) { - - /* Initializes the OS Abstraction Layer.*/ - osalInit(); - - /* Platform low level initializations.*/ - hal_lld_init(); - -#if (HAL_USE_PAL == TRUE) || defined(__DOXYGEN__) - palInit(&pal_default_config); -#endif -#if (HAL_USE_ADC == TRUE) || defined(__DOXYGEN__) - adcInit(); -#endif -#if (HAL_USE_CAN == TRUE) || defined(__DOXYGEN__) - canInit(); -#endif -#if (HAL_USE_DAC == TRUE) || defined(__DOXYGEN__) - dacInit(); -#endif -#if (HAL_USE_EXT == TRUE) || defined(__DOXYGEN__) - extInit(); -#endif -#if (HAL_USE_GPT == TRUE) || defined(__DOXYGEN__) - gptInit(); -#endif -#if (HAL_USE_I2C == TRUE) || defined(__DOXYGEN__) - i2cInit(); -#endif -#if (HAL_USE_I2S == TRUE) || defined(__DOXYGEN__) - i2sInit(); -#endif -#if (HAL_USE_ICU == TRUE) || defined(__DOXYGEN__) - icuInit(); -#endif -#if (HAL_USE_MAC == TRUE) || defined(__DOXYGEN__) - macInit(); -#endif -#if (HAL_USE_PWM == TRUE) || defined(__DOXYGEN__) - pwmInit(); -#endif -#if (HAL_USE_SERIAL == TRUE) || defined(__DOXYGEN__) - sdInit(); -#endif -#if (HAL_USE_SDC == TRUE) || defined(__DOXYGEN__) - sdcInit(); -#endif -#if (HAL_USE_SPI == TRUE) || defined(__DOXYGEN__) - spiInit(); -#endif -#if (HAL_USE_UART == TRUE) || defined(__DOXYGEN__) - uartInit(); -#endif -#if (HAL_USE_USB == TRUE) || defined(__DOXYGEN__) - usbInit(); -#endif -#if (HAL_USE_MMC_SPI == TRUE) || defined(__DOXYGEN__) - mmcInit(); -#endif -#if (HAL_USE_SERIAL_USB == TRUE) || defined(__DOXYGEN__) - sduInit(); -#endif -#if (HAL_USE_RTC == TRUE) || defined(__DOXYGEN__) - rtcInit(); -#endif -#if (HAL_USE_WDG == TRUE) || defined(__DOXYGEN__) - wdgInit(); -#endif - - /* Community driver overlay initialization.*/ -#if defined(HAL_USE_COMMUNITY) || defined(__DOXYGEN__) -#if (HAL_USE_COMMUNITY == TRUE) || defined(__DOXYGEN__) - halCommunityInit(); -#endif -#endif - - /* Board specific initialization.*/ - boardInit(); - -/* - * The ST driver is a special case, it is only initialized if the OSAL is - * configured to require it. - */ -#if OSAL_ST_MODE != OSAL_ST_MODE_NONE - stInit(); -#endif -} - -/** @} */ diff --git a/os/hal/src/hal_adc.c b/os/hal/src/hal_adc.c new file mode 100644 index 000000000..9bfb1b0d0 --- /dev/null +++ b/os/hal/src/hal_adc.c @@ -0,0 +1,321 @@ +/* + ChibiOS - Copyright (C) 2006..2016 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 adc.c + * @brief ADC Driver code. + * + * @addtogroup ADC + * @{ + */ + +#include "hal.h" + +#if (HAL_USE_ADC == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief ADC Driver initialization. + * @note This function is implicitly invoked by @p halInit(), there is + * no need to explicitly initialize the driver. + * + * @init + */ +void adcInit(void) { + + adc_lld_init(); +} + +/** + * @brief Initializes the standard part of a @p ADCDriver structure. + * + * @param[out] adcp pointer to the @p ADCDriver object + * + * @init + */ +void adcObjectInit(ADCDriver *adcp) { + + adcp->state = ADC_STOP; + adcp->config = NULL; + adcp->samples = NULL; + adcp->depth = 0; + adcp->grpp = NULL; +#if ADC_USE_WAIT == TRUE + adcp->thread = NULL; +#endif +#if ADC_USE_MUTUAL_EXCLUSION == TRUE + osalMutexObjectInit(&adcp->mutex); +#endif +#if defined(ADC_DRIVER_EXT_INIT_HOOK) + ADC_DRIVER_EXT_INIT_HOOK(adcp); +#endif +} + +/** + * @brief Configures and activates the ADC peripheral. + * + * @param[in] adcp pointer to the @p ADCDriver object + * @param[in] config pointer to the @p ADCConfig object. Depending on + * the implementation the value can be @p NULL. + * + * @api + */ +void adcStart(ADCDriver *adcp, const ADCConfig *config) { + + osalDbgCheck(adcp != NULL); + + osalSysLock(); + osalDbgAssert((adcp->state == ADC_STOP) || (adcp->state == ADC_READY), + "invalid state"); + adcp->config = config; + adc_lld_start(adcp); + adcp->state = ADC_READY; + osalSysUnlock(); +} + +/** + * @brief Deactivates the ADC peripheral. + * + * @param[in] adcp pointer to the @p ADCDriver object + * + * @api + */ +void adcStop(ADCDriver *adcp) { + + osalDbgCheck(adcp != NULL); + + osalSysLock(); + osalDbgAssert((adcp->state == ADC_STOP) || (adcp->state == ADC_READY), + "invalid state"); + adc_lld_stop(adcp); + adcp->state = ADC_STOP; + osalSysUnlock(); +} + +/** + * @brief Starts an ADC conversion. + * @details Starts an asynchronous conversion operation. + * @note The buffer is organized as a matrix of M*N elements where M is the + * channels number configured into the conversion group and N is the + * buffer depth. The samples are sequentially written into the buffer + * with no gaps. + * + * @param[in] adcp pointer to the @p ADCDriver object + * @param[in] grpp pointer to a @p ADCConversionGroup object + * @param[out] samples pointer to the samples buffer + * @param[in] depth buffer depth (matrix rows number). The buffer depth + * must be one or an even number. + * + * @api + */ +void adcStartConversion(ADCDriver *adcp, + const ADCConversionGroup *grpp, + adcsample_t *samples, + size_t depth) { + + osalSysLock(); + adcStartConversionI(adcp, grpp, samples, depth); + osalSysUnlock(); +} + +/** + * @brief Starts an ADC conversion. + * @details Starts an asynchronous conversion operation. + * @post The callbacks associated to the conversion group will be invoked + * on buffer fill and error events. + * @note The buffer is organized as a matrix of M*N elements where M is the + * channels number configured into the conversion group and N is the + * buffer depth. The samples are sequentially written into the buffer + * with no gaps. + * + * @param[in] adcp pointer to the @p ADCDriver object + * @param[in] grpp pointer to a @p ADCConversionGroup object + * @param[out] samples pointer to the samples buffer + * @param[in] depth buffer depth (matrix rows number). The buffer depth + * must be one or an even number. + * + * @iclass + */ +void adcStartConversionI(ADCDriver *adcp, + const ADCConversionGroup *grpp, + adcsample_t *samples, + size_t depth) { + + osalDbgCheckClassI(); + osalDbgCheck((adcp != NULL) && (grpp != NULL) && (samples != NULL) && + (depth > 0U) && ((depth == 1U) || ((depth & 1U) == 0U))); + osalDbgAssert((adcp->state == ADC_READY) || + (adcp->state == ADC_COMPLETE) || + (adcp->state == ADC_ERROR), + "not ready"); + + adcp->samples = samples; + adcp->depth = depth; + adcp->grpp = grpp; + adcp->state = ADC_ACTIVE; + adc_lld_start_conversion(adcp); +} + +/** + * @brief Stops an ongoing conversion. + * @details This function stops the currently ongoing conversion and returns + * the driver in the @p ADC_READY state. If there was no conversion + * being processed then the function does nothing. + * + * @param[in] adcp pointer to the @p ADCDriver object + * + * @api + */ +void adcStopConversion(ADCDriver *adcp) { + + osalDbgCheck(adcp != NULL); + + osalSysLock(); + osalDbgAssert((adcp->state == ADC_READY) || (adcp->state == ADC_ACTIVE), + "invalid state"); + if (adcp->state != ADC_READY) { + adc_lld_stop_conversion(adcp); + adcp->grpp = NULL; + adcp->state = ADC_READY; + _adc_reset_s(adcp); + } + osalSysUnlock(); +} + +/** + * @brief Stops an ongoing conversion. + * @details This function stops the currently ongoing conversion and returns + * the driver in the @p ADC_READY state. If there was no conversion + * being processed then the function does nothing. + * + * @param[in] adcp pointer to the @p ADCDriver object + * + * @iclass + */ +void adcStopConversionI(ADCDriver *adcp) { + + osalDbgCheckClassI(); + osalDbgCheck(adcp != NULL); + osalDbgAssert((adcp->state == ADC_READY) || + (adcp->state == ADC_ACTIVE) || + (adcp->state == ADC_COMPLETE), + "invalid state"); + + if (adcp->state != ADC_READY) { + adc_lld_stop_conversion(adcp); + adcp->grpp = NULL; + adcp->state = ADC_READY; + _adc_reset_i(adcp); + } +} + +#if (ADC_USE_WAIT == TRUE) || defined(__DOXYGEN__) +/** + * @brief Performs an ADC conversion. + * @details Performs a synchronous conversion operation. + * @note The buffer is organized as a matrix of M*N elements where M is the + * channels number configured into the conversion group and N is the + * buffer depth. The samples are sequentially written into the buffer + * with no gaps. + * + * @param[in] adcp pointer to the @p ADCDriver object + * @param[in] grpp pointer to a @p ADCConversionGroup object + * @param[out] samples pointer to the samples buffer + * @param[in] depth buffer depth (matrix rows number). The buffer depth + * must be one or an even number. + * @return The operation result. + * @retval MSG_OK Conversion finished. + * @retval MSG_RESET The conversion has been stopped using + * @p acdStopConversion() or @p acdStopConversionI(), + * the result buffer may contain incorrect data. + * @retval MSG_TIMEOUT The conversion has been stopped because an hardware + * error. + * + * @api + */ +msg_t adcConvert(ADCDriver *adcp, + const ADCConversionGroup *grpp, + adcsample_t *samples, + size_t depth) { + msg_t msg; + + osalSysLock(); + osalDbgAssert(adcp->thread == NULL, "already waiting"); + adcStartConversionI(adcp, grpp, samples, depth); + msg = osalThreadSuspendS(&adcp->thread); + osalSysUnlock(); + return msg; +} +#endif /* ADC_USE_WAIT == TRUE */ + +#if (ADC_USE_MUTUAL_EXCLUSION == TRUE) || defined(__DOXYGEN__) +/** + * @brief Gains exclusive access to the ADC peripheral. + * @details This function tries to gain ownership to the ADC bus, if the bus + * is already being used then the invoking thread is queued. + * @pre In order to use this function the option + * @p ADC_USE_MUTUAL_EXCLUSION must be enabled. + * + * @param[in] adcp pointer to the @p ADCDriver object + * + * @api + */ +void adcAcquireBus(ADCDriver *adcp) { + + osalDbgCheck(adcp != NULL); + + osalMutexLock(&adcp->mutex); +} + +/** + * @brief Releases exclusive access to the ADC peripheral. + * @pre In order to use this function the option + * @p ADC_USE_MUTUAL_EXCLUSION must be enabled. + * + * @param[in] adcp pointer to the @p ADCDriver object + * + * @api + */ +void adcReleaseBus(ADCDriver *adcp) { + + osalDbgCheck(adcp != NULL); + + osalMutexUnlock(&adcp->mutex); +} +#endif /* ADC_USE_MUTUAL_EXCLUSION == TRUE */ + +#endif /* HAL_USE_ADC == TRUE */ + +/** @} */ diff --git a/os/hal/src/hal_can.c b/os/hal/src/hal_can.c new file mode 100644 index 000000000..eecfdb7ce --- /dev/null +++ b/os/hal/src/hal_can.c @@ -0,0 +1,361 @@ +/* + ChibiOS - Copyright (C) 2006..2016 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 can.c + * @brief CAN Driver code. + * + * @addtogroup CAN + * @{ + */ + +#include "hal.h" + +#if (HAL_USE_CAN == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief CAN Driver initialization. + * @note This function is implicitly invoked by @p halInit(), there is + * no need to explicitly initialize the driver. + * + * @init + */ +void canInit(void) { + + can_lld_init(); +} + +/** + * @brief Initializes the standard part of a @p CANDriver structure. + * + * @param[out] canp pointer to the @p CANDriver object + * + * @init + */ +void canObjectInit(CANDriver *canp) { + + canp->state = CAN_STOP; + canp->config = NULL; + osalThreadQueueObjectInit(&canp->txqueue); + osalThreadQueueObjectInit(&canp->rxqueue); + osalEventObjectInit(&canp->rxfull_event); + osalEventObjectInit(&canp->txempty_event); + osalEventObjectInit(&canp->error_event); +#if CAN_USE_SLEEP_MODE == TRUE + osalEventObjectInit(&canp->sleep_event); + osalEventObjectInit(&canp->wakeup_event); +#endif +} + +/** + * @brief Configures and activates the CAN peripheral. + * @note Activating the CAN bus can be a slow operation. + * @note Unlike other drivers it is not possible to restart the CAN + * driver without first stopping it using canStop(). + * + * @param[in] canp pointer to the @p CANDriver object + * @param[in] config pointer to the @p CANConfig object. Depending on + * the implementation the value can be @p NULL. + * + * @api + */ +void canStart(CANDriver *canp, const CANConfig *config) { + + osalDbgCheck(canp != NULL); + + osalSysLock(); + osalDbgAssert(canp->state == CAN_STOP, "invalid state"); + + /* Entering initialization mode. */ + canp->state = CAN_STARTING; + canp->config = config; + + /* Low level initialization, could be a slow process and sleeps could + be performed inside.*/ + can_lld_start(canp); + + /* The driver finally goes into the ready state.*/ + canp->state = CAN_READY; + osalSysUnlock(); +} + +/** + * @brief Deactivates the CAN peripheral. + * + * @param[in] canp pointer to the @p CANDriver object + * + * @api + */ +void canStop(CANDriver *canp) { + + osalDbgCheck(canp != NULL); + + osalSysLock(); + osalDbgAssert((canp->state == CAN_STOP) || (canp->state == CAN_READY), + "invalid state"); + + /* The low level driver is stopped.*/ + can_lld_stop(canp); + canp->state = CAN_STOP; + + /* Threads waiting on CAN APIs are notified that the driver has been + stopped in order to not have stuck threads.*/ + osalThreadDequeueAllI(&canp->rxqueue, MSG_RESET); + osalThreadDequeueAllI(&canp->txqueue, MSG_RESET); + osalOsRescheduleS(); + osalSysUnlock(); +} + +/** + * @brief Can frame transmission attempt. + * @details The specified frame is queued for transmission, if the hardware + * queue is full then the function fails. + * + * @param[in] canp pointer to the @p CANDriver object + * @param[in] mailbox mailbox number, @p CAN_ANY_MAILBOX for any mailbox + * @param[in] ctfp pointer to the CAN frame to be transmitted + * @return The operation result. + * @retval false Frame transmitted. + * @retval true Mailbox full. + * + * @iclass + */ +bool canTryTransmitI(CANDriver *canp, + canmbx_t mailbox, + const CANTxFrame *ctfp) { + + osalDbgCheckClassI(); + osalDbgCheck((canp != NULL) && (ctfp != NULL) && + (mailbox <= (canmbx_t)CAN_TX_MAILBOXES)); + osalDbgAssert((canp->state == CAN_READY) || (canp->state == CAN_SLEEP), + "invalid state"); + + /* If the RX mailbox is full then the function fails.*/ + if (!can_lld_is_tx_empty(canp, mailbox)) { + return true; + } + + /* Transmitting frame.*/ + can_lld_transmit(canp, mailbox, ctfp); + + return false; +} + +/** + * @brief Can frame receive attempt. + * @details The function tries to fetch a frame from a mailbox. + * + * @param[in] canp pointer to the @p CANDriver object + * @param[in] mailbox mailbox number, @p CAN_ANY_MAILBOX for any mailbox + * @param[out] crfp pointer to the buffer where the CAN frame is copied + * @return The operation result. + * @retval false Frame fetched. + * @retval true Mailbox empty. + * + * @iclass + */ +bool canTryReceiveI(CANDriver *canp, + canmbx_t mailbox, + CANRxFrame *crfp) { + + osalDbgCheckClassI(); + osalDbgCheck((canp != NULL) && (crfp != NULL) && + (mailbox <= (canmbx_t)CAN_RX_MAILBOXES)); + osalDbgAssert((canp->state == CAN_READY) || (canp->state == CAN_SLEEP), + "invalid state"); + + /* If the RX mailbox is empty then the function fails.*/ + if (!can_lld_is_rx_nonempty(canp, mailbox)) { + return true; + } + + /* Fetching the frame.*/ + can_lld_receive(canp, mailbox, crfp); + + return false; +} + +/** + * @brief Can frame transmission. + * @details The specified frame is queued for transmission, if the hardware + * queue is full then the invoking thread is queued. + * @note Trying to transmit while in sleep mode simply enqueues the thread. + * + * @param[in] canp pointer to the @p CANDriver object + * @param[in] mailbox mailbox number, @p CAN_ANY_MAILBOX for any mailbox + * @param[in] ctfp pointer to the CAN frame to be transmitted + * @param[in] timeout the number of ticks before the operation timeouts, + * the following special values are allowed: + * - @a TIME_IMMEDIATE immediate timeout. + * - @a TIME_INFINITE no timeout. + * . + * @return The operation result. + * @retval MSG_OK the frame has been queued for transmission. + * @retval MSG_TIMEOUT The operation has timed out. + * @retval MSG_RESET The driver has been stopped while waiting. + * + * @api + */ +msg_t canTransmit(CANDriver *canp, + canmbx_t mailbox, + const CANTxFrame *ctfp, + systime_t timeout) { + + osalDbgCheck((canp != NULL) && (ctfp != NULL) && + (mailbox <= (canmbx_t)CAN_TX_MAILBOXES)); + + osalSysLock(); + osalDbgAssert((canp->state == CAN_READY) || (canp->state == CAN_SLEEP), + "invalid state"); + + /*lint -save -e9007 [13.5] Right side is supposed to be pure.*/ + while ((canp->state == CAN_SLEEP) || !can_lld_is_tx_empty(canp, mailbox)) { + /*lint -restore*/ + msg_t msg = osalThreadEnqueueTimeoutS(&canp->txqueue, timeout); + if (msg != MSG_OK) { + osalSysUnlock(); + return msg; + } + } + can_lld_transmit(canp, mailbox, ctfp); + osalSysUnlock(); + return MSG_OK; +} + +/** + * @brief Can frame receive. + * @details The function waits until a frame is received. + * @note Trying to receive while in sleep mode simply enqueues the thread. + * + * @param[in] canp pointer to the @p CANDriver object + * @param[in] mailbox mailbox number, @p CAN_ANY_MAILBOX for any mailbox + * @param[out] crfp pointer to the buffer where the CAN frame is copied + * @param[in] timeout the number of ticks before the operation timeouts, + * the following special values are allowed: + * - @a TIME_IMMEDIATE immediate timeout (useful in an + * event driven scenario where a thread never blocks + * for I/O). + * - @a TIME_INFINITE no timeout. + * . + * @return The operation result. + * @retval MSG_OK a frame has been received and placed in the buffer. + * @retval MSG_TIMEOUT The operation has timed out. + * @retval MSG_RESET The driver has been stopped while waiting. + * + * @api + */ +msg_t canReceive(CANDriver *canp, + canmbx_t mailbox, + CANRxFrame *crfp, + systime_t timeout) { + + osalDbgCheck((canp != NULL) && (crfp != NULL) && + (mailbox <= (canmbx_t)CAN_RX_MAILBOXES)); + + osalSysLock(); + osalDbgAssert((canp->state == CAN_READY) || (canp->state == CAN_SLEEP), + "invalid state"); + + /*lint -save -e9007 [13.5] Right side is supposed to be pure.*/ + while ((canp->state == CAN_SLEEP) || !can_lld_is_rx_nonempty(canp, mailbox)) { + /*lint -restore*/ + msg_t msg = osalThreadEnqueueTimeoutS(&canp->rxqueue, timeout); + if (msg != MSG_OK) { + osalSysUnlock(); + return msg; + } + } + can_lld_receive(canp, mailbox, crfp); + osalSysUnlock(); + return MSG_OK; +} + +#if (CAN_USE_SLEEP_MODE == TRUE) || defined(__DOXYGEN__) +/** + * @brief Enters the sleep mode. + * @details This function puts the CAN driver in sleep mode and broadcasts + * the @p sleep_event event source. + * @pre In order to use this function the option @p CAN_USE_SLEEP_MODE must + * be enabled and the @p CAN_SUPPORTS_SLEEP mode must be supported + * by the low level driver. + * + * @param[in] canp pointer to the @p CANDriver object + * + * @api + */ +void canSleep(CANDriver *canp) { + + osalDbgCheck(canp != NULL); + + osalSysLock(); + osalDbgAssert((canp->state == CAN_READY) || (canp->state == CAN_SLEEP), + "invalid state"); + if (canp->state == CAN_READY) { + can_lld_sleep(canp); + canp->state = CAN_SLEEP; + osalEventBroadcastFlagsI(&canp->sleep_event, (eventflags_t)0); + osalOsRescheduleS(); + } + osalSysUnlock(); +} + +/** + * @brief Enforces leaving the sleep mode. + * @note The sleep mode is supposed to be usually exited automatically by + * an hardware event. + * + * @param[in] canp pointer to the @p CANDriver object + */ +void canWakeup(CANDriver *canp) { + + osalDbgCheck(canp != NULL); + + osalSysLock(); + osalDbgAssert((canp->state == CAN_READY) || (canp->state == CAN_SLEEP), + "invalid state"); + if (canp->state == CAN_SLEEP) { + can_lld_wakeup(canp); + canp->state = CAN_READY; + osalEventBroadcastFlagsI(&canp->wakeup_event, (eventflags_t)0); + osalOsRescheduleS(); + } + osalSysUnlock(); +} +#endif /* CAN_USE_SLEEP_MODE == TRUE */ + +#endif /* HAL_USE_CAN == TRUE */ + +/** @} */ diff --git a/os/hal/src/hal_dac.c b/os/hal/src/hal_dac.c new file mode 100644 index 000000000..0feb4308f --- /dev/null +++ b/os/hal/src/hal_dac.c @@ -0,0 +1,349 @@ +/* + ChibiOS - Copyright (C) 2006..2016 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 dac.c + * @brief DAC Driver code. + * + * @addtogroup DAC + * @{ + */ + +#include "hal.h" + +#if (HAL_USE_DAC == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief DAC Driver initialization. + * @note This function is implicitly invoked by @p halInit(), there is + * no need to explicitly initialize the driver. + * + * @init + */ +void dacInit(void) { + + dac_lld_init(); +} + +/** + * @brief Initializes the standard part of a @p DACDriver structure. + * + * @param[out] dacp pointer to the @p DACDriver object + * + * @init + */ +void dacObjectInit(DACDriver *dacp) { + + dacp->state = DAC_STOP; + dacp->config = NULL; +#if DAC_USE_WAIT + dacp->thread = NULL; +#endif +#if DAC_USE_MUTUAL_EXCLUSION + osalMutexObjectInit(&dacp->mutex); +#endif +#if defined(DAC_DRIVER_EXT_INIT_HOOK) + DAC_DRIVER_EXT_INIT_HOOK(dacp); +#endif +} + +/** + * @brief Configures and activates the DAC peripheral. + * + * @param[in] dacp pointer to the @p DACDriver object + * @param[in] config pointer to the @p DACConfig object, it can be + * @p NULL if the low level driver implementation + * supports a default configuration + * + * @api + */ +void dacStart(DACDriver *dacp, const DACConfig *config) { + + osalDbgCheck(dacp != NULL); + + osalSysLock(); + + osalDbgAssert((dacp->state == DAC_STOP) || (dacp->state == DAC_READY), + "invalid state"); + + dacp->config = config; + dac_lld_start(dacp); + dacp->state = DAC_READY; + + osalSysUnlock(); +} + +/** + * @brief Deactivates the DAC peripheral. + * @note Deactivating the peripheral also enforces a release of the slave + * select line. + * + * @param[in] dacp pointer to the @p DACDriver object + * + * @api + */ +void dacStop(DACDriver *dacp) { + + osalDbgCheck(dacp != NULL); + + osalSysLock(); + + osalDbgAssert((dacp->state == DAC_STOP) || (dacp->state == DAC_READY), + "invalid state"); + + dac_lld_stop(dacp); + dacp->state = DAC_STOP; + + osalSysUnlock(); +} + +/** + * @brief Outputs a value directly on a DAC channel. + * + * @param[in] dacp pointer to the @p DACDriver object + * @param[in] channel DAC channel number + * @param[in] sample value to be output + * + * @xclass + */ +void dacPutChannelX(DACDriver *dacp, dacchannel_t channel, dacsample_t sample) { + + osalDbgCheck(channel < DAC_MAX_CHANNELS); + osalDbgAssert(dacp->state == DAC_READY, "invalid state"); + + dac_lld_put_channel(dacp, channel, sample); +} + +/** + * @brief Starts a DAC conversion. + * @details Starts an asynchronous conversion operation. + * @note The buffer is organized as a matrix of M*N elements where M is the + * channels number configured into the conversion group and N is the + * buffer depth. The samples are sequentially written into the buffer + * with no gaps. + * + * @param[in] dacp pointer to the @p DACDriver object + * @param[in] grpp pointer to a @p DACConversionGroup object + * @param[in] samples pointer to the samples buffer + * @param[in] depth buffer depth (matrix rows number). The buffer depth + * must be one or an even number. + * + * @api + */ +void dacStartConversion(DACDriver *dacp, + const DACConversionGroup *grpp, + const dacsample_t *samples, + size_t depth) { + + osalSysLock(); + dacStartConversionI(dacp, grpp, samples, depth); + osalSysUnlock(); +} + +/** + * @brief Starts a DAC conversion. + * @details Starts an asynchronous conversion operation. + * @post The callbacks associated to the conversion group will be invoked + * on buffer fill and error events. + * @note The buffer is organized as a matrix of M*N elements where M is the + * channels number configured into the conversion group and N is the + * buffer depth. The samples are sequentially written into the buffer + * with no gaps. + * + * @param[in] dacp pointer to the @p DACDriver object + * @param[in] grpp pointer to a @p DACConversionGroup object + * @param[in] samples pointer to the samples buffer + * @param[in] depth buffer depth (matrix rows number). The buffer depth + * must be one or an even number. + * + * @iclass + */ +void dacStartConversionI(DACDriver *dacp, + const DACConversionGroup *grpp, + const dacsample_t *samples, + size_t depth) { + + osalDbgCheckClassI(); + osalDbgCheck((dacp != NULL) && (grpp != NULL) && (samples != NULL) && + ((depth == 1) || ((depth & 1) == 0))); + osalDbgAssert((dacp->state == DAC_READY) || + (dacp->state == DAC_COMPLETE) || + (dacp->state == DAC_ERROR), + "not ready"); + + dacp->samples = samples; + dacp->depth = depth; + dacp->grpp = grpp; + dacp->state = DAC_ACTIVE; + dac_lld_start_conversion(dacp); +} + +/** + * @brief Stops an ongoing conversion. + * @details This function stops the currently ongoing conversion and returns + * the driver in the @p DAC_READY state. If there was no conversion + * being processed then the function does nothing. + * + * @param[in] dacp pointer to the @p DACDriver object + * + * @api + */ +void dacStopConversion(DACDriver *dacp) { + + osalDbgCheck(dacp != NULL); + + osalSysLock(); + + osalDbgAssert((dacp->state == DAC_READY) || + (dacp->state == DAC_ACTIVE), + "invalid state"); + + if (dacp->state != DAC_READY) { + dac_lld_stop_conversion(dacp); + dacp->grpp = NULL; + dacp->state = DAC_READY; + _dac_reset_s(dacp); + } + + osalSysUnlock(); +} + +/** + * @brief Stops an ongoing conversion. + * @details This function stops the currently ongoing conversion and returns + * the driver in the @p DAC_READY state. If there was no conversion + * being processed then the function does nothing. + * + * @param[in] dacp pointer to the @p DACDriver object + * + * @iclass + */ +void dacStopConversionI(DACDriver *dacp) { + + osalDbgCheckClassI(); + osalDbgCheck(dacp != NULL); + osalDbgAssert((dacp->state == DAC_READY) || + (dacp->state == DAC_ACTIVE) || + (dacp->state == DAC_COMPLETE), + "invalid state"); + + if (dacp->state != DAC_READY) { + dac_lld_stop_conversion(dacp); + dacp->grpp = NULL; + dacp->state = DAC_READY; + _dac_reset_i(dacp); + } +} + +#if (DAC_USE_WAIT == TRUE) || defined(__DOXYGEN__) +/** + * @brief Performs a DAC conversion. + * @details Performs a synchronous conversion operation. + * @note The buffer is organized as a matrix of M*N elements where M is the + * channels number configured into the conversion group and N is the + * buffer depth. The samples are sequentially written into the buffer + * with no gaps. + * + * @param[in] dacp pointer to the @p DACDriver object + * @param[in] grpp pointer to a @p DACConversionGroup object + * @param[out] samples pointer to the samples buffer + * @param[in] depth buffer depth (matrix rows number). The buffer depth + * must be one or an even number. + * @return The operation result. + * @retval MSG_OK Conversion finished. + * @retval MSG_RESET The conversion has been stopped using + * @p acdStopConversion() or @p acdStopConversionI(), + * the result buffer may contain incorrect data. + * @retval MSG_TIMEOUT The conversion has been stopped because an hardware + * error. + * + * @api + */ +msg_t dacConvert(DACDriver *dacp, + const DACConversionGroup *grpp, + const dacsample_t *samples, + size_t depth) { + msg_t msg; + + osalSysLock(); + + dacStartConversionI(dacp, grpp, samples, depth); + msg = osalThreadSuspendS(&dacp->thread); + + osalSysUnlock(); + return msg; +} +#endif /* DAC_USE_WAIT == TRUE */ + +#if (DAC_USE_MUTUAL_EXCLUSION == TRUE) || defined(__DOXYGEN__) +/** + * @brief Gains exclusive access to the DAC bus. + * @details This function tries to gain ownership to the DAC bus, if the bus + * is already being used then the invoking thread is queued. + * @pre In order to use this function the option @p DAC_USE_MUTUAL_EXCLUSION + * must be enabled. + * + * @param[in] dacp pointer to the @p DACDriver object + * + * @api + */ +void dacAcquireBus(DACDriver *dacp) { + + osalDbgCheck(dacp != NULL); + + osalMutexLock(&dacp->mutex); +} + +/** + * @brief Releases exclusive access to the DAC bus. + * @pre In order to use this function the option @p DAC_USE_MUTUAL_EXCLUSION + * must be enabled. + * + * @param[in] dacp pointer to the @p DACDriver object + * + * @api + */ +void dacReleaseBus(DACDriver *dacp) { + + osalDbgCheck(dacp != NULL); + + osalMutexUnlock(&dacp->mutex); +} +#endif /* DAC_USE_MUTUAL_EXCLUSION == TRUE */ + +#endif /* HAL_USE_DAC == TRUE */ + +/** @} */ diff --git a/os/hal/src/hal_ext.c b/os/hal/src/hal_ext.c new file mode 100644 index 000000000..fa25e41a4 --- /dev/null +++ b/os/hal/src/hal_ext.c @@ -0,0 +1,202 @@ +/* + ChibiOS - Copyright (C) 2006..2016 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 ext.c + * @brief EXT Driver code. + * + * @addtogroup EXT + * @{ + */ + +#include "hal.h" + +#if (HAL_USE_EXT == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief EXT Driver initialization. + * @note This function is implicitly invoked by @p halInit(), there is + * no need to explicitly initialize the driver. + * + * @init + */ +void extInit(void) { + + ext_lld_init(); +} + +/** + * @brief Initializes the standard part of a @p EXTDriver structure. + * + * @param[out] extp pointer to the @p EXTDriver object + * + * @init + */ +void extObjectInit(EXTDriver *extp) { + + extp->state = EXT_STOP; + extp->config = NULL; +} + +/** + * @brief Configures and activates the EXT peripheral. + * @post After activation all EXT channels are in the disabled state, + * use @p extChannelEnable() in order to activate them. + * + * @param[in] extp pointer to the @p EXTDriver object + * @param[in] config pointer to the @p EXTConfig object + * + * @api + */ +void extStart(EXTDriver *extp, const EXTConfig *config) { + + osalDbgCheck((extp != NULL) && (config != NULL)); + + osalSysLock(); + osalDbgAssert((extp->state == EXT_STOP) || (extp->state == EXT_ACTIVE), + "invalid state"); + extp->config = config; + ext_lld_start(extp); + extp->state = EXT_ACTIVE; + osalSysUnlock(); +} + +/** + * @brief Deactivates the EXT peripheral. + * + * @param[in] extp pointer to the @p EXTDriver object + * + * @api + */ +void extStop(EXTDriver *extp) { + + osalDbgCheck(extp != NULL); + + osalSysLock(); + osalDbgAssert((extp->state == EXT_STOP) || (extp->state == EXT_ACTIVE), + "invalid state"); + ext_lld_stop(extp); + extp->state = EXT_STOP; + osalSysUnlock(); +} + +/** + * @brief Enables an EXT channel. + * @pre The channel must not be in @p EXT_CH_MODE_DISABLED mode. + * + * @param[in] extp pointer to the @p EXTDriver object + * @param[in] channel channel to be enabled + * + * @api + */ +void extChannelEnable(EXTDriver *extp, expchannel_t channel) { + + osalDbgCheck((extp != NULL) && (channel < (expchannel_t)EXT_MAX_CHANNELS)); + + osalSysLock(); + osalDbgAssert((extp->state == EXT_ACTIVE) && + ((extp->config->channels[channel].mode & + EXT_CH_MODE_EDGES_MASK) != EXT_CH_MODE_DISABLED), + "invalid state"); + extChannelEnableI(extp, channel); + osalSysUnlock(); +} + +/** + * @brief Disables an EXT channel. + * @pre The channel must not be in @p EXT_CH_MODE_DISABLED mode. + * + * @param[in] extp pointer to the @p EXTDriver object + * @param[in] channel channel to be disabled + * + * @api + */ +void extChannelDisable(EXTDriver *extp, expchannel_t channel) { + + osalDbgCheck((extp != NULL) && (channel < (expchannel_t)EXT_MAX_CHANNELS)); + + osalSysLock(); + osalDbgAssert((extp->state == EXT_ACTIVE) && + ((extp->config->channels[channel].mode & + EXT_CH_MODE_EDGES_MASK) != EXT_CH_MODE_DISABLED), + "invalid state"); + extChannelDisableI(extp, channel); + osalSysUnlock(); +} + +/** + * @brief Changes the operation mode of a channel. + * @note This function attempts to write over the current configuration + * structure that must have been not declared constant. This + * violates the @p const qualifier in @p extStart() but it is + * intentional. + * @note This function cannot be used if the configuration structure is + * declared @p const. + * @note The effect of this function on constant configuration structures + * is not defined. + * + * @param[in] extp pointer to the @p EXTDriver object + * @param[in] channel channel to be changed + * @param[in] extcp new configuration for the channel + * + * @iclass + */ +void extSetChannelModeI(EXTDriver *extp, + expchannel_t channel, + const EXTChannelConfig *extcp) { + EXTChannelConfig *oldcp; + + osalDbgCheck((extp != NULL) && + (channel < (expchannel_t)EXT_MAX_CHANNELS) && + (extcp != NULL)); + + osalDbgAssert(extp->state == EXT_ACTIVE, "invalid state"); + + /* Note that here the access is enforced as non-const, known access + violation.*/ + /*lint -save -e9005 [11.8] Known issue, the driver needs rework here.*/ + oldcp = (EXTChannelConfig *)&extp->config->channels[channel]; + /*lint -restore*/ + + /* Overwriting the old channels configuration then the channel is + reconfigured by the low level driver.*/ + *oldcp = *extcp; + ext_lld_channel_enable(extp, channel); +} + +#endif /* HAL_USE_EXT == TRUE */ + +/** @} */ diff --git a/os/hal/src/hal_gpt.c b/os/hal/src/hal_gpt.c new file mode 100644 index 000000000..b83ffa1c1 --- /dev/null +++ b/os/hal/src/hal_gpt.c @@ -0,0 +1,262 @@ +/* + ChibiOS - Copyright (C) 2006..2016 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 gpt.c + * @brief GPT Driver code. + * + * @addtogroup GPT + * @{ + */ + +#include "hal.h" + +#if (HAL_USE_GPT == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief GPT Driver initialization. + * @note This function is implicitly invoked by @p halInit(), there is + * no need to explicitly initialize the driver. + * + * @init + */ +void gptInit(void) { + + gpt_lld_init(); +} + +/** + * @brief Initializes the standard part of a @p GPTDriver structure. + * + * @param[out] gptp pointer to the @p GPTDriver object + * + * @init + */ +void gptObjectInit(GPTDriver *gptp) { + + gptp->state = GPT_STOP; + gptp->config = NULL; +} + +/** + * @brief Configures and activates the GPT peripheral. + * + * @param[in] gptp pointer to the @p GPTDriver object + * @param[in] config pointer to the @p GPTConfig object + * + * @api + */ +void gptStart(GPTDriver *gptp, const GPTConfig *config) { + + osalDbgCheck((gptp != NULL) && (config != NULL)); + + osalSysLock(); + osalDbgAssert((gptp->state == GPT_STOP) || (gptp->state == GPT_READY), + "invalid state"); + gptp->config = config; + gpt_lld_start(gptp); + gptp->state = GPT_READY; + osalSysUnlock(); +} + +/** + * @brief Deactivates the GPT peripheral. + * + * @param[in] gptp pointer to the @p GPTDriver object + * + * @api + */ +void gptStop(GPTDriver *gptp) { + + osalDbgCheck(gptp != NULL); + + osalSysLock(); + osalDbgAssert((gptp->state == GPT_STOP) || (gptp->state == GPT_READY), + "invalid state"); + gpt_lld_stop(gptp); + gptp->state = GPT_STOP; + osalSysUnlock(); +} + +/** + * @brief Changes the interval of GPT peripheral. + * @details This function changes the interval of a running GPT unit. + * @pre The GPT unit must be running in continuous mode. + * @post The GPT unit interval is changed to the new value. + * + * @param[in] gptp pointer to a @p GPTDriver object + * @param[in] interval new cycle time in timer ticks + * + * @api + */ +void gptChangeInterval(GPTDriver *gptp, gptcnt_t interval) { + + osalDbgCheck(gptp != NULL); + + osalSysLock(); + osalDbgAssert(gptp->state == GPT_CONTINUOUS, + "invalid state"); + gptChangeIntervalI(gptp, interval); + osalSysUnlock(); +} + +/** + * @brief Starts the timer in continuous mode. + * + * @param[in] gptp pointer to the @p GPTDriver object + * @param[in] interval period in ticks + * + * @api + */ +void gptStartContinuous(GPTDriver *gptp, gptcnt_t interval) { + + osalSysLock(); + gptStartContinuousI(gptp, interval); + osalSysUnlock(); +} + +/** + * @brief Starts the timer in continuous mode. + * + * @param[in] gptp pointer to the @p GPTDriver object + * @param[in] interval period in ticks + * + * @iclass + */ +void gptStartContinuousI(GPTDriver *gptp, gptcnt_t interval) { + + osalDbgCheckClassI(); + osalDbgCheck(gptp != NULL); + osalDbgAssert(gptp->state == GPT_READY, + "invalid state"); + + gptp->state = GPT_CONTINUOUS; + gpt_lld_start_timer(gptp, interval); +} + +/** + * @brief Starts the timer in one shot mode. + * + * @param[in] gptp pointer to the @p GPTDriver object + * @param[in] interval time interval in ticks + * + * @api + */ +void gptStartOneShot(GPTDriver *gptp, gptcnt_t interval) { + + osalSysLock(); + gptStartOneShotI(gptp, interval); + osalSysUnlock(); +} + +/** + * @brief Starts the timer in one shot mode. + * + * @param[in] gptp pointer to the @p GPTDriver object + * @param[in] interval time interval in ticks + * + * @api + */ +void gptStartOneShotI(GPTDriver *gptp, gptcnt_t interval) { + + osalDbgCheckClassI(); + osalDbgCheck(gptp != NULL); + osalDbgCheck(gptp->config->callback != NULL); + osalDbgAssert(gptp->state == GPT_READY, + "invalid state"); + + gptp->state = GPT_ONESHOT; + gpt_lld_start_timer(gptp, interval); +} + +/** + * @brief Stops the timer. + * + * @param[in] gptp pointer to the @p GPTDriver object + * + * @api + */ +void gptStopTimer(GPTDriver *gptp) { + + osalSysLock(); + gptStopTimerI(gptp); + osalSysUnlock(); +} + +/** + * @brief Stops the timer. + * + * @param[in] gptp pointer to the @p GPTDriver object + * + * @api + */ +void gptStopTimerI(GPTDriver *gptp) { + + osalDbgCheckClassI(); + osalDbgCheck(gptp != NULL); + osalDbgAssert((gptp->state == GPT_READY) || (gptp->state == GPT_CONTINUOUS) || + (gptp->state == GPT_ONESHOT), + "invalid state"); + + gptp->state = GPT_READY; + gpt_lld_stop_timer(gptp); +} + +/** + * @brief Starts the timer in one shot mode and waits for completion. + * @details This function specifically polls the timer waiting for completion + * in order to not have extra delays caused by interrupt servicing, + * this function is only recommended for short delays. + * @note The configured callback is not invoked when using this function. + * + * @param[in] gptp pointer to the @p GPTDriver object + * @param[in] interval time interval in ticks + * + * @api + */ +void gptPolledDelay(GPTDriver *gptp, gptcnt_t interval) { + + osalDbgAssert(gptp->state == GPT_READY, + "invalid state"); + + gptp->state = GPT_ONESHOT; + gpt_lld_polled_delay(gptp, interval); + gptp->state = GPT_READY; +} + +#endif /* HAL_USE_GPT == TRUE */ + +/** @} */ diff --git a/os/hal/src/hal_hal.c b/os/hal/src/hal_hal.c new file mode 100644 index 000000000..04cd0b2c5 --- /dev/null +++ b/os/hal/src/hal_hal.c @@ -0,0 +1,144 @@ +/* + ChibiOS - Copyright (C) 2006..2016 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.c + * @brief HAL subsystem code. + * + * @addtogroup HAL + * @{ + */ + +#include "hal.h" + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief HAL initialization. + * @details This function invokes the low level initialization code then + * initializes all the drivers enabled in the HAL. Finally the + * board-specific initialization is performed by invoking + * @p boardInit() (usually defined in @p board.c). + * + * @init + */ +void halInit(void) { + + /* Initializes the OS Abstraction Layer.*/ + osalInit(); + + /* Platform low level initializations.*/ + hal_lld_init(); + +#if (HAL_USE_PAL == TRUE) || defined(__DOXYGEN__) + palInit(&pal_default_config); +#endif +#if (HAL_USE_ADC == TRUE) || defined(__DOXYGEN__) + adcInit(); +#endif +#if (HAL_USE_CAN == TRUE) || defined(__DOXYGEN__) + canInit(); +#endif +#if (HAL_USE_DAC == TRUE) || defined(__DOXYGEN__) + dacInit(); +#endif +#if (HAL_USE_EXT == TRUE) || defined(__DOXYGEN__) + extInit(); +#endif +#if (HAL_USE_GPT == TRUE) || defined(__DOXYGEN__) + gptInit(); +#endif +#if (HAL_USE_I2C == TRUE) || defined(__DOXYGEN__) + i2cInit(); +#endif +#if (HAL_USE_I2S == TRUE) || defined(__DOXYGEN__) + i2sInit(); +#endif +#if (HAL_USE_ICU == TRUE) || defined(__DOXYGEN__) + icuInit(); +#endif +#if (HAL_USE_MAC == TRUE) || defined(__DOXYGEN__) + macInit(); +#endif +#if (HAL_USE_PWM == TRUE) || defined(__DOXYGEN__) + pwmInit(); +#endif +#if (HAL_USE_SERIAL == TRUE) || defined(__DOXYGEN__) + sdInit(); +#endif +#if (HAL_USE_SDC == TRUE) || defined(__DOXYGEN__) + sdcInit(); +#endif +#if (HAL_USE_SPI == TRUE) || defined(__DOXYGEN__) + spiInit(); +#endif +#if (HAL_USE_UART == TRUE) || defined(__DOXYGEN__) + uartInit(); +#endif +#if (HAL_USE_USB == TRUE) || defined(__DOXYGEN__) + usbInit(); +#endif +#if (HAL_USE_MMC_SPI == TRUE) || defined(__DOXYGEN__) + mmcInit(); +#endif +#if (HAL_USE_SERIAL_USB == TRUE) || defined(__DOXYGEN__) + sduInit(); +#endif +#if (HAL_USE_RTC == TRUE) || defined(__DOXYGEN__) + rtcInit(); +#endif +#if (HAL_USE_WDG == TRUE) || defined(__DOXYGEN__) + wdgInit(); +#endif + + /* Community driver overlay initialization.*/ +#if defined(HAL_USE_COMMUNITY) || defined(__DOXYGEN__) +#if (HAL_USE_COMMUNITY == TRUE) || defined(__DOXYGEN__) + halCommunityInit(); +#endif +#endif + + /* Board specific initialization.*/ + boardInit(); + +/* + * The ST driver is a special case, it is only initialized if the OSAL is + * configured to require it. + */ +#if OSAL_ST_MODE != OSAL_ST_MODE_NONE + stInit(); +#endif +} + +/** @} */ diff --git a/os/hal/src/hal_i2c.c b/os/hal/src/hal_i2c.c new file mode 100644 index 000000000..0ed77eeaf --- /dev/null +++ b/os/hal/src/hal_i2c.c @@ -0,0 +1,283 @@ +/* + ChibiOS - Copyright (C) 2006..2016 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. +*/ +/* + Concepts and parts of this file have been contributed by Uladzimir Pylinsky + aka barthess. + */ + +/** + * @file i2c.c + * @brief I2C Driver code. + * + * @addtogroup I2C + * @{ + */ +#include "hal.h" + +#if (HAL_USE_I2C == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief I2C Driver initialization. + * @note This function is implicitly invoked by @p halInit(), there is + * no need to explicitly initialize the driver. + * + * @init + */ +void i2cInit(void) { + + i2c_lld_init(); +} + +/** + * @brief Initializes the standard part of a @p I2CDriver structure. + * + * @param[out] i2cp pointer to the @p I2CDriver object + * + * @init + */ +void i2cObjectInit(I2CDriver *i2cp) { + + i2cp->state = I2C_STOP; + i2cp->config = NULL; + +#if I2C_USE_MUTUAL_EXCLUSION == TRUE + osalMutexObjectInit(&i2cp->mutex); +#endif + +#if defined(I2C_DRIVER_EXT_INIT_HOOK) + I2C_DRIVER_EXT_INIT_HOOK(i2cp); +#endif +} + +/** + * @brief Configures and activates the I2C peripheral. + * + * @param[in] i2cp pointer to the @p I2CDriver object + * @param[in] config pointer to the @p I2CConfig object + * + * @api + */ +void i2cStart(I2CDriver *i2cp, const I2CConfig *config) { + + osalDbgCheck((i2cp != NULL) && (config != NULL)); + osalDbgAssert((i2cp->state == I2C_STOP) || (i2cp->state == I2C_READY) || + (i2cp->state == I2C_LOCKED), "invalid state"); + + osalSysLock(); + i2cp->config = config; + i2c_lld_start(i2cp); + i2cp->state = I2C_READY; + osalSysUnlock(); +} + +/** + * @brief Deactivates the I2C peripheral. + * + * @param[in] i2cp pointer to the @p I2CDriver object + * + * @api + */ +void i2cStop(I2CDriver *i2cp) { + + osalDbgCheck(i2cp != NULL); + osalDbgAssert((i2cp->state == I2C_STOP) || (i2cp->state == I2C_READY) || + (i2cp->state == I2C_LOCKED), "invalid state"); + + osalSysLock(); + i2c_lld_stop(i2cp); + i2cp->state = I2C_STOP; + osalSysUnlock(); +} + +/** + * @brief Returns the errors mask associated to the previous operation. + * + * @param[in] i2cp pointer to the @p I2CDriver object + * @return The errors mask. + * + * @api + */ +i2cflags_t i2cGetErrors(I2CDriver *i2cp) { + + osalDbgCheck(i2cp != NULL); + + return i2c_lld_get_errors(i2cp); +} + +/** + * @brief Sends data via the I2C bus. + * @details Function designed to realize "read-through-write" transfer + * paradigm. If you want transmit data without any further read, + * than set @b rxbytes field to 0. + * + * @param[in] i2cp pointer to the @p I2CDriver object + * @param[in] addr slave device address (7 bits) without R/W bit + * @param[in] txbuf pointer to transmit buffer + * @param[in] txbytes number of bytes to be transmitted + * @param[out] rxbuf pointer to receive buffer + * @param[in] rxbytes number of bytes to be received, set it to 0 if + * you want transmit only + * @param[in] timeout the number of ticks before the operation timeouts, + * the following special values are allowed: + * - @a TIME_INFINITE no timeout. + * . + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval MSG_TIMEOUT if a timeout occurred before operation end. + * + * @api + */ +msg_t i2cMasterTransmitTimeout(I2CDriver *i2cp, + i2caddr_t addr, + const uint8_t *txbuf, + size_t txbytes, + uint8_t *rxbuf, + size_t rxbytes, + systime_t timeout) { + msg_t rdymsg; + + osalDbgCheck((i2cp != NULL) && (addr != 0U) && + (txbytes > 0U) && (txbuf != NULL) && + ((rxbytes == 0U) || ((rxbytes > 0U) && (rxbuf != NULL))) && + (timeout != TIME_IMMEDIATE)); + + osalDbgAssert(i2cp->state == I2C_READY, "not ready"); + + osalSysLock(); + i2cp->errors = I2C_NO_ERROR; + i2cp->state = I2C_ACTIVE_TX; + rdymsg = i2c_lld_master_transmit_timeout(i2cp, addr, txbuf, txbytes, + rxbuf, rxbytes, timeout); + if (rdymsg == MSG_TIMEOUT) { + i2cp->state = I2C_LOCKED; + } + else { + i2cp->state = I2C_READY; + } + osalSysUnlock(); + return rdymsg; +} + +/** + * @brief Receives data from the I2C bus. + * + * @param[in] i2cp pointer to the @p I2CDriver object + * @param[in] addr slave device address (7 bits) without R/W bit + * @param[out] rxbuf pointer to receive buffer + * @param[in] rxbytes number of bytes to be received + * @param[in] timeout the number of ticks before the operation timeouts, + * the following special values are allowed: + * - @a TIME_INFINITE no timeout. + * . + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval MSG_TIMEOUT if a timeout occurred before operation end. + * + * @api + */ +msg_t i2cMasterReceiveTimeout(I2CDriver *i2cp, + i2caddr_t addr, + uint8_t *rxbuf, + size_t rxbytes, + systime_t timeout){ + + msg_t rdymsg; + + osalDbgCheck((i2cp != NULL) && (addr != 0U) && + (rxbytes > 0U) && (rxbuf != NULL) && + (timeout != TIME_IMMEDIATE)); + + osalDbgAssert(i2cp->state == I2C_READY, "not ready"); + + osalSysLock(); + i2cp->errors = I2C_NO_ERROR; + i2cp->state = I2C_ACTIVE_RX; + rdymsg = i2c_lld_master_receive_timeout(i2cp, addr, rxbuf, rxbytes, timeout); + if (rdymsg == MSG_TIMEOUT) { + i2cp->state = I2C_LOCKED; + } + else { + i2cp->state = I2C_READY; + } + osalSysUnlock(); + return rdymsg; +} + +#if (I2C_USE_MUTUAL_EXCLUSION == TRUE) || defined(__DOXYGEN__) +/** + * @brief Gains exclusive access to the I2C bus. + * @details This function tries to gain ownership to the I2C bus, if the bus + * is already being used then the invoking thread is queued. + * @pre In order to use this function the option @p I2C_USE_MUTUAL_EXCLUSION + * must be enabled. + * + * @param[in] i2cp pointer to the @p I2CDriver object + * + * @api + */ +void i2cAcquireBus(I2CDriver *i2cp) { + + osalDbgCheck(i2cp != NULL); + + osalMutexLock(&i2cp->mutex); +} + +/** + * @brief Releases exclusive access to the I2C bus. + * @pre In order to use this function the option @p I2C_USE_MUTUAL_EXCLUSION + * must be enabled. + * + * @param[in] i2cp pointer to the @p I2CDriver object + * + * @api + */ +void i2cReleaseBus(I2CDriver *i2cp) { + + osalDbgCheck(i2cp != NULL); + + osalMutexUnlock(&i2cp->mutex); +} +#endif /* I2C_USE_MUTUAL_EXCLUSION == TRUE */ + +#endif /* HAL_USE_I2C == TRUE */ + +/** @} */ diff --git a/os/hal/src/hal_i2s.c b/os/hal/src/hal_i2s.c new file mode 100644 index 000000000..57a43a7e3 --- /dev/null +++ b/os/hal/src/hal_i2s.c @@ -0,0 +1,155 @@ +/* + ChibiOS - Copyright (C) 2006..2016 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 i2s.c + * @brief I2S Driver code. + * + * @addtogroup I2S + * @{ + */ + +#include "hal.h" + +#if (HAL_USE_I2S == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief I2S Driver initialization. + * @note This function is implicitly invoked by @p halInit(), there is + * no need to explicitly initialize the driver. + * + * @init + */ +void i2sInit(void) { + + i2s_lld_init(); +} + +/** + * @brief Initializes the standard part of a @p I2SDriver structure. + * + * @param[out] i2sp pointer to the @p I2SDriver object + * + * @init + */ +void i2sObjectInit(I2SDriver *i2sp) { + + i2sp->state = I2S_STOP; + i2sp->config = NULL; +} + +/** + * @brief Configures and activates the I2S peripheral. + * + * @param[in] i2sp pointer to the @p I2SDriver object + * @param[in] config pointer to the @p I2SConfig object + * + * @api + */ +void i2sStart(I2SDriver *i2sp, const I2SConfig *config) { + + osalDbgCheck((i2sp != NULL) && (config != NULL)); + + osalSysLock(); + osalDbgAssert((i2sp->state == I2S_STOP) || (i2sp->state == I2S_READY), + "invalid state"); + i2sp->config = config; + i2s_lld_start(i2sp); + i2sp->state = I2S_READY; + osalSysUnlock(); +} + +/** + * @brief Deactivates the I2S peripheral. + * + * @param[in] i2sp pointer to the @p I2SDriver object + * + * @api + */ +void i2sStop(I2SDriver *i2sp) { + + osalDbgCheck(i2sp != NULL); + + osalSysLock(); + osalDbgAssert((i2sp->state == I2S_STOP) || (i2sp->state == I2S_READY), + "invalid state"); + i2s_lld_stop(i2sp); + i2sp->state = I2S_STOP; + osalSysUnlock(); +} + +/** + * @brief Starts a I2S data exchange. + * + * @param[in] i2sp pointer to the @p I2SDriver object + * + * @api + */ +void i2sStartExchange(I2SDriver *i2sp) { + + osalDbgCheck(i2sp != NULL); + + osalSysLock(); + osalDbgAssert(i2sp->state == I2S_READY, "not ready"); + i2sStartExchangeI(i2sp); + osalSysUnlock(); +} + +/** + * @brief Stops the ongoing data exchange. + * @details The ongoing data exchange, if any, is stopped, if the driver + * was not active the function does nothing. + * + * @param[in] i2sp pointer to the @p I2SDriver object + * + * @api + */ +void i2sStopExchange(I2SDriver *i2sp) { + + osalDbgCheck((i2sp != NULL)); + + osalSysLock(); + osalDbgAssert((i2sp->state == I2S_READY) || + (i2sp->state == I2S_ACTIVE) || + (i2sp->state == I2S_COMPLETE), + "invalid state"); + i2sStopExchangeI(i2sp); + osalSysUnlock(); +} + +#endif /* HAL_USE_I2S == TRUE */ + +/** @} */ diff --git a/os/hal/src/hal_icu.c b/os/hal/src/hal_icu.c new file mode 100644 index 000000000..ab42dc8ce --- /dev/null +++ b/os/hal/src/hal_icu.c @@ -0,0 +1,225 @@ +/* + ChibiOS - Copyright (C) 2006..2016 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 icu.c + * @brief ICU Driver code. + * + * @addtogroup ICU + * @{ + */ + +#include "hal.h" + +#if (HAL_USE_ICU == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief ICU Driver initialization. + * @note This function is implicitly invoked by @p halInit(), there is + * no need to explicitly initialize the driver. + * + * @init + */ +void icuInit(void) { + + icu_lld_init(); +} + +/** + * @brief Initializes the standard part of a @p ICUDriver structure. + * + * @param[out] icup pointer to the @p ICUDriver object + * + * @init + */ +void icuObjectInit(ICUDriver *icup) { + + icup->state = ICU_STOP; + icup->config = NULL; +} + +/** + * @brief Configures and activates the ICU peripheral. + * + * @param[in] icup pointer to the @p ICUDriver object + * @param[in] config pointer to the @p ICUConfig object + * + * @api + */ +void icuStart(ICUDriver *icup, const ICUConfig *config) { + + osalDbgCheck((icup != NULL) && (config != NULL)); + + osalSysLock(); + osalDbgAssert((icup->state == ICU_STOP) || (icup->state == ICU_READY), + "invalid state"); + icup->config = config; + icu_lld_start(icup); + icup->state = ICU_READY; + osalSysUnlock(); +} + +/** + * @brief Deactivates the ICU peripheral. + * + * @param[in] icup pointer to the @p ICUDriver object + * + * @api + */ +void icuStop(ICUDriver *icup) { + + osalDbgCheck(icup != NULL); + + osalSysLock(); + osalDbgAssert((icup->state == ICU_STOP) || (icup->state == ICU_READY), + "invalid state"); + icu_lld_stop(icup); + icup->state = ICU_STOP; + osalSysUnlock(); +} + +/** + * @brief Starts the input capture. + * + * @param[in] icup pointer to the @p ICUDriver object + * + * @api + */ +void icuStartCapture(ICUDriver *icup) { + + osalDbgCheck(icup != NULL); + + osalSysLock(); + osalDbgAssert(icup->state == ICU_READY, "invalid state"); + icuStartCaptureI(icup); + osalSysUnlock(); +} + +/** + * @brief Waits for a completed capture. + * @note The operation could be performed in polled mode depending on. + * @note In order to use this function notifications must be disabled. + * @pre The driver must be in @p ICU_WAITING or @p ICU_ACTIVE states. + * @post After the capture is available the driver is in @p ICU_ACTIVE + * state. If a capture fails then the driver is in @p ICU_WAITING + * state. + * + * @param[in] icup pointer to the @p ICUDriver object + * @return The capture status. + * @retval false if the capture is successful. + * @retval true if a timer overflow occurred. + * + * @api + */ +bool icuWaitCapture(ICUDriver *icup) { + bool result; + + osalDbgCheck(icup != NULL); + + osalSysLock(); + osalDbgAssert((icup->state == ICU_WAITING) || (icup->state == ICU_ACTIVE), + "invalid state"); + osalDbgAssert(icuAreNotificationsEnabledX(icup) == false, + "notifications enabled"); + result = icu_lld_wait_capture(icup); + icup->state = result ? ICU_WAITING : ICU_ACTIVE; + osalSysUnlock(); + + return result; +} + +/** + * @brief Stops the input capture. + * + * @param[in] icup pointer to the @p ICUDriver object + * + * @api + */ +void icuStopCapture(ICUDriver *icup) { + + osalDbgCheck(icup != NULL); + + osalSysLock(); + osalDbgAssert((icup->state == ICU_READY) || (icup->state == ICU_WAITING) || + (icup->state == ICU_ACTIVE), + "invalid state"); + icuStopCaptureI(icup); + osalSysUnlock(); +} + +/** + * @brief Enables notifications. + * @pre The ICU unit must have been activated using @p icuStart(). + * @note If the notification is already enabled then the call has no effect. + * + * @param[in] icup pointer to the @p ICUDriver object + * + * @api + */ +void icuEnableNotifications(ICUDriver *icup) { + + osalDbgCheck(icup != NULL); + + osalSysLock(); + osalDbgAssert((icup->state == ICU_WAITING) || (icup->state == ICU_ACTIVE), + "invalid state"); + icuEnableNotificationsI(icup); + osalSysUnlock(); +} + +/** + * @brief Disables notifications. + * @pre The ICU unit must have been activated using @p icuStart(). + * @note If the notification is already disabled then the call has no effect. + * + * @param[in] icup pointer to the @p ICUDriver object + * + * @api + */ +void icuDisableNotifications(ICUDriver *icup) { + + osalDbgCheck(icup != NULL); + + osalSysLock(); + osalDbgAssert((icup->state == ICU_WAITING) || (icup->state == ICU_ACTIVE), + "invalid state"); + icuDisableNotificationsI(icup); + osalSysUnlock(); +} + +#endif /* HAL_USE_ICU == TRUE */ + +/** @} */ diff --git a/os/hal/src/hal_mac.c b/os/hal/src/hal_mac.c new file mode 100644 index 000000000..18add7560 --- /dev/null +++ b/os/hal/src/hal_mac.c @@ -0,0 +1,268 @@ +/* + ChibiOS - Copyright (C) 2006..2016 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 mac.c + * @brief MAC Driver code. + * + * @addtogroup MAC + * @{ + */ + +#include "hal.h" + +#if (HAL_USE_MAC == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +#if (MAC_USE_ZERO_COPY == TRUE) && (MAC_SUPPORTS_ZERO_COPY == FALSE) +#error "MAC_USE_ZERO_COPY not supported by this implementation" +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief MAC Driver initialization. + * @note This function is implicitly invoked by @p halInit(), there is + * no need to explicitly initialize the driver. + * + * @init + */ +void macInit(void) { + + mac_lld_init(); +} + +/** + * @brief Initialize the standard part of a @p MACDriver structure. + * + * @param[out] macp pointer to the @p MACDriver object + * + * @init + */ +void macObjectInit(MACDriver *macp) { + + macp->state = MAC_STOP; + macp->config = NULL; + osalThreadQueueObjectInit(&macp->tdqueue); + osalThreadQueueObjectInit(&macp->rdqueue); +#if MAC_USE_EVENTS == TRUE + osalEventObjectInit(&macp->rdevent); +#endif +} + +/** + * @brief Configures and activates the MAC peripheral. + * + * @param[in] macp pointer to the @p MACDriver object + * @param[in] config pointer to the @p MACConfig object + * + * @api + */ +void macStart(MACDriver *macp, const MACConfig *config) { + + osalDbgCheck((macp != NULL) && (config != NULL)); + + osalSysLock(); + osalDbgAssert(macp->state == MAC_STOP, + "invalid state"); + macp->config = config; + mac_lld_start(macp); + macp->state = MAC_ACTIVE; + osalSysUnlock(); +} + +/** + * @brief Deactivates the MAC peripheral. + * + * @param[in] macp pointer to the @p MACDriver object + * + * @api + */ +void macStop(MACDriver *macp) { + + osalDbgCheck(macp != NULL); + + osalSysLock(); + osalDbgAssert((macp->state == MAC_STOP) || (macp->state == MAC_ACTIVE), + "invalid state"); + mac_lld_stop(macp); + macp->state = MAC_STOP; + osalSysUnlock(); +} + +/** + * @brief Allocates a transmission descriptor. + * @details One of the available transmission descriptors is locked and + * returned. If a descriptor is not currently available then the + * invoking thread is queued until one is freed. + * + * @param[in] macp pointer to the @p MACDriver object + * @param[out] tdp pointer to a @p MACTransmitDescriptor structure + * @param[in] timeout the number of ticks before the operation timeouts, + * the following special values are allowed: + * - @a TIME_IMMEDIATE immediate timeout. + * - @a TIME_INFINITE no timeout. + * . + * @return The operation status. + * @retval MSG_OK the descriptor was obtained. + * @retval MSG_TIMEOUT the operation timed out, descriptor not initialized. + * + * @api + */ +msg_t macWaitTransmitDescriptor(MACDriver *macp, + MACTransmitDescriptor *tdp, + systime_t timeout) { + msg_t msg; + systime_t now; + + osalDbgCheck((macp != NULL) && (tdp != NULL)); + osalDbgAssert(macp->state == MAC_ACTIVE, "not active"); + + while (((msg = mac_lld_get_transmit_descriptor(macp, tdp)) != MSG_OK) && + (timeout > (systime_t)0)) { + osalSysLock(); + now = osalOsGetSystemTimeX(); + msg = osalThreadEnqueueTimeoutS(&macp->tdqueue, timeout); + if (msg == MSG_TIMEOUT) { + osalSysUnlock(); + break; + } + if (timeout != TIME_INFINITE) { + timeout -= (osalOsGetSystemTimeX() - now); + } + osalSysUnlock(); + } + return msg; +} + +/** + * @brief Releases a transmit descriptor and starts the transmission of the + * enqueued data as a single frame. + * + * @param[in] tdp the pointer to the @p MACTransmitDescriptor structure + * + * @api + */ +void macReleaseTransmitDescriptor(MACTransmitDescriptor *tdp) { + + osalDbgCheck(tdp != NULL); + + mac_lld_release_transmit_descriptor(tdp); +} + +/** + * @brief Waits for a received frame. + * @details Stops until a frame is received and buffered. If a frame is + * not immediately available then the invoking thread is queued + * until one is received. + * + * @param[in] macp pointer to the @p MACDriver object + * @param[out] rdp pointer to a @p MACReceiveDescriptor structure + * @param[in] timeout the number of ticks before the operation timeouts, + * the following special values are allowed: + * - @a TIME_IMMEDIATE immediate timeout. + * - @a TIME_INFINITE no timeout. + * . + * @return The operation status. + * @retval MSG_OK the descriptor was obtained. + * @retval MSG_TIMEOUT the operation timed out, descriptor not initialized. + * + * @api + */ +msg_t macWaitReceiveDescriptor(MACDriver *macp, + MACReceiveDescriptor *rdp, + systime_t timeout) { + msg_t msg; + systime_t now; + + osalDbgCheck((macp != NULL) && (rdp != NULL)); + osalDbgAssert(macp->state == MAC_ACTIVE, "not active"); + + while (((msg = mac_lld_get_receive_descriptor(macp, rdp)) != MSG_OK) && + (timeout > (systime_t)0)) { + osalSysLock(); + now = osalOsGetSystemTimeX(); + msg = osalThreadEnqueueTimeoutS(&macp->rdqueue, timeout); + if (msg == MSG_TIMEOUT) { + osalSysUnlock(); + break; + } + if (timeout != TIME_INFINITE) { + timeout -= (osalOsGetSystemTimeX() - now); + } + osalSysUnlock(); + } + return msg; +} + +/** + * @brief Releases a receive descriptor. + * @details The descriptor and its buffer are made available for more incoming + * frames. + * + * @param[in] rdp the pointer to the @p MACReceiveDescriptor structure + * + * @api + */ +void macReleaseReceiveDescriptor(MACReceiveDescriptor *rdp) { + + osalDbgCheck(rdp != NULL); + + mac_lld_release_receive_descriptor(rdp); +} + +/** + * @brief Updates and returns the link status. + * + * @param[in] macp pointer to the @p MACDriver object + * @return The link status. + * @retval true if the link is active. + * @retval false if the link is down. + * + * @api + */ +bool macPollLinkStatus(MACDriver *macp) { + + osalDbgCheck(macp != NULL); + osalDbgAssert(macp->state == MAC_ACTIVE, "not active"); + + return mac_lld_poll_link_status(macp); +} + +#endif /* HAL_USE_MAC == TRUE */ + +/** @} */ diff --git a/os/hal/src/hal_mmc_spi.c b/os/hal/src/hal_mmc_spi.c new file mode 100644 index 000000000..acb0d6d2e --- /dev/null +++ b/os/hal/src/hal_mmc_spi.c @@ -0,0 +1,918 @@ +/* + ChibiOS - Copyright (C) 2006..2016 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. +*/ +/* + Parts of this file have been contributed by Matthias Blaicher. + */ + +/** + * @file mmc_spi.c + * @brief MMC over SPI driver code. + * + * @addtogroup MMC_SPI + * @{ + */ + +#include + +#include "hal.h" + +#if (HAL_USE_MMC_SPI == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/* Forward declarations required by mmc_vmt.*/ +static bool mmc_read(void *instance, uint32_t startblk, + uint8_t *buffer, uint32_t n); +static bool mmc_write(void *instance, uint32_t startblk, + const uint8_t *buffer, uint32_t n); + +/** + * @brief Virtual methods table. + */ +static const struct MMCDriverVMT mmc_vmt = { + (bool (*)(void *))mmc_lld_is_card_inserted, + (bool (*)(void *))mmc_lld_is_write_protected, + (bool (*)(void *))mmcConnect, + (bool (*)(void *))mmcDisconnect, + mmc_read, + mmc_write, + (bool (*)(void *))mmcSync, + (bool (*)(void *, BlockDeviceInfo *))mmcGetInfo +}; + +/** + * @brief Lookup table for CRC-7 ( based on polynomial x^7 + x^3 + 1). + */ +static const uint8_t crc7_lookup_table[256] = { + 0x00, 0x09, 0x12, 0x1b, 0x24, 0x2d, 0x36, 0x3f, 0x48, 0x41, 0x5a, 0x53, + 0x6c, 0x65, 0x7e, 0x77, 0x19, 0x10, 0x0b, 0x02, 0x3d, 0x34, 0x2f, 0x26, + 0x51, 0x58, 0x43, 0x4a, 0x75, 0x7c, 0x67, 0x6e, 0x32, 0x3b, 0x20, 0x29, + 0x16, 0x1f, 0x04, 0x0d, 0x7a, 0x73, 0x68, 0x61, 0x5e, 0x57, 0x4c, 0x45, + 0x2b, 0x22, 0x39, 0x30, 0x0f, 0x06, 0x1d, 0x14, 0x63, 0x6a, 0x71, 0x78, + 0x47, 0x4e, 0x55, 0x5c, 0x64, 0x6d, 0x76, 0x7f, 0x40, 0x49, 0x52, 0x5b, + 0x2c, 0x25, 0x3e, 0x37, 0x08, 0x01, 0x1a, 0x13, 0x7d, 0x74, 0x6f, 0x66, + 0x59, 0x50, 0x4b, 0x42, 0x35, 0x3c, 0x27, 0x2e, 0x11, 0x18, 0x03, 0x0a, + 0x56, 0x5f, 0x44, 0x4d, 0x72, 0x7b, 0x60, 0x69, 0x1e, 0x17, 0x0c, 0x05, + 0x3a, 0x33, 0x28, 0x21, 0x4f, 0x46, 0x5d, 0x54, 0x6b, 0x62, 0x79, 0x70, + 0x07, 0x0e, 0x15, 0x1c, 0x23, 0x2a, 0x31, 0x38, 0x41, 0x48, 0x53, 0x5a, + 0x65, 0x6c, 0x77, 0x7e, 0x09, 0x00, 0x1b, 0x12, 0x2d, 0x24, 0x3f, 0x36, + 0x58, 0x51, 0x4a, 0x43, 0x7c, 0x75, 0x6e, 0x67, 0x10, 0x19, 0x02, 0x0b, + 0x34, 0x3d, 0x26, 0x2f, 0x73, 0x7a, 0x61, 0x68, 0x57, 0x5e, 0x45, 0x4c, + 0x3b, 0x32, 0x29, 0x20, 0x1f, 0x16, 0x0d, 0x04, 0x6a, 0x63, 0x78, 0x71, + 0x4e, 0x47, 0x5c, 0x55, 0x22, 0x2b, 0x30, 0x39, 0x06, 0x0f, 0x14, 0x1d, + 0x25, 0x2c, 0x37, 0x3e, 0x01, 0x08, 0x13, 0x1a, 0x6d, 0x64, 0x7f, 0x76, + 0x49, 0x40, 0x5b, 0x52, 0x3c, 0x35, 0x2e, 0x27, 0x18, 0x11, 0x0a, 0x03, + 0x74, 0x7d, 0x66, 0x6f, 0x50, 0x59, 0x42, 0x4b, 0x17, 0x1e, 0x05, 0x0c, + 0x33, 0x3a, 0x21, 0x28, 0x5f, 0x56, 0x4d, 0x44, 0x7b, 0x72, 0x69, 0x60, + 0x0e, 0x07, 0x1c, 0x15, 0x2a, 0x23, 0x38, 0x31, 0x46, 0x4f, 0x54, 0x5d, + 0x62, 0x6b, 0x70, 0x79 +}; + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static bool mmc_read(void *instance, uint32_t startblk, + uint8_t *buffer, uint32_t n) { + + if (mmcStartSequentialRead((MMCDriver *)instance, startblk)) { + return HAL_FAILED; + } + + while (n > 0U) { + if (mmcSequentialRead((MMCDriver *)instance, buffer)) { + return HAL_FAILED; + } + buffer += MMCSD_BLOCK_SIZE; + n--; + } + + if (mmcStopSequentialRead((MMCDriver *)instance)) { + return HAL_FAILED; + } + return HAL_SUCCESS; +} + +static bool mmc_write(void *instance, uint32_t startblk, + const uint8_t *buffer, uint32_t n) { + + if (mmcStartSequentialWrite((MMCDriver *)instance, startblk)) { + return HAL_FAILED; + } + + while (n > 0U) { + if (mmcSequentialWrite((MMCDriver *)instance, buffer)) { + return HAL_FAILED; + } + buffer += MMCSD_BLOCK_SIZE; + n--; + } + + if (mmcStopSequentialWrite((MMCDriver *)instance)) { + return HAL_FAILED; + } + return HAL_SUCCESS; +} + +/** + * @brief Calculate the MMC standard CRC-7 based on a lookup table. + * + * @param[in] crc start value for CRC + * @param[in] buffer pointer to data buffer + * @param[in] len length of data + * @return Calculated CRC + */ +static uint8_t crc7(uint8_t crc, const uint8_t *buffer, size_t len) { + + while (len > 0U) { + crc = crc7_lookup_table[(crc << 1) ^ (*buffer++)]; + len--; + } + return crc; +} + +/** + * @brief Waits an idle condition. + * + * @param[in] mmcp pointer to the @p MMCDriver object + * + * @notapi + */ +static void wait(MMCDriver *mmcp) { + int i; + uint8_t buf[4]; + + for (i = 0; i < 16; i++) { + spiReceive(mmcp->config->spip, 1, buf); + if (buf[0] == 0xFFU) { + return; + } + } + /* Looks like it is a long wait.*/ + while (true) { + spiReceive(mmcp->config->spip, 1, buf); + if (buf[0] == 0xFFU) { + break; + } +#if MMC_NICE_WAITING == TRUE + /* Trying to be nice with the other threads.*/ + osalThreadSleepMilliseconds(1); +#endif + } +} + +/** + * @brief Sends a command header. + * + * @param[in] mmcp pointer to the @p MMCDriver object + * @param[in] cmd the command id + * @param[in] arg the command argument + * + * @notapi + */ +static void send_hdr(MMCDriver *mmcp, uint8_t cmd, uint32_t arg) { + uint8_t buf[6]; + + /* Wait for the bus to become idle if a write operation was in progress.*/ + wait(mmcp); + + buf[0] = (uint8_t)0x40U | cmd; + buf[1] = (uint8_t)(arg >> 24U); + buf[2] = (uint8_t)(arg >> 16U); + buf[3] = (uint8_t)(arg >> 8U); + buf[4] = (uint8_t)arg; + /* Calculate CRC for command header, shift to right position, add stop bit.*/ + buf[5] = ((crc7(0, buf, 5U) & 0x7FU) << 1U) | 0x01U; + + spiSend(mmcp->config->spip, 6, buf); +} + +/** + * @brief Receives a single byte response. + * + * @param[in] mmcp pointer to the @p MMCDriver object + * @return The response as an @p uint8_t value. + * @retval 0xFF timed out. + * + * @notapi + */ +static uint8_t recvr1(MMCDriver *mmcp) { + int i; + uint8_t r1[1]; + + for (i = 0; i < 9; i++) { + spiReceive(mmcp->config->spip, 1, r1); + if (r1[0] != 0xFFU) { + return r1[0]; + } + } + return 0xFFU; +} + +/** + * @brief Receives a three byte response. + * + * @param[in] mmcp pointer to the @p MMCDriver object + * @param[out] buffer pointer to four bytes wide buffer + * @return First response byte as an @p uint8_t value. + * @retval 0xFF timed out. + * + * @notapi + */ +static uint8_t recvr3(MMCDriver *mmcp, uint8_t* buffer) { + uint8_t r1; + + r1 = recvr1(mmcp); + spiReceive(mmcp->config->spip, 4, buffer); + + return r1; +} + +/** + * @brief Sends a command an returns a single byte response. + * + * @param[in] mmcp pointer to the @p MMCDriver object + * @param[in] cmd the command id + * @param[in] arg the command argument + * @return The response as an @p uint8_t value. + * @retval 0xFF timed out. + * + * @notapi + */ +static uint8_t send_command_R1(MMCDriver *mmcp, uint8_t cmd, uint32_t arg) { + uint8_t r1; + + spiSelect(mmcp->config->spip); + send_hdr(mmcp, cmd, arg); + r1 = recvr1(mmcp); + spiUnselect(mmcp->config->spip); + return r1; +} + +/** + * @brief Sends a command which returns a five bytes response (R3). + * + * @param[in] mmcp pointer to the @p MMCDriver object + * @param[in] cmd the command id + * @param[in] arg the command argument + * @param[out] response pointer to four bytes wide uint8_t buffer + * @return The first byte of the response (R1) as an @p + * uint8_t value. + * @retval 0xFF timed out. + * + * @notapi + */ +static uint8_t send_command_R3(MMCDriver *mmcp, uint8_t cmd, uint32_t arg, + uint8_t *response) { + uint8_t r1; + + spiSelect(mmcp->config->spip); + send_hdr(mmcp, cmd, arg); + r1 = recvr3(mmcp, response); + spiUnselect(mmcp->config->spip); + return r1; +} + +/** + * @brief Reads the CSD. + * + * @param[in] mmcp pointer to the @p MMCDriver object + * @param[out] cmd command + * @param[out] cxd pointer to the CSD/CID buffer + * + * @return The operation status. + * @retval HAL_SUCCESS the operation succeeded. + * @retval HAL_FAILED the operation failed. + * + * @notapi + */ +static bool read_CxD(MMCDriver *mmcp, uint8_t cmd, uint32_t cxd[4]) { + unsigned i; + uint8_t *bp, buf[16]; + + spiSelect(mmcp->config->spip); + send_hdr(mmcp, cmd, 0); + if (recvr1(mmcp) != 0x00U) { + spiUnselect(mmcp->config->spip); + return HAL_FAILED; + } + + /* Wait for data availability.*/ + for (i = 0U; i < MMC_WAIT_DATA; i++) { + spiReceive(mmcp->config->spip, 1, buf); + if (buf[0] == 0xFEU) { + uint32_t *wp; + + spiReceive(mmcp->config->spip, 16, buf); + bp = buf; + for (wp = &cxd[3]; wp >= cxd; wp--) { + *wp = ((uint32_t)bp[0] << 24U) | ((uint32_t)bp[1] << 16U) | + ((uint32_t)bp[2] << 8U) | (uint32_t)bp[3]; + bp += 4; + } + + /* CRC ignored then end of transaction. */ + spiIgnore(mmcp->config->spip, 2); + spiUnselect(mmcp->config->spip); + + return HAL_SUCCESS; + } + } + return HAL_FAILED; +} + +/** + * @brief Waits that the card reaches an idle state. + * + * @param[in] mmcp pointer to the @p MMCDriver object + * + * @notapi + */ +static void sync(MMCDriver *mmcp) { + uint8_t buf[1]; + + spiSelect(mmcp->config->spip); + while (true) { + spiReceive(mmcp->config->spip, 1, buf); + if (buf[0] == 0xFFU) { + break; + } +#if MMC_NICE_WAITING == TRUE + /* Trying to be nice with the other threads.*/ + osalThreadSleepMilliseconds(1); +#endif + } + spiUnselect(mmcp->config->spip); +} + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief MMC over SPI driver initialization. + * @note This function is implicitly invoked by @p halInit(), there is + * no need to explicitly initialize the driver. + * + * @init + */ +void mmcInit(void) { + +} + +/** + * @brief Initializes an instance. + * + * @param[out] mmcp pointer to the @p MMCDriver object + * + * @init + */ +void mmcObjectInit(MMCDriver *mmcp) { + + mmcp->vmt = &mmc_vmt; + mmcp->state = BLK_STOP; + mmcp->config = NULL; + mmcp->block_addresses = false; +} + +/** + * @brief Configures and activates the MMC peripheral. + * + * @param[in] mmcp pointer to the @p MMCDriver object + * @param[in] config pointer to the @p MMCConfig object. + * + * @api + */ +void mmcStart(MMCDriver *mmcp, const MMCConfig *config) { + + osalDbgCheck((mmcp != NULL) && (config != NULL)); + osalDbgAssert((mmcp->state == BLK_STOP) || (mmcp->state == BLK_ACTIVE), + "invalid state"); + + mmcp->config = config; + mmcp->state = BLK_ACTIVE; +} + +/** + * @brief Disables the MMC peripheral. + * + * @param[in] mmcp pointer to the @p MMCDriver object + * + * @api + */ +void mmcStop(MMCDriver *mmcp) { + + osalDbgCheck(mmcp != NULL); + osalDbgAssert((mmcp->state == BLK_STOP) || (mmcp->state == BLK_ACTIVE), + "invalid state"); + + spiStop(mmcp->config->spip); + mmcp->state = BLK_STOP; +} + +/** + * @brief Performs the initialization procedure on the inserted card. + * @details This function should be invoked when a card is inserted and + * brings the driver in the @p MMC_READY state where it is possible + * to perform read and write operations. + * @note It is possible to invoke this function from the insertion event + * handler. + * + * @param[in] mmcp pointer to the @p MMCDriver object + * + * @return The operation status. + * @retval HAL_SUCCESS the operation succeeded and the driver is now + * in the @p MMC_READY state. + * @retval HAL_FAILED the operation failed. + * + * @api + */ +bool mmcConnect(MMCDriver *mmcp) { + unsigned i; + uint8_t r3[4]; + + osalDbgCheck(mmcp != NULL); + + osalDbgAssert((mmcp->state == BLK_ACTIVE) || (mmcp->state == BLK_READY), + "invalid state"); + + /* Connection procedure in progress.*/ + mmcp->state = BLK_CONNECTING; + mmcp->block_addresses = false; + + /* Slow clock mode and 128 clock pulses.*/ + spiStart(mmcp->config->spip, mmcp->config->lscfg); + spiIgnore(mmcp->config->spip, 16); + + /* SPI mode selection.*/ + i = 0; + while (true) { + if (send_command_R1(mmcp, MMCSD_CMD_GO_IDLE_STATE, 0) == 0x01U) { + break; + } + if (++i >= MMC_CMD0_RETRY) { + goto failed; + } + osalThreadSleepMilliseconds(10); + } + + /* Try to detect if this is a high capacity card and switch to block + addresses if possible. + This method is based on "How to support SDC Ver2 and high capacity cards" + by ElmChan.*/ + if (send_command_R3(mmcp, MMCSD_CMD_SEND_IF_COND, + MMCSD_CMD8_PATTERN, r3) != 0x05U) { + + /* Switch to SDHC mode.*/ + i = 0; + while (true) { + /*lint -save -e9007 [13.5] Side effect unimportant.*/ + if ((send_command_R1(mmcp, MMCSD_CMD_APP_CMD, 0) == 0x01U) && + (send_command_R3(mmcp, MMCSD_CMD_APP_OP_COND, 0x400001AAU, r3) == 0x00U)) { + /*lint -restore*/ + break; + } + + if (++i >= MMC_ACMD41_RETRY) { + goto failed; + } + osalThreadSleepMilliseconds(10); + } + + /* Execute dedicated read on OCR register */ + (void) send_command_R3(mmcp, MMCSD_CMD_READ_OCR, 0, r3); + + /* Check if CCS is set in response. Card operates in block mode if set.*/ + if ((r3[0] & 0x40U) != 0U) { + mmcp->block_addresses = true; + } + } + + /* Initialization.*/ + i = 0; + while (true) { + uint8_t b = send_command_R1(mmcp, MMCSD_CMD_INIT, 0); + if (b == 0x00U) { + break; + } + if (b != 0x01U) { + goto failed; + } + if (++i >= MMC_CMD1_RETRY) { + goto failed; + } + osalThreadSleepMilliseconds(10); + } + + /* Initialization complete, full speed.*/ + spiStart(mmcp->config->spip, mmcp->config->hscfg); + + /* Setting block size.*/ + if (send_command_R1(mmcp, MMCSD_CMD_SET_BLOCKLEN, + MMCSD_BLOCK_SIZE) != 0x00U) { + goto failed; + } + + /* Determine capacity.*/ + if (read_CxD(mmcp, MMCSD_CMD_SEND_CSD, mmcp->csd)) { + goto failed; + } + + mmcp->capacity = _mmcsd_get_capacity(mmcp->csd); + if (mmcp->capacity == 0U) { + goto failed; + } + + if (read_CxD(mmcp, MMCSD_CMD_SEND_CID, mmcp->cid)) { + goto failed; + } + + mmcp->state = BLK_READY; + return HAL_SUCCESS; + + /* Connection failed, state reset to BLK_ACTIVE.*/ +failed: + spiStop(mmcp->config->spip); + mmcp->state = BLK_ACTIVE; + return HAL_FAILED; +} + +/** + * @brief Brings the driver in a state safe for card removal. + * + * @param[in] mmcp pointer to the @p MMCDriver object + * @return The operation status. + * + * @retval HAL_SUCCESS the operation succeeded and the driver is now + * in the @p MMC_INSERTED state. + * @retval HAL_FAILED the operation failed. + * + * @api + */ +bool mmcDisconnect(MMCDriver *mmcp) { + + osalDbgCheck(mmcp != NULL); + + osalSysLock(); + osalDbgAssert((mmcp->state == BLK_ACTIVE) || (mmcp->state == BLK_READY), + "invalid state"); + if (mmcp->state == BLK_ACTIVE) { + osalSysUnlock(); + return HAL_SUCCESS; + } + mmcp->state = BLK_DISCONNECTING; + osalSysUnlock(); + + /* Wait for the pending write operations to complete.*/ + spiStart(mmcp->config->spip, mmcp->config->hscfg); + sync(mmcp); + + spiStop(mmcp->config->spip); + mmcp->state = BLK_ACTIVE; + return HAL_SUCCESS; +} + +/** + * @brief Starts a sequential read. + * + * @param[in] mmcp pointer to the @p MMCDriver object + * @param[in] startblk first block to read + * + * @return The operation status. + * @retval HAL_SUCCESS the operation succeeded. + * @retval HAL_FAILED the operation failed. + * + * @api + */ +bool mmcStartSequentialRead(MMCDriver *mmcp, uint32_t startblk) { + + osalDbgCheck(mmcp != NULL); + osalDbgAssert(mmcp->state == BLK_READY, "invalid state"); + + /* Read operation in progress.*/ + mmcp->state = BLK_READING; + + /* (Re)starting the SPI in case it has been reprogrammed externally, it can + happen if the SPI bus is shared among multiple peripherals.*/ + spiStart(mmcp->config->spip, mmcp->config->hscfg); + spiSelect(mmcp->config->spip); + + if (mmcp->block_addresses) { + send_hdr(mmcp, MMCSD_CMD_READ_MULTIPLE_BLOCK, startblk); + } + else { + send_hdr(mmcp, MMCSD_CMD_READ_MULTIPLE_BLOCK, startblk * MMCSD_BLOCK_SIZE); + } + + if (recvr1(mmcp) != 0x00U) { + spiStop(mmcp->config->spip); + mmcp->state = BLK_READY; + return HAL_FAILED; + } + return HAL_SUCCESS; +} + +/** + * @brief Reads a block within a sequential read operation. + * + * @param[in] mmcp pointer to the @p MMCDriver object + * @param[out] buffer pointer to the read buffer + * + * @return The operation status. + * @retval HAL_SUCCESS the operation succeeded. + * @retval HAL_FAILED the operation failed. + * + * @api + */ +bool mmcSequentialRead(MMCDriver *mmcp, uint8_t *buffer) { + unsigned i; + + osalDbgCheck((mmcp != NULL) && (buffer != NULL)); + + if (mmcp->state != BLK_READING) { + return HAL_FAILED; + } + + for (i = 0; i < MMC_WAIT_DATA; i++) { + spiReceive(mmcp->config->spip, 1, buffer); + if (buffer[0] == 0xFEU) { + spiReceive(mmcp->config->spip, MMCSD_BLOCK_SIZE, buffer); + /* CRC ignored. */ + spiIgnore(mmcp->config->spip, 2); + return HAL_SUCCESS; + } + } + /* Timeout.*/ + spiUnselect(mmcp->config->spip); + spiStop(mmcp->config->spip); + mmcp->state = BLK_READY; + return HAL_FAILED; +} + +/** + * @brief Stops a sequential read gracefully. + * + * @param[in] mmcp pointer to the @p MMCDriver object + * + * @return The operation status. + * @retval HAL_SUCCESS the operation succeeded. + * @retval HAL_FAILED the operation failed. + * + * @api + */ +bool mmcStopSequentialRead(MMCDriver *mmcp) { + static const uint8_t stopcmd[] = { + (uint8_t)(0x40U | MMCSD_CMD_STOP_TRANSMISSION), 0, 0, 0, 0, 1, 0xFF + }; + + osalDbgCheck(mmcp != NULL); + + if (mmcp->state != BLK_READING) { + return HAL_FAILED; + } + + spiSend(mmcp->config->spip, sizeof(stopcmd), stopcmd); +/* result = recvr1(mmcp) != 0x00U;*/ + /* Note, ignored r1 response, it can be not zero, unknown issue.*/ + (void) recvr1(mmcp); + + /* Read operation finished.*/ + spiUnselect(mmcp->config->spip); + mmcp->state = BLK_READY; + return HAL_SUCCESS; +} + +/** + * @brief Starts a sequential write. + * + * @param[in] mmcp pointer to the @p MMCDriver object + * @param[in] startblk first block to write + * + * @return The operation status. + * @retval HAL_SUCCESS the operation succeeded. + * @retval HAL_FAILED the operation failed. + * + * @api + */ +bool mmcStartSequentialWrite(MMCDriver *mmcp, uint32_t startblk) { + + osalDbgCheck(mmcp != NULL); + osalDbgAssert(mmcp->state == BLK_READY, "invalid state"); + + /* Write operation in progress.*/ + mmcp->state = BLK_WRITING; + + spiStart(mmcp->config->spip, mmcp->config->hscfg); + spiSelect(mmcp->config->spip); + if (mmcp->block_addresses) { + send_hdr(mmcp, MMCSD_CMD_WRITE_MULTIPLE_BLOCK, startblk); + } + else { + send_hdr(mmcp, MMCSD_CMD_WRITE_MULTIPLE_BLOCK, + startblk * MMCSD_BLOCK_SIZE); + } + + if (recvr1(mmcp) != 0x00U) { + spiStop(mmcp->config->spip); + mmcp->state = BLK_READY; + return HAL_FAILED; + } + return HAL_SUCCESS; +} + +/** + * @brief Writes a block within a sequential write operation. + * + * @param[in] mmcp pointer to the @p MMCDriver object + * @param[out] buffer pointer to the write buffer + * + * @return The operation status. + * @retval HAL_SUCCESS the operation succeeded. + * @retval HAL_FAILED the operation failed. + * + * @api + */ +bool mmcSequentialWrite(MMCDriver *mmcp, const uint8_t *buffer) { + static const uint8_t start[] = {0xFF, 0xFC}; + uint8_t b[1]; + + osalDbgCheck((mmcp != NULL) && (buffer != NULL)); + + if (mmcp->state != BLK_WRITING) { + return HAL_FAILED; + } + + spiSend(mmcp->config->spip, sizeof(start), start); /* Data prologue. */ + spiSend(mmcp->config->spip, MMCSD_BLOCK_SIZE, buffer);/* Data. */ + spiIgnore(mmcp->config->spip, 2); /* CRC ignored. */ + spiReceive(mmcp->config->spip, 1, b); + if ((b[0] & 0x1FU) == 0x05U) { + wait(mmcp); + return HAL_SUCCESS; + } + + /* Error.*/ + spiUnselect(mmcp->config->spip); + spiStop(mmcp->config->spip); + mmcp->state = BLK_READY; + return HAL_FAILED; +} + +/** + * @brief Stops a sequential write gracefully. + * + * @param[in] mmcp pointer to the @p MMCDriver object + * + * @return The operation status. + * @retval HAL_SUCCESS the operation succeeded. + * @retval HAL_FAILED the operation failed. + * + * @api + */ +bool mmcStopSequentialWrite(MMCDriver *mmcp) { + static const uint8_t stop[] = {0xFD, 0xFF}; + + osalDbgCheck(mmcp != NULL); + + if (mmcp->state != BLK_WRITING) { + return HAL_FAILED; + } + + spiSend(mmcp->config->spip, sizeof(stop), stop); + spiUnselect(mmcp->config->spip); + + /* Write operation finished.*/ + mmcp->state = BLK_READY; + return HAL_SUCCESS; +} + +/** + * @brief Waits for card idle condition. + * + * @param[in] mmcp pointer to the @p MMCDriver object + * + * @return The operation status. + * @retval HAL_SUCCESS the operation succeeded. + * @retval HAL_FAILED the operation failed. + * + * @api + */ +bool mmcSync(MMCDriver *mmcp) { + + osalDbgCheck(mmcp != NULL); + + if (mmcp->state != BLK_READY) { + return HAL_FAILED; + } + + /* Synchronization operation in progress.*/ + mmcp->state = BLK_SYNCING; + + spiStart(mmcp->config->spip, mmcp->config->hscfg); + sync(mmcp); + + /* Synchronization operation finished.*/ + mmcp->state = BLK_READY; + return HAL_SUCCESS; +} + +/** + * @brief Returns the media info. + * + * @param[in] mmcp pointer to the @p MMCDriver object + * @param[out] bdip pointer to a @p BlockDeviceInfo structure + * + * @return The operation status. + * @retval HAL_SUCCESS the operation succeeded. + * @retval HAL_FAILED the operation failed. + * + * @api + */ +bool mmcGetInfo(MMCDriver *mmcp, BlockDeviceInfo *bdip) { + + osalDbgCheck((mmcp != NULL) && (bdip != NULL)); + + if (mmcp->state != BLK_READY) { + return HAL_FAILED; + } + + bdip->blk_num = mmcp->capacity; + bdip->blk_size = MMCSD_BLOCK_SIZE; + + return HAL_SUCCESS; +} + +/** + * @brief Erases blocks. + * + * @param[in] mmcp pointer to the @p MMCDriver object + * @param[in] startblk starting block number + * @param[in] endblk ending block number + * + * @return The operation status. + * @retval HAL_SUCCESS the operation succeeded. + * @retval HAL_FAILED the operation failed. + * + * @api + */ +bool mmcErase(MMCDriver *mmcp, uint32_t startblk, uint32_t endblk) { + + osalDbgCheck((mmcp != NULL)); + + /* Erase operation in progress.*/ + mmcp->state = BLK_WRITING; + + /* Handling command differences between HC and normal cards.*/ + if (!mmcp->block_addresses) { + startblk *= MMCSD_BLOCK_SIZE; + endblk *= MMCSD_BLOCK_SIZE; + } + + if (send_command_R1(mmcp, MMCSD_CMD_ERASE_RW_BLK_START, startblk) != 0x00U) { + goto failed; + } + + if (send_command_R1(mmcp, MMCSD_CMD_ERASE_RW_BLK_END, endblk) != 0x00U) { + goto failed; + } + + if (send_command_R1(mmcp, MMCSD_CMD_ERASE, 0) != 0x00U) { + goto failed; + } + + mmcp->state = BLK_READY; + return HAL_SUCCESS; + + /* Command failed, state reset to BLK_ACTIVE.*/ +failed: + spiStop(mmcp->config->spip); + mmcp->state = BLK_READY; + return HAL_FAILED; +} + +#endif /* HAL_USE_MMC_SPI == TRUE */ + +/** @} */ diff --git a/os/hal/src/hal_pal.c b/os/hal/src/hal_pal.c new file mode 100644 index 000000000..f75e8d481 --- /dev/null +++ b/os/hal/src/hal_pal.c @@ -0,0 +1,122 @@ +/* + ChibiOS - Copyright (C) 2006..2016 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 pal.c + * @brief I/O Ports Abstraction Layer code. + * + * @addtogroup PAL + * @{ + */ + +#include "hal.h" + +#if (HAL_USE_PAL == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Read from an I/O bus. + * @note The operation is not guaranteed to be atomic on all the + * architectures, for atomicity and/or portability reasons you may + * need to enclose port I/O operations between @p osalSysLock() and + * @p osalSysUnlock(). + * @note The function internally uses the @p palReadGroup() macro. The use + * of this function is preferred when you value code size, readability + * and error checking over speed. + * @note The function can be called from any context. + * + * @param[in] bus the I/O bus, pointer to a @p IOBus structure + * @return The bus logical states. + * + * @special + */ +ioportmask_t palReadBus(IOBus *bus) { + + osalDbgCheck((bus != NULL) && (bus->offset < PAL_IOPORTS_WIDTH)); + + return palReadGroup(bus->portid, bus->mask, bus->offset); +} + +/** + * @brief Write to an I/O bus. + * @note The operation is not guaranteed to be atomic on all the + * architectures, for atomicity and/or portability reasons you may + * need to enclose port I/O operations between @p osalSysLock() and + * @p osalSysUnlock(). + * @note The default implementation is non atomic and not necessarily + * optimal. Low level drivers may optimize the function by using + * specific hardware or coding. + * @note The function can be called from any context. + * + * @param[in] bus the I/O bus, pointer to a @p IOBus structure + * @param[in] bits the bits to be written on the I/O bus. Values exceeding + * the bus width are masked so most significant bits are + * lost. + * + * @special + */ +void palWriteBus(IOBus *bus, ioportmask_t bits) { + + osalDbgCheck((bus != NULL) && (bus->offset < PAL_IOPORTS_WIDTH)); + + palWriteGroup(bus->portid, bus->mask, bus->offset, bits); +} + +/** + * @brief Programs a bus with the specified mode. + * @note The operation is not guaranteed to be atomic on all the + * architectures, for atomicity and/or portability reasons you may + * need to enclose port I/O operations between @p osalSysLock() and + * @p osalSysUnlock(). + * @note The default implementation is non atomic and not necessarily + * optimal. Low level drivers may optimize the function by using + * specific hardware or coding. + * @note The function can be called from any context. + * + * @param[in] bus the I/O bus, pointer to a @p IOBus structure + * @param[in] mode the mode + * + * @special + */ +void palSetBusMode(IOBus *bus, iomode_t mode) { + + osalDbgCheck((bus != NULL) && (bus->offset < PAL_IOPORTS_WIDTH)); + + palSetGroupMode(bus->portid, bus->mask, bus->offset, mode); +} + +#endif /* HAL_USE_PAL == TRUE */ + +/** @} */ diff --git a/os/hal/src/hal_pwm.c b/os/hal/src/hal_pwm.c new file mode 100644 index 000000000..f74bf534c --- /dev/null +++ b/os/hal/src/hal_pwm.c @@ -0,0 +1,309 @@ +/* + ChibiOS - Copyright (C) 2006..2016 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 pwm.c + * @brief PWM Driver code. + * + * @addtogroup PWM + * @{ + */ + +#include "hal.h" + +#if (HAL_USE_PWM == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief PWM Driver initialization. + * @note This function is implicitly invoked by @p halInit(), there is + * no need to explicitly initialize the driver. + * + * @init + */ +void pwmInit(void) { + + pwm_lld_init(); +} + +/** + * @brief Initializes the standard part of a @p PWMDriver structure. + * + * @param[out] pwmp pointer to a @p PWMDriver object + * + * @init + */ +void pwmObjectInit(PWMDriver *pwmp) { + + pwmp->state = PWM_STOP; + pwmp->config = NULL; + pwmp->enabled = 0; + pwmp->channels = 0; +#if defined(PWM_DRIVER_EXT_INIT_HOOK) + PWM_DRIVER_EXT_INIT_HOOK(pwmp); +#endif +} + +/** + * @brief Configures and activates the PWM peripheral. + * @note Starting a driver that is already in the @p PWM_READY state + * disables all the active channels. + * + * @param[in] pwmp pointer to a @p PWMDriver object + * @param[in] config pointer to a @p PWMConfig object + * + * @api + */ +void pwmStart(PWMDriver *pwmp, const PWMConfig *config) { + + osalDbgCheck((pwmp != NULL) && (config != NULL)); + + osalSysLock(); + osalDbgAssert((pwmp->state == PWM_STOP) || (pwmp->state == PWM_READY), + "invalid state"); + pwmp->config = config; + pwmp->period = config->period; + pwm_lld_start(pwmp); + pwmp->enabled = 0; + pwmp->state = PWM_READY; + osalSysUnlock(); +} + +/** + * @brief Deactivates the PWM peripheral. + * + * @param[in] pwmp pointer to a @p PWMDriver object + * + * @api + */ +void pwmStop(PWMDriver *pwmp) { + + osalDbgCheck(pwmp != NULL); + + osalSysLock(); + osalDbgAssert((pwmp->state == PWM_STOP) || (pwmp->state == PWM_READY), + "invalid state"); + pwm_lld_stop(pwmp); + pwmp->enabled = 0; + pwmp->state = PWM_STOP; + osalSysUnlock(); +} + +/** + * @brief Changes the period the PWM peripheral. + * @details This function changes the period of a PWM unit that has already + * been activated using @p pwmStart(). + * @pre The PWM unit must have been activated using @p pwmStart(). + * @post The PWM unit period is changed to the new value. + * @note If a period is specified that is shorter than the pulse width + * programmed in one of the channels then the behavior is not + * guaranteed. + * + * @param[in] pwmp pointer to a @p PWMDriver object + * @param[in] period new cycle time in ticks + * + * @api + */ +void pwmChangePeriod(PWMDriver *pwmp, pwmcnt_t period) { + + osalDbgCheck(pwmp != NULL); + + osalSysLock(); + osalDbgAssert(pwmp->state == PWM_READY, "invalid state"); + pwmChangePeriodI(pwmp, period); + osalSysUnlock(); +} + +/** + * @brief Enables a PWM channel. + * @pre The PWM unit must have been activated using @p pwmStart(). + * @post The channel is active using the specified configuration. + * @note Depending on the hardware implementation this function has + * effect starting on the next cycle (recommended implementation) + * or immediately (fallback implementation). + * + * @param[in] pwmp pointer to a @p PWMDriver object + * @param[in] channel PWM channel identifier (0...channels-1) + * @param[in] width PWM pulse width as clock pulses number + * + * @api + */ +void pwmEnableChannel(PWMDriver *pwmp, + pwmchannel_t channel, + pwmcnt_t width) { + + osalDbgCheck((pwmp != NULL) && (channel < pwmp->channels)); + + osalSysLock(); + + osalDbgAssert(pwmp->state == PWM_READY, "not ready"); + + pwmEnableChannelI(pwmp, channel, width); + + osalSysUnlock(); +} + +/** + * @brief Disables a PWM channel and its notification. + * @pre The PWM unit must have been activated using @p pwmStart(). + * @post The channel is disabled and its output line returned to the + * idle state. + * @note Depending on the hardware implementation this function has + * effect starting on the next cycle (recommended implementation) + * or immediately (fallback implementation). + * + * @param[in] pwmp pointer to a @p PWMDriver object + * @param[in] channel PWM channel identifier (0...channels-1) + * + * @api + */ +void pwmDisableChannel(PWMDriver *pwmp, pwmchannel_t channel) { + + osalDbgCheck((pwmp != NULL) && (channel < pwmp->channels)); + + osalSysLock(); + + osalDbgAssert(pwmp->state == PWM_READY, "not ready"); + + pwmDisableChannelI(pwmp, channel); + + osalSysUnlock(); +} + +/** + * @brief Enables the periodic activation edge notification. + * @pre The PWM unit must have been activated using @p pwmStart(). + * @note If the notification is already enabled then the call has no effect. + * + * @param[in] pwmp pointer to a @p PWMDriver object + * + * @api + */ +void pwmEnablePeriodicNotification(PWMDriver *pwmp) { + + osalDbgCheck(pwmp != NULL); + + osalSysLock(); + + osalDbgAssert(pwmp->state == PWM_READY, "not ready"); + osalDbgAssert(pwmp->config->callback != NULL, "undefined periodic callback"); + + pwmEnablePeriodicNotificationI(pwmp); + + osalSysUnlock(); +} + +/** + * @brief Disables the periodic activation edge notification. + * @pre The PWM unit must have been activated using @p pwmStart(). + * @note If the notification is already disabled then the call has no effect. + * + * @param[in] pwmp pointer to a @p PWMDriver object + * + * @api + */ +void pwmDisablePeriodicNotification(PWMDriver *pwmp) { + + osalDbgCheck(pwmp != NULL); + + osalSysLock(); + + osalDbgAssert(pwmp->state == PWM_READY, "not ready"); + osalDbgAssert(pwmp->config->callback != NULL, "undefined periodic callback"); + + pwmDisablePeriodicNotificationI(pwmp); + + osalSysUnlock(); +} + +/** + * @brief Enables a channel de-activation edge notification. + * @pre The PWM unit must have been activated using @p pwmStart(). + * @pre The channel must have been activated using @p pwmEnableChannel(). + * @note If the notification is already enabled then the call has no effect. + * + * @param[in] pwmp pointer to a @p PWMDriver object + * @param[in] channel PWM channel identifier (0...channels-1) + * + * @api + */ +void pwmEnableChannelNotification(PWMDriver *pwmp, pwmchannel_t channel) { + + osalDbgCheck((pwmp != NULL) && (channel < pwmp->channels)); + + osalSysLock(); + + osalDbgAssert(pwmp->state == PWM_READY, "not ready"); + osalDbgAssert((pwmp->enabled & ((pwmchnmsk_t)1U << (pwmchnmsk_t)channel)) != 0U, + "channel not enabled"); + osalDbgAssert(pwmp->config->channels[channel].callback != NULL, + "undefined channel callback"); + + pwmEnableChannelNotificationI(pwmp, channel); + + osalSysUnlock(); +} + +/** + * @brief Disables a channel de-activation edge notification. + * @pre The PWM unit must have been activated using @p pwmStart(). + * @pre The channel must have been activated using @p pwmEnableChannel(). + * @note If the notification is already disabled then the call has no effect. + * + * @param[in] pwmp pointer to a @p PWMDriver object + * @param[in] channel PWM channel identifier (0...channels-1) + * + * @api + */ +void pwmDisableChannelNotification(PWMDriver *pwmp, pwmchannel_t channel) { + + osalDbgCheck((pwmp != NULL) && (channel < pwmp->channels)); + + osalSysLock(); + + osalDbgAssert(pwmp->state == PWM_READY, "not ready"); + osalDbgAssert((pwmp->enabled & ((pwmchnmsk_t)1U << (pwmchnmsk_t)channel)) != 0U, + "channel not enabled"); + osalDbgAssert(pwmp->config->channels[channel].callback != NULL, + "undefined channel callback"); + + pwmDisableChannelNotificationI(pwmp, channel); + + osalSysUnlock(); +} + +#endif /* HAL_USE_PWM == TRUE */ + +/** @} */ diff --git a/os/hal/src/hal_rtc.c b/os/hal/src/hal_rtc.c new file mode 100644 index 000000000..252bb7ab1 --- /dev/null +++ b/os/hal/src/hal_rtc.c @@ -0,0 +1,321 @@ +/* + ChibiOS - Copyright (C) 2006..2016 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. +*/ +/* + Concepts and parts of this file have been contributed by Uladzimir Pylinsky + aka barthess. + */ + +/** + * @file rtc.c + * @brief RTC Driver code. + * + * @addtogroup RTC + * @{ + */ + +#include "hal.h" + +#if (HAL_USE_RTC == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/* + * Lookup table with months' length + */ +static const uint8_t month_len[12] = { + 31, 30, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 +}; + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief RTC Driver initialization. + * @note This function is implicitly invoked by @p halInit(), there is + * no need to explicitly initialize the driver. + * + * @init + */ +void rtcInit(void) { + + rtc_lld_init(); +} + +/** + * @brief Initializes a generic RTC driver object. + * @details The HW dependent part of the initialization has to be performed + * outside, usually in the hardware initialization code. + * + * @param[out] rtcp pointer to RTC driver structure + * + * @init + */ +void rtcObjectInit(RTCDriver *rtcp) { + +#if RTC_HAS_STORAGE == TRUE + rtcp->vmt = &_rtc_lld_vmt; +#else + (void)rtcp; +#endif +} + +/** + * @brief Set current time. + * @note This function can be called from any context but limitations + * could be imposed by the low level implementation. It is + * guaranteed that the function can be called from thread + * context. + * @note The function can be reentrant or not reentrant depending on + * the low level implementation. + * + * @param[in] rtcp pointer to RTC driver structure + * @param[in] timespec pointer to a @p RTCDateTime structure + * + * @special + */ +void rtcSetTime(RTCDriver *rtcp, const RTCDateTime *timespec) { + + osalDbgCheck((rtcp != NULL) && (timespec != NULL)); + + rtc_lld_set_time(rtcp, timespec); +} + +/** + * @brief Get current time. + * @note This function can be called from any context but limitations + * could be imposed by the low level implementation. It is + * guaranteed that the function can be called from thread + * context. + * @note The function can be reentrant or not reentrant depending on + * the low level implementation. + * + * @param[in] rtcp pointer to RTC driver structure + * @param[out] timespec pointer to a @p RTCDateTime structure + * + * @special + */ +void rtcGetTime(RTCDriver *rtcp, RTCDateTime *timespec) { + + osalDbgCheck((rtcp != NULL) && (timespec != NULL)); + + rtc_lld_get_time(rtcp, timespec); +} + +#if (RTC_ALARMS > 0) || defined(__DOXYGEN__) +/** + * @brief Set alarm time. + * @note This function can be called from any context but limitations + * could be imposed by the low level implementation. It is + * guaranteed that the function can be called from thread + * context. + * @note The function can be reentrant or not reentrant depending on + * the low level implementation. + * + * @param[in] rtcp pointer to RTC driver structure + * @param[in] alarm alarm identifier + * @param[in] alarmspec pointer to a @p RTCAlarm structure or @p NULL + * + * @special + */ +void rtcSetAlarm(RTCDriver *rtcp, + rtcalarm_t alarm, + const RTCAlarm *alarmspec) { + + osalDbgCheck((rtcp != NULL) && (alarm < (rtcalarm_t)RTC_ALARMS)); + + rtc_lld_set_alarm(rtcp, alarm, alarmspec); +} + +/** + * @brief Get current alarm. + * @note If an alarm has not been set then the returned alarm specification + * is not meaningful. + * @note This function can be called from any context but limitations + * could be imposed by the low level implementation. It is + * guaranteed that the function can be called from thread + * context. + * @note The function can be reentrant or not reentrant depending on + * the low level implementation. + * + * @param[in] rtcp pointer to RTC driver structure + * @param[in] alarm alarm identifier + * @param[out] alarmspec pointer to a @p RTCAlarm structure + * + * @special + */ +void rtcGetAlarm(RTCDriver *rtcp, + rtcalarm_t alarm, + RTCAlarm *alarmspec) { + + osalDbgCheck((rtcp != NULL) && + (alarm < (rtcalarm_t)RTC_ALARMS) && + (alarmspec != NULL)); + + rtc_lld_get_alarm(rtcp, alarm, alarmspec); +} +#endif /* RTC_ALARMS > 0 */ + +#if (RTC_SUPPORTS_CALLBACKS == TRUE) || defined(__DOXYGEN__) +/** + * @brief Enables or disables RTC callbacks. + * @details This function enables or disables the callback, use a @p NULL + * pointer in order to disable it. + * @note This function can be called from any context but limitations + * could be imposed by the low level implementation. It is + * guaranteed that the function can be called from thread + * context. + * @note The function can be reentrant or not reentrant depending on + * the low level implementation. + * + * @param[in] rtcp pointer to RTC driver structure + * @param[in] callback callback function pointer or @p NULL + * + * @special + */ +void rtcSetCallback(RTCDriver *rtcp, rtccb_t callback) { + + osalDbgCheck(rtcp != NULL); + + rtc_lld_set_callback(rtcp, callback); +} +#endif /* RTC_SUPPORTS_CALLBACKS == TRUE */ + +/** + * @brief Convert @p RTCDateTime to broken-down time structure. + * + * @param[in] timespec pointer to a @p RTCDateTime structure + * @param[out] timp pointer to a broken-down time structure + * @param[out] tv_msec pointer to milliseconds value or @p NULL + * + * @api + */ +void rtcConvertDateTimeToStructTm(const RTCDateTime *timespec, + struct tm *timp, + uint32_t *tv_msec) { + int sec; + + timp->tm_year = (int)timespec->year + (1980 - 1900); + timp->tm_mon = (int)timespec->month - 1; + timp->tm_mday = (int)timespec->day; + timp->tm_isdst = (int)timespec->dstflag; + timp->tm_wday = (int)timespec->dayofweek - 1; + + sec = (int)timespec->millisecond / 1000; + timp->tm_hour = sec / 3600; + sec %= 3600; + timp->tm_min = sec / 60; + timp->tm_sec = sec % 60; + + if (NULL != tv_msec) { + *tv_msec = (uint32_t)timespec->millisecond % 1000U; + } +} + +/** + * @brief Convert broken-down time structure to @p RTCDateTime. + * + * @param[in] timp pointer to a broken-down time structure + * @param[in] tv_msec milliseconds value + * @param[out] timespec pointer to a @p RTCDateTime structure + * + * @api + */ +void rtcConvertStructTmToDateTime(const struct tm *timp, + uint32_t tv_msec, + RTCDateTime *timespec) { + + /*lint -save -e9034 [10.4] Verified assignments to bit fields.*/ + timespec->year = (uint32_t)timp->tm_year - (1980U - 1900U); + timespec->month = (uint32_t)timp->tm_mon + 1U; + timespec->day = (uint32_t)timp->tm_mday; + timespec->dayofweek = (uint32_t)timp->tm_wday + 1U; + if (-1 == timp->tm_isdst) { + timespec->dstflag = 0U; /* set zero if dst is unknown */ + } + else { + timespec->dstflag = (uint32_t)timp->tm_isdst; + } + /*lint -restore*/ + /*lint -save -e9033 [10.8] Verified assignments to bit fields.*/ + timespec->millisecond = tv_msec + (uint32_t)(((timp->tm_hour * 3600) + + (timp->tm_min * 60) + + timp->tm_sec) * 1000); + /*lint -restore*/ +} + +/** + * @brief Get current time in format suitable for usage in FAT file system. + * @note The information about day of week and DST is lost in DOS + * format, the second field loses its least significant bit. + * + * @param[out] timespec pointer to a @p RTCDateTime structure + * @return FAT date/time value. + * + * @api + */ +uint32_t rtcConvertDateTimeToFAT(const RTCDateTime *timespec) { + uint32_t fattime; + uint32_t sec, min, hour, day, month; + + sec = timespec->millisecond / 1000U; + hour = sec / 3600U; + sec %= 3600U; + min = sec / 60U; + sec %= 60U; + day = timespec->day; + month = timespec->month; + + /* handle DST flag */ + if (1U == timespec->dstflag) { + hour += 1U; + if (hour == 24U) { + hour = 0U; + day += 1U; + if (day > month_len[month - 1U]) { + day = 1U; + month += 1U; + } + } + } + + fattime = sec >> 1U; + fattime |= min << 5U; + fattime |= hour << 11U; + fattime |= day << 16U; + fattime |= month << 21U; + fattime |= (uint32_t)timespec->year << 25U; + + return fattime; +} + +#endif /* HAL_USE_RTC == TRUE */ + +/** @} */ diff --git a/os/hal/src/hal_sdc.c b/os/hal/src/hal_sdc.c new file mode 100644 index 000000000..bd2c0bef6 --- /dev/null +++ b/os/hal/src/hal_sdc.c @@ -0,0 +1,1005 @@ +/* + ChibiOS - Copyright (C) 2006..2016 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 sdc.c + * @brief SDC Driver code. + * + * @addtogroup SDC + * @{ + */ + +#include + +#include "hal.h" + +#if (HAL_USE_SDC == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/** + * @brief MMC switch mode. + */ +typedef enum { + MMC_SWITCH_COMMAND_SET = 0, + MMC_SWITCH_SET_BITS = 1, + MMC_SWITCH_CLEAR_BITS = 2, + MMC_SWITCH_WRITE_BYTE = 3 +} mmc_switch_t; + +/** + * @brief SDC switch mode. + */ +typedef enum { + SD_SWITCH_CHECK = 0, + SD_SWITCH_SET = 1 +} sd_switch_t; + +/** + * @brief SDC switch function. + */ +typedef enum { + SD_SWITCH_FUNCTION_SPEED = 0, + SD_SWITCH_FUNCTION_CMD_SYSTEM = 1, + SD_SWITCH_FUNCTION_DRIVER_STRENGTH = 2, + SD_SWITCH_FUNCTION_CURRENT_LIMIT = 3 +} sd_switch_function_t; + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/** + * @brief Virtual methods table. + */ +static const struct SDCDriverVMT sdc_vmt = { + (bool (*)(void *))sdc_lld_is_card_inserted, + (bool (*)(void *))sdc_lld_is_write_protected, + (bool (*)(void *))sdcConnect, + (bool (*)(void *))sdcDisconnect, + (bool (*)(void *, uint32_t, uint8_t *, uint32_t))sdcRead, + (bool (*)(void *, uint32_t, const uint8_t *, uint32_t))sdcWrite, + (bool (*)(void *))sdcSync, + (bool (*)(void *, BlockDeviceInfo *))sdcGetInfo +}; + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ +/** + * @brief Detects card mode. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * + * @return The operation status. + * @retval HAL_SUCCESS operation succeeded. + * @retval HAL_FAILED operation failed. + * + * @notapi + */ +static bool mode_detect(SDCDriver *sdcp) { + uint32_t resp[1]; + + /* V2.0 cards detection.*/ + if (!sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_SEND_IF_COND, + MMCSD_CMD8_PATTERN, resp)) { + sdcp->cardmode = SDC_MODE_CARDTYPE_SDV20; + /* Voltage verification.*/ + if (((resp[0] >> 8U) & 0xFU) != 1U) { + return HAL_FAILED; + } + if (sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_APP_CMD, 0, resp) || + MMCSD_R1_ERROR(resp[0])) { + return HAL_FAILED; + } + } + else { + /* MMC or SD V1.1 detection.*/ + if (sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_APP_CMD, 0, resp) || + MMCSD_R1_ERROR(resp[0])) { + sdcp->cardmode = SDC_MODE_CARDTYPE_MMC; + } + else { + sdcp->cardmode = SDC_MODE_CARDTYPE_SDV11; + + /* Reset error flag illegal command.*/ + sdc_lld_send_cmd_none(sdcp, MMCSD_CMD_GO_IDLE_STATE, 0); + } + } + + return HAL_SUCCESS; +} + +/** + * @brief Init procedure for MMC. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * + * @return The operation status. + * @retval HAL_SUCCESS operation succeeded. + * @retval HAL_FAILED operation failed. + * + * @notapi + */ +static bool mmc_init(SDCDriver *sdcp) { + uint32_t ocr; + unsigned i; + uint32_t resp[1]; + + ocr = 0xC0FF8000U; + i = 0; + while (true) { + if (sdc_lld_send_cmd_short(sdcp, MMCSD_CMD_INIT, ocr, resp)) { + return HAL_FAILED; + } + if ((resp[0] & 0x80000000U) != 0U) { + if ((resp[0] & 0x40000000U) != 0U) { + sdcp->cardmode |= SDC_MODE_HIGH_CAPACITY; + } + break; + } + if (++i >= (unsigned)SDC_INIT_RETRY) { + return HAL_FAILED; + } + osalThreadSleepMilliseconds(10); + } + + return HAL_SUCCESS; +} + +/** + * @brief Init procedure for SDC. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * + * @return The operation status. + * @retval HAL_SUCCESS operation succeeded. + * @retval HAL_FAILED operation failed. + * + * @notapi + */ +static bool sdc_init(SDCDriver *sdcp) { + unsigned i; + uint32_t ocr; + uint32_t resp[1]; + + if ((sdcp->cardmode & SDC_MODE_CARDTYPE_MASK) == SDC_MODE_CARDTYPE_SDV20) { + ocr = 0xC0100000U; + } + else { + ocr = 0x80100000U; + } + + i = 0; + while (true) { + if (sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_APP_CMD, 0, resp) || + MMCSD_R1_ERROR(resp[0])) { + return HAL_FAILED; + } + if (sdc_lld_send_cmd_short(sdcp, MMCSD_CMD_APP_OP_COND, ocr, resp)) { + return HAL_FAILED; + } + if ((resp[0] & 0x80000000U) != 0U) { + if ((resp[0] & 0x40000000U) != 0U) { + sdcp->cardmode |= SDC_MODE_HIGH_CAPACITY; + } + break; + } + if (++i >= (unsigned)SDC_INIT_RETRY) { + return HAL_FAILED; + } + osalThreadSleepMilliseconds(10); + } + + return HAL_SUCCESS; +} + +/** + * @brief Constructs CMD6 argument for MMC. + * + * @param[in] access EXT_CSD access mode + * @param[in] idx EXT_CSD byte number + * @param[in] value value to be written in target field + * @param[in] cmd_set switch current command set + * + * @return CMD6 argument. + * + * @notapi + */ +static uint32_t mmc_cmd6_construct(mmc_switch_t access, uint32_t idx, + uint32_t value, uint32_t cmd_set) { + + osalDbgAssert(idx <= 191U, "This field is not writable"); + osalDbgAssert(cmd_set < 8U, "This field has only 3 bits"); + + return ((uint32_t)access << 24U) | (idx << 16U) | (value << 8U) | cmd_set; +} + +/** + * @brief Constructs CMD6 argument for SDC. + * + * @param[in] mode switch/test mode + * @param[in] function function number to be switched + * @param[in] value value to be written in target function + * + * @return CMD6 argument. + * + * @notapi + */ +static uint32_t sdc_cmd6_construct(sd_switch_t mode, + sd_switch_function_t function, + uint32_t value) { + uint32_t ret = 0xFFFFFF; + + osalDbgAssert((value < 16U), "This field has only 4 bits"); + + ret &= ~((uint32_t)0xFU << ((uint32_t)function * 4U)); + ret |= value << ((uint32_t)function * 4U); + return ret | ((uint32_t)mode << 31U); +} + +/** + * @brief Extracts information from CMD6 answer. + * + * @param[in] function function number to be switched + * @param[in] buf buffer with answer + * + * @return extracted answer. + * + * @notapi + */ +static uint16_t sdc_cmd6_extract_info(sd_switch_function_t function, + const uint8_t *buf) { + + unsigned start = 12U - ((unsigned)function * 2U); + + return ((uint16_t)buf[start] << 8U) | (uint16_t)buf[start + 1U]; +} + +/** + * @brief Checks status after switching using CMD6. + * + * @param[in] function function number to be switched + * @param[in] buf buffer with answer + * + * @return The operation status. + * @retval HAL_SUCCESS operation succeeded. + * @retval HAL_FAILED operation failed. + * + * @notapi + */ +static bool sdc_cmd6_check_status(sd_switch_function_t function, + const uint8_t *buf) { + + uint32_t tmp; + uint32_t status; + + tmp = ((uint32_t)buf[14] << 16U) | + ((uint32_t)buf[15] << 8U) | + (uint32_t)buf[16]; + status = (tmp >> ((uint32_t)function * 4U)) & 0xFU; + if (0xFU != status) { + return HAL_SUCCESS; + } + return HAL_FAILED; +} + +/** + * @brief Reads supported bus clock and switch SDC to appropriate mode. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * @param[out] clk pointer to clock enum + * + * @return The operation status. + * @retval HAL_SUCCESS operation succeeded. + * @retval HAL_FAILED operation failed. + * + * @notapi + */ +static bool sdc_detect_bus_clk(SDCDriver *sdcp, sdcbusclk_t *clk) { + uint32_t cmdarg; + const size_t N = 64; + uint8_t tmp[N]; + + /* Safe default.*/ + *clk = SDC_CLK_25MHz; + + /* Looks like only "high capacity" cards produce meaningful results during + this clock detection procedure.*/ + if (0U == _mmcsd_get_slice(sdcp->csd, MMCSD_CSD_10_CSD_STRUCTURE_SLICE)) { + *clk = SDC_CLK_25MHz; + return HAL_SUCCESS; + } + + /* Read switch functions' register.*/ + if (sdc_lld_read_special(sdcp, tmp, N, MMCSD_CMD_SWITCH, 0)) { + return HAL_FAILED; + } + + /* Check card capabilities parsing acquired data.*/ + if ((sdc_cmd6_extract_info(SD_SWITCH_FUNCTION_SPEED, tmp) & 2U) == 2U) { + /* Construct command to set the bus speed.*/ + cmdarg = sdc_cmd6_construct(SD_SWITCH_SET, SD_SWITCH_FUNCTION_SPEED, 1); + + /* Write constructed command and read operation status in single call.*/ + if (sdc_lld_read_special(sdcp, tmp, N, MMCSD_CMD_SWITCH, cmdarg)) { + return HAL_FAILED; + } + + /* Check card answer for success status bits.*/ + if (HAL_SUCCESS == sdc_cmd6_check_status(SD_SWITCH_FUNCTION_SPEED, tmp)) { + *clk = SDC_CLK_50MHz; + } + else { + *clk = SDC_CLK_25MHz; + } + } + + return HAL_SUCCESS; +} + +/** + * @brief Reads supported bus clock and switch MMC to appropriate mode. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * @param[out] clk pointer to clock enum + * + * @return The operation status. + * @retval HAL_SUCCESS operation succeeded. + * @retval HAL_FAILED operation failed. + * + * @notapi + */ +static bool mmc_detect_bus_clk(SDCDriver *sdcp, sdcbusclk_t *clk) { + uint32_t cmdarg; + uint32_t resp[1]; + uint8_t *scratchpad = sdcp->config->scratchpad; + + /* Safe default.*/ + *clk = SDC_CLK_25MHz; + + /* Use safe default when there is no space for data.*/ + if (NULL == scratchpad) { + return HAL_SUCCESS; + } + + cmdarg = mmc_cmd6_construct(MMC_SWITCH_WRITE_BYTE, 185, 1, 0); + if (!(sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_SWITCH, cmdarg, resp) || + MMCSD_R1_ERROR(resp[0]))) { + *clk = SDC_CLK_50MHz; + } + + return HAL_SUCCESS; +} + +/** + * @brief Reads supported bus clock and switch card to appropriate mode. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * @param[out] clk pointer to clock enum + * + * @return The operation status. + * @retval HAL_SUCCESS operation succeeded. + * @retval HAL_FAILED operation failed. + * + * @notapi + */ +static bool detect_bus_clk(SDCDriver *sdcp, sdcbusclk_t *clk) { + + if (SDC_MODE_CARDTYPE_MMC == (sdcp->cardmode & SDC_MODE_CARDTYPE_MASK)) { + return mmc_detect_bus_clk(sdcp, clk); + } + return sdc_detect_bus_clk(sdcp, clk); +} + +/** + * @brief Sets bus width for SDC. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * + * @return The operation status. + * @retval HAL_SUCCESS operation succeeded. + * @retval HAL_FAILED operation failed. + * + * @notapi + */ +static bool sdc_set_bus_width(SDCDriver *sdcp) { + uint32_t resp[1]; + + if (SDC_MODE_1BIT == sdcp->config->bus_width) { + /* Nothing to do. Bus is already in 1bit mode.*/ + return HAL_SUCCESS; + } + else if (SDC_MODE_4BIT == sdcp->config->bus_width) { + sdc_lld_set_bus_mode(sdcp, SDC_MODE_4BIT); + if (sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_APP_CMD, sdcp->rca, resp) || + MMCSD_R1_ERROR(resp[0])) { + return HAL_FAILED; + } + + if (sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_SET_BUS_WIDTH, 2, resp) || + MMCSD_R1_ERROR(resp[0])) { + return HAL_FAILED; + } + } + else { + /* SD card does not support 8bit bus.*/ + return HAL_FAILED; + } + + return HAL_SUCCESS; +} + +/** + * @brief Sets bus width for MMC. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * + * @return The operation status. + * @retval HAL_SUCCESS operation succeeded. + * @retval HAL_FAILED operation failed. + * + * @notapi + */ +static bool mmc_set_bus_width(SDCDriver *sdcp) { + uint32_t resp[1]; + uint32_t cmdarg = mmc_cmd6_construct(MMC_SWITCH_WRITE_BYTE, 183, 0, 0); + + switch(sdcp->config->bus_width){ + case SDC_MODE_1BIT: + /* Nothing to do. Bus is already in 1bit mode.*/ + return HAL_SUCCESS; + case SDC_MODE_4BIT: + cmdarg = mmc_cmd6_construct(MMC_SWITCH_WRITE_BYTE, 183, 1, 0); + break; + case SDC_MODE_8BIT: + cmdarg = mmc_cmd6_construct(MMC_SWITCH_WRITE_BYTE, 183, 2, 0); + break; + default: + osalDbgAssert(false, "unexpected case"); + break; + } + + sdc_lld_set_bus_mode(sdcp, sdcp->config->bus_width); + if (sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_SWITCH, cmdarg, resp) || + MMCSD_R1_ERROR(resp[0])) { + return HAL_FAILED; + } + + return HAL_SUCCESS; +} + +/** + * @brief Wait for the card to complete pending operations. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * + * @return The operation status. + * @retval HAL_SUCCESS operation succeeded. + * @retval HAL_FAILED operation failed. + * + * @notapi + */ +bool _sdc_wait_for_transfer_state(SDCDriver *sdcp) { + uint32_t resp[1]; + + while (true) { + if (sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_SEND_STATUS, + sdcp->rca, resp) || + MMCSD_R1_ERROR(resp[0])) { + return HAL_FAILED; + } + + switch (MMCSD_R1_STS(resp[0])) { + case MMCSD_STS_TRAN: + return HAL_SUCCESS; + case MMCSD_STS_DATA: + case MMCSD_STS_RCV: + case MMCSD_STS_PRG: +#if SDC_NICE_WAITING == TRUE + osalThreadSleepMilliseconds(1); +#endif + continue; + default: + /* The card should have been initialized so any other state is not + valid and is reported as an error.*/ + return HAL_FAILED; + } + } +} + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief SDC Driver initialization. + * @note This function is implicitly invoked by @p halInit(), there is + * no need to explicitly initialize the driver. + * + * @init + */ +void sdcInit(void) { + + sdc_lld_init(); +} + +/** + * @brief Initializes the standard part of a @p SDCDriver structure. + * + * @param[out] sdcp pointer to the @p SDCDriver object + * + * @init + */ +void sdcObjectInit(SDCDriver *sdcp) { + + sdcp->vmt = &sdc_vmt; + sdcp->state = BLK_STOP; + sdcp->errors = SDC_NO_ERROR; + sdcp->config = NULL; + sdcp->capacity = 0; +} + +/** + * @brief Configures and activates the SDC peripheral. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * @param[in] config pointer to the @p SDCConfig object, can be @p NULL if + * the driver supports a default configuration or + * requires no configuration + * + * @api + */ +void sdcStart(SDCDriver *sdcp, const SDCConfig *config) { + + osalDbgCheck(sdcp != NULL); + + osalSysLock(); + osalDbgAssert((sdcp->state == BLK_STOP) || (sdcp->state == BLK_ACTIVE), + "invalid state"); + sdcp->config = config; + sdc_lld_start(sdcp); + sdcp->state = BLK_ACTIVE; + osalSysUnlock(); +} + +/** + * @brief Deactivates the SDC peripheral. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * + * @api + */ +void sdcStop(SDCDriver *sdcp) { + + osalDbgCheck(sdcp != NULL); + + osalSysLock(); + osalDbgAssert((sdcp->state == BLK_STOP) || (sdcp->state == BLK_ACTIVE), + "invalid state"); + sdc_lld_stop(sdcp); + sdcp->state = BLK_STOP; + osalSysUnlock(); +} + +/** + * @brief Performs the initialization procedure on the inserted card. + * @details This function should be invoked when a card is inserted and + * brings the driver in the @p BLK_READY state where it is possible + * to perform read and write operations. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * + * @return The operation status. + * @retval HAL_SUCCESS operation succeeded. + * @retval HAL_FAILED operation failed. + * + * @api + */ +bool sdcConnect(SDCDriver *sdcp) { + uint32_t resp[1]; + sdcbusclk_t clk = SDC_CLK_25MHz; + + osalDbgCheck(sdcp != NULL); + osalDbgAssert((sdcp->state == BLK_ACTIVE) || (sdcp->state == BLK_READY), + "invalid state"); + + /* Connection procedure in progress.*/ + sdcp->state = BLK_CONNECTING; + + /* Card clock initialization.*/ + sdc_lld_start_clk(sdcp); + + /* Enforces the initial card state.*/ + sdc_lld_send_cmd_none(sdcp, MMCSD_CMD_GO_IDLE_STATE, 0); + + /* Detect card type.*/ + if (HAL_FAILED == mode_detect(sdcp)) { + goto failed; + } + + /* Perform specific initialization procedure.*/ + if ((sdcp->cardmode & SDC_MODE_CARDTYPE_MASK) == SDC_MODE_CARDTYPE_MMC) { + if (HAL_FAILED == mmc_init(sdcp)) { + goto failed; + } + } + else { + if (HAL_FAILED == sdc_init(sdcp)) { + goto failed; + } + } + + /* Reads CID.*/ + if (sdc_lld_send_cmd_long_crc(sdcp, MMCSD_CMD_ALL_SEND_CID, 0, sdcp->cid)) { + goto failed; + } + + /* Asks for the RCA.*/ + if (sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_SEND_RELATIVE_ADDR, + 0, &sdcp->rca)) { + goto failed; + } + + /* Reads CSD.*/ + if (sdc_lld_send_cmd_long_crc(sdcp, MMCSD_CMD_SEND_CSD, + sdcp->rca, sdcp->csd)) { + goto failed; + } + + /* Selects the card for operations.*/ + if (sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_SEL_DESEL_CARD, + sdcp->rca, resp)) { + goto failed; + } + + /* Switches to high speed.*/ + if (HAL_SUCCESS != detect_bus_clk(sdcp, &clk)) { + goto failed; + } + sdc_lld_set_data_clk(sdcp, clk); + + /* Reads extended CSD if needed and possible.*/ + if (SDC_MODE_CARDTYPE_MMC == (sdcp->cardmode & SDC_MODE_CARDTYPE_MASK)) { + + /* The card is a MMC, checking if it is a large device.*/ + if (_mmcsd_get_slice(sdcp->csd, MMCSD_CSD_MMC_CSD_STRUCTURE_SLICE) > 1U) { + uint8_t *ext_csd = sdcp->config->scratchpad; + + /* Size detection requires the buffer.*/ + if (NULL == ext_csd) { + goto failed; + } + + if(sdc_lld_read_special(sdcp, ext_csd, 512, MMCSD_CMD_SEND_EXT_CSD, 0)) { + goto failed; + } + + /* Capacity from the EXT_CSD.*/ + sdcp->capacity = _mmcsd_get_capacity_ext(ext_csd); + } + else { + /* Capacity from the normal CSD.*/ + sdcp->capacity = _mmcsd_get_capacity(sdcp->csd); + } + } + else { + /* The card is an SDC, capacity from the normal CSD.*/ + sdcp->capacity = _mmcsd_get_capacity(sdcp->csd); + } + + /* Block length fixed at 512 bytes.*/ + if (sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_SET_BLOCKLEN, + MMCSD_BLOCK_SIZE, resp) || + MMCSD_R1_ERROR(resp[0])) { + goto failed; + } + + /* Switches to wide bus mode.*/ + switch (sdcp->cardmode & SDC_MODE_CARDTYPE_MASK) { + case SDC_MODE_CARDTYPE_SDV11: + case SDC_MODE_CARDTYPE_SDV20: + if (HAL_FAILED == sdc_set_bus_width(sdcp)) { + goto failed; + } + break; + case SDC_MODE_CARDTYPE_MMC: + if (HAL_FAILED == mmc_set_bus_width(sdcp)) { + goto failed; + } + break; + default: + /* Unknown type.*/ + goto failed; + } + + /* Initialization complete.*/ + sdcp->state = BLK_READY; + return HAL_SUCCESS; + + /* Connection failed, state reset to BLK_ACTIVE.*/ +failed: + sdc_lld_stop_clk(sdcp); + sdcp->state = BLK_ACTIVE; + return HAL_FAILED; +} + +/** + * @brief Brings the driver in a state safe for card removal. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * + * @return The operation status. + * @retval HAL_SUCCESS operation succeeded. + * @retval HAL_FAILED operation failed. + * + * @api + */ +bool sdcDisconnect(SDCDriver *sdcp) { + + osalDbgCheck(sdcp != NULL); + + osalSysLock(); + osalDbgAssert((sdcp->state == BLK_ACTIVE) || (sdcp->state == BLK_READY), + "invalid state"); + if (sdcp->state == BLK_ACTIVE) { + osalSysUnlock(); + return HAL_SUCCESS; + } + sdcp->state = BLK_DISCONNECTING; + osalSysUnlock(); + + /* Waits for eventual pending operations completion.*/ + if (_sdc_wait_for_transfer_state(sdcp)) { + sdc_lld_stop_clk(sdcp); + sdcp->state = BLK_ACTIVE; + return HAL_FAILED; + } + + /* Card clock stopped.*/ + sdc_lld_stop_clk(sdcp); + sdcp->state = BLK_ACTIVE; + return HAL_SUCCESS; +} + +/** + * @brief Reads one or more blocks. + * @pre The driver must be in the @p BLK_READY state after a successful + * sdcConnect() invocation. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * @param[in] startblk first block to read + * @param[out] buf pointer to the read buffer + * @param[in] n number of blocks to read + * + * @return The operation status. + * @retval HAL_SUCCESS operation succeeded. + * @retval HAL_FAILED operation failed. + * + * @api + */ +bool sdcRead(SDCDriver *sdcp, uint32_t startblk, uint8_t *buf, uint32_t n) { + bool status; + + osalDbgCheck((sdcp != NULL) && (buf != NULL) && (n > 0U)); + osalDbgAssert(sdcp->state == BLK_READY, "invalid state"); + + if ((startblk + n - 1U) > sdcp->capacity){ + sdcp->errors |= SDC_OVERFLOW_ERROR; + return HAL_FAILED; + } + + /* Read operation in progress.*/ + sdcp->state = BLK_READING; + + status = sdc_lld_read(sdcp, startblk, buf, n); + + /* Read operation finished.*/ + sdcp->state = BLK_READY; + return status; +} + +/** + * @brief Writes one or more blocks. + * @pre The driver must be in the @p BLK_READY state after a successful + * sdcConnect() invocation. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * @param[in] startblk first block to write + * @param[out] buf pointer to the write buffer + * @param[in] n number of blocks to write + * + * @return The operation status. + * @retval HAL_SUCCESS operation succeeded. + * @retval HAL_FAILED operation failed. + * + * @api + */ +bool sdcWrite(SDCDriver *sdcp, uint32_t startblk, + const uint8_t *buf, uint32_t n) { + bool status; + + osalDbgCheck((sdcp != NULL) && (buf != NULL) && (n > 0U)); + osalDbgAssert(sdcp->state == BLK_READY, "invalid state"); + + if ((startblk + n - 1U) > sdcp->capacity){ + sdcp->errors |= SDC_OVERFLOW_ERROR; + return HAL_FAILED; + } + + /* Write operation in progress.*/ + sdcp->state = BLK_WRITING; + + status = sdc_lld_write(sdcp, startblk, buf, n); + + /* Write operation finished.*/ + sdcp->state = BLK_READY; + return status; +} + +/** + * @brief Returns the errors mask associated to the previous operation. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * @return The errors mask. + * + * @api + */ +sdcflags_t sdcGetAndClearErrors(SDCDriver *sdcp) { + sdcflags_t flags; + + osalDbgCheck(sdcp != NULL); + osalDbgAssert(sdcp->state == BLK_READY, "invalid state"); + + osalSysLock(); + flags = sdcp->errors; + sdcp->errors = SDC_NO_ERROR; + osalSysUnlock(); + return flags; +} + +/** + * @brief Waits for card idle condition. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * + * @return The operation status. + * @retval HAL_SUCCESS the operation succeeded. + * @retval HAL_FAILED the operation failed. + * + * @api + */ +bool sdcSync(SDCDriver *sdcp) { + bool result; + + osalDbgCheck(sdcp != NULL); + + if (sdcp->state != BLK_READY) { + return HAL_FAILED; + } + + /* Synchronization operation in progress.*/ + sdcp->state = BLK_SYNCING; + + result = sdc_lld_sync(sdcp); + + /* Synchronization operation finished.*/ + sdcp->state = BLK_READY; + return result; +} + +/** + * @brief Returns the media info. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * @param[out] bdip pointer to a @p BlockDeviceInfo structure + * + * @return The operation status. + * @retval HAL_SUCCESS the operation succeeded. + * @retval HAL_FAILED the operation failed. + * + * @api + */ +bool sdcGetInfo(SDCDriver *sdcp, BlockDeviceInfo *bdip) { + + osalDbgCheck((sdcp != NULL) && (bdip != NULL)); + + if (sdcp->state != BLK_READY) { + return HAL_FAILED; + } + + bdip->blk_num = sdcp->capacity; + bdip->blk_size = MMCSD_BLOCK_SIZE; + + return HAL_SUCCESS; +} + +/** + * @brief Erases the supplied blocks. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * @param[in] startblk starting block number + * @param[in] endblk ending block number + * + * @return The operation status. + * @retval HAL_SUCCESS the operation succeeded. + * @retval HAL_FAILED the operation failed. + * + * @api + */ +bool sdcErase(SDCDriver *sdcp, uint32_t startblk, uint32_t endblk) { + uint32_t resp[1]; + + osalDbgCheck((sdcp != NULL)); + osalDbgAssert(sdcp->state == BLK_READY, "invalid state"); + + /* Erase operation in progress.*/ + sdcp->state = BLK_WRITING; + + /* Handling command differences between HC and normal cards.*/ + if ((sdcp->cardmode & SDC_MODE_HIGH_CAPACITY) != 0U) { + startblk *= MMCSD_BLOCK_SIZE; + endblk *= MMCSD_BLOCK_SIZE; + } + + if (_sdc_wait_for_transfer_state(sdcp)) { + goto failed; + } + + if ((sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_ERASE_RW_BLK_START, + startblk, resp) != HAL_SUCCESS) || + MMCSD_R1_ERROR(resp[0])) { + goto failed; + } + + if ((sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_ERASE_RW_BLK_END, + endblk, resp) != HAL_SUCCESS) || + MMCSD_R1_ERROR(resp[0])) { + goto failed; + } + + if ((sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_ERASE, + 0, resp) != HAL_SUCCESS) || + MMCSD_R1_ERROR(resp[0])) { + goto failed; + } + + /* Quick sleep to allow it to transition to programming or receiving state */ + /* TODO: ??????????????????????????? */ + + /* Wait for it to return to transfer state to indicate it has finished erasing */ + if (_sdc_wait_for_transfer_state(sdcp)) { + goto failed; + } + + sdcp->state = BLK_READY; + return HAL_SUCCESS; + +failed: + sdcp->state = BLK_READY; + return HAL_FAILED; +} + +#endif /* HAL_USE_SDC == TRUE */ + +/** @} */ + diff --git a/os/hal/src/hal_serial.c b/os/hal/src/hal_serial.c new file mode 100644 index 000000000..a0956ba9a --- /dev/null +++ b/os/hal/src/hal_serial.c @@ -0,0 +1,289 @@ +/* + ChibiOS - Copyright (C) 2006..2016 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 serial.c + * @brief Serial Driver code. + * + * @addtogroup SERIAL + * @{ + */ + +#include "hal.h" + +#if (HAL_USE_SERIAL == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/* + * Interface implementation, the following functions just invoke the equivalent + * queue-level function or macro. + */ + +static size_t write(void *ip, const uint8_t *bp, size_t n) { + + return oqWriteTimeout(&((SerialDriver *)ip)->oqueue, bp, + n, TIME_INFINITE); +} + +static size_t read(void *ip, uint8_t *bp, size_t n) { + + return iqReadTimeout(&((SerialDriver *)ip)->iqueue, bp, + n, TIME_INFINITE); +} + +static msg_t put(void *ip, uint8_t b) { + + return oqPutTimeout(&((SerialDriver *)ip)->oqueue, b, TIME_INFINITE); +} + +static msg_t get(void *ip) { + + return iqGetTimeout(&((SerialDriver *)ip)->iqueue, TIME_INFINITE); +} + +static msg_t putt(void *ip, uint8_t b, systime_t timeout) { + + return oqPutTimeout(&((SerialDriver *)ip)->oqueue, b, timeout); +} + +static msg_t gett(void *ip, systime_t timeout) { + + return iqGetTimeout(&((SerialDriver *)ip)->iqueue, timeout); +} + +static size_t writet(void *ip, const uint8_t *bp, size_t n, systime_t timeout) { + + return oqWriteTimeout(&((SerialDriver *)ip)->oqueue, bp, n, timeout); +} + +static size_t readt(void *ip, uint8_t *bp, size_t n, systime_t timeout) { + + return iqReadTimeout(&((SerialDriver *)ip)->iqueue, bp, n, timeout); +} + +static const struct SerialDriverVMT vmt = { + write, read, put, get, + putt, gett, writet, readt +}; + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Serial Driver initialization. + * @note This function is implicitly invoked by @p halInit(), there is + * no need to explicitly initialize the driver. + * + * @init + */ +void sdInit(void) { + + sd_lld_init(); +} + +/** + * @brief Initializes a generic full duplex driver object. + * @details The HW dependent part of the initialization has to be performed + * outside, usually in the hardware initialization code. + * + * @param[out] sdp pointer to a @p SerialDriver structure + * @param[in] inotify pointer to a callback function that is invoked when + * some data is read from the Queue. The value can be + * @p NULL. + * @param[in] onotify pointer to a callback function that is invoked when + * some data is written in the Queue. The value can be + * @p NULL. + * + * @init + */ +void sdObjectInit(SerialDriver *sdp, qnotify_t inotify, qnotify_t onotify) { + + sdp->vmt = &vmt; + osalEventObjectInit(&sdp->event); + sdp->state = SD_STOP; + iqObjectInit(&sdp->iqueue, sdp->ib, SERIAL_BUFFERS_SIZE, inotify, sdp); + oqObjectInit(&sdp->oqueue, sdp->ob, SERIAL_BUFFERS_SIZE, onotify, sdp); +} + +/** + * @brief Configures and starts the driver. + * + * @param[in] sdp pointer to a @p SerialDriver object + * @param[in] config the architecture-dependent serial driver configuration. + * If this parameter is set to @p NULL then a default + * configuration is used. + * + * @api + */ +void sdStart(SerialDriver *sdp, const SerialConfig *config) { + + osalDbgCheck(sdp != NULL); + + osalSysLock(); + osalDbgAssert((sdp->state == SD_STOP) || (sdp->state == SD_READY), + "invalid state"); + sd_lld_start(sdp, config); + sdp->state = SD_READY; + osalSysUnlock(); +} + +/** + * @brief Stops the driver. + * @details Any thread waiting on the driver's queues will be awakened with + * the message @p MSG_RESET. + * + * @param[in] sdp pointer to a @p SerialDriver object + * + * @api + */ +void sdStop(SerialDriver *sdp) { + + osalDbgCheck(sdp != NULL); + + osalSysLock(); + osalDbgAssert((sdp->state == SD_STOP) || (sdp->state == SD_READY), + "invalid state"); + sd_lld_stop(sdp); + sdp->state = SD_STOP; + oqResetI(&sdp->oqueue); + iqResetI(&sdp->iqueue); + osalOsRescheduleS(); + osalSysUnlock(); +} + +/** + * @brief Handles incoming data. + * @details This function must be called from the input interrupt service + * routine in order to enqueue incoming data and generate the + * related events. + * @note The incoming data event is only generated when the input queue + * becomes non-empty. + * @note In order to gain some performance it is suggested to not use + * this function directly but copy this code directly into the + * interrupt service routine. + * + * @param[in] sdp pointer to a @p SerialDriver structure + * @param[in] b the byte to be written in the driver's Input Queue + * + * @iclass + */ +void sdIncomingDataI(SerialDriver *sdp, uint8_t b) { + + osalDbgCheckClassI(); + osalDbgCheck(sdp != NULL); + + if (iqIsEmptyI(&sdp->iqueue)) + chnAddFlagsI(sdp, CHN_INPUT_AVAILABLE); + if (iqPutI(&sdp->iqueue, b) < MSG_OK) + chnAddFlagsI(sdp, SD_OVERRUN_ERROR); +} + +/** + * @brief Handles outgoing data. + * @details Must be called from the output interrupt service routine in order + * to get the next byte to be transmitted. + * @note In order to gain some performance it is suggested to not use + * this function directly but copy this code directly into the + * interrupt service routine. + * + * @param[in] sdp pointer to a @p SerialDriver structure + * @return The byte value read from the driver's output queue. + * @retval MSG_TIMEOUT if the queue is empty (the lower driver usually + * disables the interrupt source when this happens). + * + * @iclass + */ +msg_t sdRequestDataI(SerialDriver *sdp) { + msg_t b; + + osalDbgCheckClassI(); + osalDbgCheck(sdp != NULL); + + b = oqGetI(&sdp->oqueue); + if (b < MSG_OK) + chnAddFlagsI(sdp, CHN_OUTPUT_EMPTY); + return b; +} + +/** + * @brief Direct output check on a @p SerialDriver. + * @note This function bypasses the indirect access to the channel and + * checks directly the output queue. This is faster but cannot + * be used to check different channels implementations. + * + * @param[in] sdp pointer to a @p SerialDriver structure + * @return The queue status. + * @retval false if the next write operation would not block. + * @retval true if the next write operation would block. + * + * @deprecated + * + * @api + */ +bool sdPutWouldBlock(SerialDriver *sdp) { + bool b; + + osalSysLock(); + b = oqIsFullI(&sdp->oqueue); + osalSysUnlock(); + + return b; +} + +/** + * @brief Direct input check on a @p SerialDriver. + * @note This function bypasses the indirect access to the channel and + * checks directly the input queue. This is faster but cannot + * be used to check different channels implementations. + * + * @param[in] sdp pointer to a @p SerialDriver structure + * @return The queue status. + * @retval false if the next write operation would not block. + * @retval true if the next write operation would block. + * + * @deprecated + * + * @api + */ +bool sdGetWouldBlock(SerialDriver *sdp) { + bool b; + + osalSysLock(); + b = iqIsEmptyI(&sdp->iqueue); + osalSysUnlock(); + + return b; +} + +#endif /* HAL_USE_SERIAL == TRUE */ + +/** @} */ diff --git a/os/hal/src/hal_serial_usb.c b/os/hal/src/hal_serial_usb.c new file mode 100644 index 000000000..9c21f7b56 --- /dev/null +++ b/os/hal/src/hal_serial_usb.c @@ -0,0 +1,502 @@ +/* + ChibiOS - Copyright (C) 2006..2016 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 serial_usb.c + * @brief Serial over USB Driver code. + * + * @addtogroup SERIAL_USB + * @{ + */ + +#include "hal.h" + +#if (HAL_USE_SERIAL_USB == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/* + * Current Line Coding. + */ +static cdc_linecoding_t linecoding = { + {0x00, 0x96, 0x00, 0x00}, /* 38400. */ + LC_STOP_1, LC_PARITY_NONE, 8 +}; + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/* + * Interface implementation. + */ + +static size_t write(void *ip, const uint8_t *bp, size_t n) { + + if (usbGetDriverStateI(((SerialUSBDriver *)ip)->config->usbp) != USB_ACTIVE) { + return 0; + } + + return obqWriteTimeout(&((SerialUSBDriver *)ip)->obqueue, bp, + n, TIME_INFINITE); +} + +static size_t read(void *ip, uint8_t *bp, size_t n) { + + if (usbGetDriverStateI(((SerialUSBDriver *)ip)->config->usbp) != USB_ACTIVE) { + return 0; + } + + return ibqReadTimeout(&((SerialUSBDriver *)ip)->ibqueue, bp, + n, TIME_INFINITE); +} + +static msg_t put(void *ip, uint8_t b) { + + if (usbGetDriverStateI(((SerialUSBDriver *)ip)->config->usbp) != USB_ACTIVE) { + return MSG_RESET; + } + + return obqPutTimeout(&((SerialUSBDriver *)ip)->obqueue, b, TIME_INFINITE); +} + +static msg_t get(void *ip) { + + if (usbGetDriverStateI(((SerialUSBDriver *)ip)->config->usbp) != USB_ACTIVE) { + return MSG_RESET; + } + + return ibqGetTimeout(&((SerialUSBDriver *)ip)->ibqueue, TIME_INFINITE); +} + +static msg_t putt(void *ip, uint8_t b, systime_t timeout) { + + if (usbGetDriverStateI(((SerialUSBDriver *)ip)->config->usbp) != USB_ACTIVE) { + return MSG_RESET; + } + + return obqPutTimeout(&((SerialUSBDriver *)ip)->obqueue, b, timeout); +} + +static msg_t gett(void *ip, systime_t timeout) { + + if (usbGetDriverStateI(((SerialUSBDriver *)ip)->config->usbp) != USB_ACTIVE) { + return MSG_RESET; + } + + return ibqGetTimeout(&((SerialUSBDriver *)ip)->ibqueue, timeout); +} + +static size_t writet(void *ip, const uint8_t *bp, size_t n, systime_t timeout) { + + if (usbGetDriverStateI(((SerialUSBDriver *)ip)->config->usbp) != USB_ACTIVE) { + return 0; + } + + return obqWriteTimeout(&((SerialUSBDriver *)ip)->obqueue, bp, n, timeout); +} + +static size_t readt(void *ip, uint8_t *bp, size_t n, systime_t timeout) { + + if (usbGetDriverStateI(((SerialUSBDriver *)ip)->config->usbp) != USB_ACTIVE) { + return 0; + } + + return ibqReadTimeout(&((SerialUSBDriver *)ip)->ibqueue, bp, n, timeout); +} + +static const struct SerialUSBDriverVMT vmt = { + write, read, put, get, + putt, gett, writet, readt +}; + +/** + * @brief Notification of empty buffer released into the input buffers queue. + * + * @param[in] bqp the buffers queue pointer. + */ +static void ibnotify(io_buffers_queue_t *bqp) { + SerialUSBDriver *sdup = bqGetLinkX(bqp); + + /* If the USB driver is not in the appropriate state then transactions + must not be started.*/ + if ((usbGetDriverStateI(sdup->config->usbp) != USB_ACTIVE) || + (sdup->state != SDU_READY)) { + return; + } + + /* Checking if there is already a transaction ongoing on the endpoint.*/ + if (!usbGetReceiveStatusI(sdup->config->usbp, sdup->config->bulk_out)) { + /* Trying to get a free buffer.*/ + uint8_t *buf = ibqGetEmptyBufferI(&sdup->ibqueue); + if (buf != NULL) { + /* Buffer found, starting a new transaction.*/ + usbStartReceiveI(sdup->config->usbp, sdup->config->bulk_out, + buf, SERIAL_USB_BUFFERS_SIZE); + } + } +} + +/** + * @brief Notification of filled buffer inserted into the output buffers queue. + * + * @param[in] bqp the buffers queue pointer. + */ +static void obnotify(io_buffers_queue_t *bqp) { + size_t n; + SerialUSBDriver *sdup = bqGetLinkX(bqp); + + /* If the USB driver is not in the appropriate state then transactions + must not be started.*/ + if ((usbGetDriverStateI(sdup->config->usbp) != USB_ACTIVE) || + (sdup->state != SDU_READY)) { + return; + } + + /* Checking if there is already a transaction ongoing on the endpoint.*/ + if (!usbGetTransmitStatusI(sdup->config->usbp, sdup->config->bulk_in)) { + /* Trying to get a full buffer.*/ + uint8_t *buf = obqGetFullBufferI(&sdup->obqueue, &n); + if (buf != NULL) { + /* Buffer found, starting a new transaction.*/ + usbStartTransmitI(sdup->config->usbp, sdup->config->bulk_in, buf, n); + } + } +} + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Serial Driver initialization. + * @note This function is implicitly invoked by @p halInit(), there is + * no need to explicitly initialize the driver. + * + * @init + */ +void sduInit(void) { +} + +/** + * @brief Initializes a generic full duplex driver object. + * @details The HW dependent part of the initialization has to be performed + * outside, usually in the hardware initialization code. + * + * @param[out] sdup pointer to a @p SerialUSBDriver structure + * + * @init + */ +void sduObjectInit(SerialUSBDriver *sdup) { + + sdup->vmt = &vmt; + osalEventObjectInit(&sdup->event); + sdup->state = SDU_STOP; + ibqObjectInit(&sdup->ibqueue, sdup->ib, + SERIAL_USB_BUFFERS_SIZE, SERIAL_USB_BUFFERS_NUMBER, + ibnotify, sdup); + obqObjectInit(&sdup->obqueue, sdup->ob, + SERIAL_USB_BUFFERS_SIZE, SERIAL_USB_BUFFERS_NUMBER, + obnotify, sdup); +} + +/** + * @brief Configures and starts the driver. + * + * @param[in] sdup pointer to a @p SerialUSBDriver object + * @param[in] config the serial over USB driver configuration + * + * @api + */ +void sduStart(SerialUSBDriver *sdup, const SerialUSBConfig *config) { + USBDriver *usbp = config->usbp; + + osalDbgCheck(sdup != NULL); + + osalSysLock(); + osalDbgAssert((sdup->state == SDU_STOP) || (sdup->state == SDU_READY), + "invalid state"); + usbp->in_params[config->bulk_in - 1U] = sdup; + usbp->out_params[config->bulk_out - 1U] = sdup; + if (config->int_in > 0U) { + usbp->in_params[config->int_in - 1U] = sdup; + } + sdup->config = config; + sdup->state = SDU_READY; + osalSysUnlock(); +} + +/** + * @brief Stops the driver. + * @details Any thread waiting on the driver's queues will be awakened with + * the message @p MSG_RESET. + * + * @param[in] sdup pointer to a @p SerialUSBDriver object + * + * @api + */ +void sduStop(SerialUSBDriver *sdup) { + USBDriver *usbp = sdup->config->usbp; + + osalDbgCheck(sdup != NULL); + + osalSysLock(); + osalDbgAssert((sdup->state == SDU_STOP) || (sdup->state == SDU_READY), + "invalid state"); + + /* Driver in stopped state.*/ + usbp->in_params[sdup->config->bulk_in - 1U] = NULL; + usbp->out_params[sdup->config->bulk_out - 1U] = NULL; + if (sdup->config->int_in > 0U) { + usbp->in_params[sdup->config->int_in - 1U] = NULL; + } + sdup->state = SDU_STOP; + + /* Enforces a disconnection.*/ + sduDisconnectI(sdup); + osalOsRescheduleS(); + osalSysUnlock(); +} + +/** + * @brief USB device disconnection handler. + * @note If this function is not called from an ISR then an explicit call + * to @p osalOsRescheduleS() in necessary afterward. + * + * @param[in] sdup pointer to a @p SerialUSBDriver object + * + * @iclass + */ +void sduDisconnectI(SerialUSBDriver *sdup) { + + /* Queues reset in order to signal the driver stop to the application.*/ + chnAddFlagsI(sdup, CHN_DISCONNECTED); + ibqResetI(&sdup->ibqueue); + obqResetI(&sdup->obqueue); +} + +/** + * @brief USB device configured handler. + * + * @param[in] sdup pointer to a @p SerialUSBDriver object + * + * @iclass + */ +void sduConfigureHookI(SerialUSBDriver *sdup) { + uint8_t *buf; + + ibqResetI(&sdup->ibqueue); + obqResetI(&sdup->obqueue); + chnAddFlagsI(sdup, CHN_CONNECTED); + + /* Starts the first OUT transaction immediately.*/ + buf = ibqGetEmptyBufferI(&sdup->ibqueue); + + osalDbgAssert(buf != NULL, "no free buffer"); + + usbStartReceiveI(sdup->config->usbp, sdup->config->bulk_out, + buf, SERIAL_USB_BUFFERS_SIZE); +} + +/** + * @brief Default requests hook. + * @details Applications wanting to use the Serial over USB driver can use + * this function as requests hook in the USB configuration. + * The following requests are emulated: + * - CDC_GET_LINE_CODING. + * - CDC_SET_LINE_CODING. + * - CDC_SET_CONTROL_LINE_STATE. + * . + * + * @param[in] usbp pointer to the @p USBDriver object + * @return The hook status. + * @retval true Message handled internally. + * @retval false Message not handled. + */ +bool sduRequestsHook(USBDriver *usbp) { + + if ((usbp->setup[0] & USB_RTYPE_TYPE_MASK) == USB_RTYPE_TYPE_CLASS) { + switch (usbp->setup[1]) { + case CDC_GET_LINE_CODING: + usbSetupTransfer(usbp, (uint8_t *)&linecoding, sizeof(linecoding), NULL); + return true; + case CDC_SET_LINE_CODING: + usbSetupTransfer(usbp, (uint8_t *)&linecoding, sizeof(linecoding), NULL); + return true; + case CDC_SET_CONTROL_LINE_STATE: + /* Nothing to do, there are no control lines.*/ + usbSetupTransfer(usbp, NULL, 0, NULL); + return true; + default: + return false; + } + } + return false; +} + +/** + * @brief SOF handler. + * @details The SOF interrupt is used for automatic flushing of incomplete + * buffers pending in the output queue. + * + * @param[in] sdup pointer to a @p SerialUSBDriver object + * + * @iclass + */ +void sduSOFHookI(SerialUSBDriver *sdup) { + + /* If the USB driver is not in the appropriate state then transactions + must not be started.*/ + if ((usbGetDriverStateI(sdup->config->usbp) != USB_ACTIVE) || + (sdup->state != SDU_READY)) { + return; + } + + /* If there is already a transaction ongoing then another one cannot be + started.*/ + if (usbGetTransmitStatusI(sdup->config->usbp, sdup->config->bulk_in)) { + return; + } + + /* Checking if there only a buffer partially filled, if so then it is + enforced in the queue and transmitted.*/ + if (obqTryFlushI(&sdup->obqueue)) { + size_t n; + uint8_t *buf = obqGetFullBufferI(&sdup->obqueue, &n); + + osalDbgAssert(buf != NULL, "queue is empty"); + + usbStartTransmitI(sdup->config->usbp, sdup->config->bulk_in, buf, n); + } +} + +/** + * @brief Default data transmitted callback. + * @details The application must use this function as callback for the IN + * data endpoint. + * + * @param[in] usbp pointer to the @p USBDriver object + * @param[in] ep IN endpoint number + */ +void sduDataTransmitted(USBDriver *usbp, usbep_t ep) { + uint8_t *buf; + size_t n; + SerialUSBDriver *sdup = usbp->in_params[ep - 1U]; + + if (sdup == NULL) { + return; + } + + osalSysLockFromISR(); + + /* Signaling that space is available in the output queue.*/ + chnAddFlagsI(sdup, CHN_OUTPUT_EMPTY); + + /* Freeing the buffer just transmitted, if it was not a zero size packet.*/ + if (usbp->epc[ep]->in_state->txsize > 0U) { + obqReleaseEmptyBufferI(&sdup->obqueue); + } + + /* Checking if there is a buffer ready for transmission.*/ + buf = obqGetFullBufferI(&sdup->obqueue, &n); + + if (buf != NULL) { + /* The endpoint cannot be busy, we are in the context of the callback, + so it is safe to transmit without a check.*/ + usbStartTransmitI(usbp, ep, buf, n); + } + else if ((usbp->epc[ep]->in_state->txsize > 0U) && + ((usbp->epc[ep]->in_state->txsize & + ((size_t)usbp->epc[ep]->in_maxsize - 1U)) == 0U)) { + /* Transmit zero sized packet in case the last one has maximum allowed + size. Otherwise the recipient may expect more data coming soon and + not return buffered data to app. See section 5.8.3 Bulk Transfer + Packet Size Constraints of the USB Specification document.*/ + usbStartTransmitI(usbp, ep, usbp->setup, 0); + + } + else { + /* Nothing to transmit.*/ + } + + osalSysUnlockFromISR(); +} + +/** + * @brief Default data received callback. + * @details The application must use this function as callback for the OUT + * data endpoint. + * + * @param[in] usbp pointer to the @p USBDriver object + * @param[in] ep OUT endpoint number + */ +void sduDataReceived(USBDriver *usbp, usbep_t ep) { + uint8_t *buf; + SerialUSBDriver *sdup = usbp->out_params[ep - 1U]; + + if (sdup == NULL) { + return; + } + + osalSysLockFromISR(); + + /* Signaling that data is available in the input queue.*/ + chnAddFlagsI(sdup, CHN_INPUT_AVAILABLE); + + /* Posting the filled buffer in the queue.*/ + ibqPostFullBufferI(&sdup->ibqueue, + usbGetReceiveTransactionSizeX(sdup->config->usbp, + sdup->config->bulk_out)); + + /* The endpoint cannot be busy, we are in the context of the callback, + so a packet is in the buffer for sure. Trying to get a free buffer + for the next transaction.*/ + buf = ibqGetEmptyBufferI(&sdup->ibqueue); + if (buf != NULL) { + /* Buffer found, starting a new transaction.*/ + usbStartReceiveI(sdup->config->usbp, sdup->config->bulk_out, + buf, SERIAL_USB_BUFFERS_SIZE); + } + osalSysUnlockFromISR(); +} + +/** + * @brief Default data received callback. + * @details The application must use this function as callback for the IN + * interrupt endpoint. + * + * @param[in] usbp pointer to the @p USBDriver object + * @param[in] ep endpoint number + */ +void sduInterruptTransmitted(USBDriver *usbp, usbep_t ep) { + + (void)usbp; + (void)ep; +} + +#endif /* HAL_USE_SERIAL_USB == TRUE */ + +/** @} */ diff --git a/os/hal/src/hal_spi.c b/os/hal/src/hal_spi.c new file mode 100644 index 000000000..90907e8f4 --- /dev/null +++ b/os/hal/src/hal_spi.c @@ -0,0 +1,416 @@ +/* + ChibiOS - Copyright (C) 2006..2016 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 spi.c + * @brief SPI Driver code. + * + * @addtogroup SPI + * @{ + */ + +#include "hal.h" + +#if (HAL_USE_SPI == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief SPI Driver initialization. + * @note This function is implicitly invoked by @p halInit(), there is + * no need to explicitly initialize the driver. + * + * @init + */ +void spiInit(void) { + + spi_lld_init(); +} + +/** + * @brief Initializes the standard part of a @p SPIDriver structure. + * + * @param[out] spip pointer to the @p SPIDriver object + * + * @init + */ +void spiObjectInit(SPIDriver *spip) { + + spip->state = SPI_STOP; + spip->config = NULL; +#if SPI_USE_WAIT == TRUE + spip->thread = NULL; +#endif +#if SPI_USE_MUTUAL_EXCLUSION == TRUE + osalMutexObjectInit(&spip->mutex); +#endif +#if defined(SPI_DRIVER_EXT_INIT_HOOK) + SPI_DRIVER_EXT_INIT_HOOK(spip); +#endif +} + +/** + * @brief Configures and activates the SPI peripheral. + * + * @param[in] spip pointer to the @p SPIDriver object + * @param[in] config pointer to the @p SPIConfig object + * + * @api + */ +void spiStart(SPIDriver *spip, const SPIConfig *config) { + + osalDbgCheck((spip != NULL) && (config != NULL)); + + osalSysLock(); + osalDbgAssert((spip->state == SPI_STOP) || (spip->state == SPI_READY), + "invalid state"); + spip->config = config; + spi_lld_start(spip); + spip->state = SPI_READY; + osalSysUnlock(); +} + +/** + * @brief Deactivates the SPI peripheral. + * @note Deactivating the peripheral also enforces a release of the slave + * select line. + * + * @param[in] spip pointer to the @p SPIDriver object + * + * @api + */ +void spiStop(SPIDriver *spip) { + + osalDbgCheck(spip != NULL); + + osalSysLock(); + osalDbgAssert((spip->state == SPI_STOP) || (spip->state == SPI_READY), + "invalid state"); + spi_lld_stop(spip); + spip->state = SPI_STOP; + osalSysUnlock(); +} + +/** + * @brief Asserts the slave select signal and prepares for transfers. + * + * @param[in] spip pointer to the @p SPIDriver object + * + * @api + */ +void spiSelect(SPIDriver *spip) { + + osalDbgCheck(spip != NULL); + + osalSysLock(); + osalDbgAssert(spip->state == SPI_READY, "not ready"); + spiSelectI(spip); + osalSysUnlock(); +} + +/** + * @brief Deasserts the slave select signal. + * @details The previously selected peripheral is unselected. + * + * @param[in] spip pointer to the @p SPIDriver object + * + * @api + */ +void spiUnselect(SPIDriver *spip) { + + osalDbgCheck(spip != NULL); + + osalSysLock(); + osalDbgAssert(spip->state == SPI_READY, "not ready"); + spiUnselectI(spip); + osalSysUnlock(); +} + +/** + * @brief Ignores data on the SPI bus. + * @details This asynchronous function starts the transmission of a series of + * idle words on the SPI bus and ignores the received data. + * @pre A slave must have been selected using @p spiSelect() or + * @p spiSelectI(). + * @post At the end of the operation the configured callback is invoked. + * + * @param[in] spip pointer to the @p SPIDriver object + * @param[in] n number of words to be ignored + * + * @api + */ +void spiStartIgnore(SPIDriver *spip, size_t n) { + + osalDbgCheck((spip != NULL) && (n > 0U)); + + osalSysLock(); + osalDbgAssert(spip->state == SPI_READY, "not ready"); + spiStartIgnoreI(spip, n); + osalSysUnlock(); +} + +/** + * @brief Exchanges data on the SPI bus. + * @details This asynchronous function starts a simultaneous transmit/receive + * operation. + * @pre A slave must have been selected using @p spiSelect() or + * @p spiSelectI(). + * @post At the end of the operation the configured callback is invoked. + * @note The buffers are organized as uint8_t arrays for data sizes below + * or equal to 8 bits else it is organized as uint16_t arrays. + * + * @param[in] spip pointer to the @p SPIDriver object + * @param[in] n number of words to be exchanged + * @param[in] txbuf the pointer to the transmit buffer + * @param[out] rxbuf the pointer to the receive buffer + * + * @api + */ +void spiStartExchange(SPIDriver *spip, size_t n, + const void *txbuf, void *rxbuf) { + + osalDbgCheck((spip != NULL) && (n > 0U) && + (rxbuf != NULL) && (txbuf != NULL)); + + osalSysLock(); + osalDbgAssert(spip->state == SPI_READY, "not ready"); + spiStartExchangeI(spip, n, txbuf, rxbuf); + osalSysUnlock(); +} + +/** + * @brief Sends data over the SPI bus. + * @details This asynchronous function starts a transmit operation. + * @pre A slave must have been selected using @p spiSelect() or + * @p spiSelectI(). + * @post At the end of the operation the configured callback is invoked. + * @note The buffers are organized as uint8_t arrays for data sizes below + * or equal to 8 bits else it is organized as uint16_t arrays. + * + * @param[in] spip pointer to the @p SPIDriver object + * @param[in] n number of words to send + * @param[in] txbuf the pointer to the transmit buffer + * + * @api + */ +void spiStartSend(SPIDriver *spip, size_t n, const void *txbuf) { + + osalDbgCheck((spip != NULL) && (n > 0U) && (txbuf != NULL)); + + osalSysLock(); + osalDbgAssert(spip->state == SPI_READY, "not ready"); + spiStartSendI(spip, n, txbuf); + osalSysUnlock(); +} + +/** + * @brief Receives data from the SPI bus. + * @details This asynchronous function starts a receive operation. + * @pre A slave must have been selected using @p spiSelect() or + * @p spiSelectI(). + * @post At the end of the operation the configured callback is invoked. + * @note The buffers are organized as uint8_t arrays for data sizes below + * or equal to 8 bits else it is organized as uint16_t arrays. + * + * @param[in] spip pointer to the @p SPIDriver object + * @param[in] n number of words to receive + * @param[out] rxbuf the pointer to the receive buffer + * + * @api + */ +void spiStartReceive(SPIDriver *spip, size_t n, void *rxbuf) { + + osalDbgCheck((spip != NULL) && (n > 0U) && (rxbuf != NULL)); + + osalSysLock(); + osalDbgAssert(spip->state == SPI_READY, "not ready"); + spiStartReceiveI(spip, n, rxbuf); + osalSysUnlock(); +} + +#if (SPI_USE_WAIT == TRUE) || defined(__DOXYGEN__) +/** + * @brief Ignores data on the SPI bus. + * @details This synchronous function performs the transmission of a series of + * idle words on the SPI bus and ignores the received data. + * @pre In order to use this function the option @p SPI_USE_WAIT must be + * enabled. + * @pre In order to use this function the driver must have been configured + * without callbacks (@p end_cb = @p NULL). + * + * @param[in] spip pointer to the @p SPIDriver object + * @param[in] n number of words to be ignored + * + * @api + */ +void spiIgnore(SPIDriver *spip, size_t n) { + + osalDbgCheck((spip != NULL) && (n > 0U)); + + osalSysLock(); + osalDbgAssert(spip->state == SPI_READY, "not ready"); + osalDbgAssert(spip->config->end_cb == NULL, "has callback"); + spiStartIgnoreI(spip, n); + (void) osalThreadSuspendS(&spip->thread); + osalSysUnlock(); +} + +/** + * @brief Exchanges data on the SPI bus. + * @details This synchronous function performs a simultaneous transmit/receive + * operation. + * @pre In order to use this function the option @p SPI_USE_WAIT must be + * enabled. + * @pre In order to use this function the driver must have been configured + * without callbacks (@p end_cb = @p NULL). + * @note The buffers are organized as uint8_t arrays for data sizes below + * or equal to 8 bits else it is organized as uint16_t arrays. + * + * @param[in] spip pointer to the @p SPIDriver object + * @param[in] n number of words to be exchanged + * @param[in] txbuf the pointer to the transmit buffer + * @param[out] rxbuf the pointer to the receive buffer + * + * @api + */ +void spiExchange(SPIDriver *spip, size_t n, + const void *txbuf, void *rxbuf) { + + osalDbgCheck((spip != NULL) && (n > 0U) && + (rxbuf != NULL) && (txbuf != NULL)); + + osalSysLock(); + osalDbgAssert(spip->state == SPI_READY, "not ready"); + osalDbgAssert(spip->config->end_cb == NULL, "has callback"); + spiStartExchangeI(spip, n, txbuf, rxbuf); + (void) osalThreadSuspendS(&spip->thread); + osalSysUnlock(); +} + +/** + * @brief Sends data over the SPI bus. + * @details This synchronous function performs a transmit operation. + * @pre In order to use this function the option @p SPI_USE_WAIT must be + * enabled. + * @pre In order to use this function the driver must have been configured + * without callbacks (@p end_cb = @p NULL). + * @note The buffers are organized as uint8_t arrays for data sizes below + * or equal to 8 bits else it is organized as uint16_t arrays. + * + * @param[in] spip pointer to the @p SPIDriver object + * @param[in] n number of words to send + * @param[in] txbuf the pointer to the transmit buffer + * + * @api + */ +void spiSend(SPIDriver *spip, size_t n, const void *txbuf) { + + osalDbgCheck((spip != NULL) && (n > 0U) && (txbuf != NULL)); + + osalSysLock(); + osalDbgAssert(spip->state == SPI_READY, "not ready"); + osalDbgAssert(spip->config->end_cb == NULL, "has callback"); + spiStartSendI(spip, n, txbuf); + (void) osalThreadSuspendS(&spip->thread); + osalSysUnlock(); +} + +/** + * @brief Receives data from the SPI bus. + * @details This synchronous function performs a receive operation. + * @pre In order to use this function the option @p SPI_USE_WAIT must be + * enabled. + * @pre In order to use this function the driver must have been configured + * without callbacks (@p end_cb = @p NULL). + * @note The buffers are organized as uint8_t arrays for data sizes below + * or equal to 8 bits else it is organized as uint16_t arrays. + * + * @param[in] spip pointer to the @p SPIDriver object + * @param[in] n number of words to receive + * @param[out] rxbuf the pointer to the receive buffer + * + * @api + */ +void spiReceive(SPIDriver *spip, size_t n, void *rxbuf) { + + osalDbgCheck((spip != NULL) && (n > 0U) && (rxbuf != NULL)); + + osalSysLock(); + osalDbgAssert(spip->state == SPI_READY, "not ready"); + osalDbgAssert(spip->config->end_cb == NULL, "has callback"); + spiStartReceiveI(spip, n, rxbuf); + (void) osalThreadSuspendS(&spip->thread); + osalSysUnlock(); +} +#endif /* SPI_USE_WAIT == TRUE */ + +#if (SPI_USE_MUTUAL_EXCLUSION == TRUE) || defined(__DOXYGEN__) +/** + * @brief Gains exclusive access to the SPI bus. + * @details This function tries to gain ownership to the SPI bus, if the bus + * is already being used then the invoking thread is queued. + * @pre In order to use this function the option @p SPI_USE_MUTUAL_EXCLUSION + * must be enabled. + * + * @param[in] spip pointer to the @p SPIDriver object + * + * @api + */ +void spiAcquireBus(SPIDriver *spip) { + + osalDbgCheck(spip != NULL); + + osalMutexLock(&spip->mutex); +} + +/** + * @brief Releases exclusive access to the SPI bus. + * @pre In order to use this function the option @p SPI_USE_MUTUAL_EXCLUSION + * must be enabled. + * + * @param[in] spip pointer to the @p SPIDriver object + * + * @api + */ +void spiReleaseBus(SPIDriver *spip) { + + osalDbgCheck(spip != NULL); + + osalMutexUnlock(&spip->mutex); +} +#endif /* SPI_USE_MUTUAL_EXCLUSION == TRUE */ + +#endif /* HAL_USE_SPI == TRUE */ + +/** @} */ diff --git a/os/hal/src/hal_st.c b/os/hal/src/hal_st.c new file mode 100644 index 000000000..cf654f882 --- /dev/null +++ b/os/hal/src/hal_st.c @@ -0,0 +1,130 @@ +/* + ChibiOS - Copyright (C) 2006..2016 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 st.c + * @brief ST Driver code. + * + * @addtogroup ST + * @{ + */ + +#include "hal.h" + +#if (OSAL_ST_MODE != OSAL_ST_MODE_NONE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief ST Driver initialization. + * @note This function is implicitly invoked by @p halInit(), there is + * no need to explicitly initialize the driver. + * + * @init + */ +void stInit(void) { + + st_lld_init(); +} + + +/** + * @brief Starts the alarm. + * @note Makes sure that no spurious alarms are triggered after + * this call. + * @note This functionality is only available in free running mode, the + * behavior in periodic mode is undefined. + * + * @param[in] abstime the time to be set for the first alarm + * + * @api + */ +void stStartAlarm(systime_t abstime) { + + osalDbgAssert(stIsAlarmActive() == false, "already active"); + + st_lld_start_alarm(abstime); +} + +/** + * @brief Stops the alarm interrupt. + * @note This functionality is only available in free running mode, the + * behavior in periodic mode is undefined. + * + * @api + */ +void stStopAlarm(void) { + + st_lld_stop_alarm(); +} + +/** + * @brief Sets the alarm time. + * @note This functionality is only available in free running mode, the + * behavior in periodic mode is undefined. + * + * @param[in] abstime the time to be set for the next alarm + * + * @api + */ +void stSetAlarm(systime_t abstime) { + + osalDbgAssert(stIsAlarmActive() != false, "not active"); + + st_lld_set_alarm(abstime); +} + +/** + * @brief Returns the current alarm time. + * @note This functionality is only available in free running mode, the + * behavior in periodic mode is undefined. + * + * @return The currently set alarm time. + * + * @api + */ +systime_t stGetAlarm(void) { + + osalDbgAssert(stIsAlarmActive() != false, "not active"); + + return st_lld_get_alarm(); +} + +#endif /* OSAL_ST_MODE != OSAL_ST_MODE_NONE */ + +/** @} */ diff --git a/os/hal/src/hal_uart.c b/os/hal/src/hal_uart.c new file mode 100644 index 000000000..7bf0e5d74 --- /dev/null +++ b/os/hal/src/hal_uart.c @@ -0,0 +1,515 @@ +/* + ChibiOS - Copyright (C) 2006..2016 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 uart.c + * @brief UART Driver code. + * + * @addtogroup UART + * @{ + */ + +#include "hal.h" + +#if (HAL_USE_UART == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief UART Driver initialization. + * @note This function is implicitly invoked by @p halInit(), there is + * no need to explicitly initialize the driver. + * + * @init + */ +void uartInit(void) { + + uart_lld_init(); +} + +/** + * @brief Initializes the standard part of a @p UARTDriver structure. + * + * @param[out] uartp pointer to the @p UARTDriver object + * + * @init + */ +void uartObjectInit(UARTDriver *uartp) { + + uartp->state = UART_STOP; + uartp->txstate = UART_TX_IDLE; + uartp->rxstate = UART_RX_IDLE; + uartp->config = NULL; +#if UART_USE_WAIT == TRUE + uartp->early = false; + uartp->threadrx = NULL; + uartp->threadtx = NULL; +#endif /* UART_USE_WAIT */ +#if UART_USE_MUTUAL_EXCLUSION == TRUE + osalMutexObjectInit(&uartp->mutex); +#endif /* UART_USE_MUTUAL_EXCLUSION */ + + /* Optional, user-defined initializer.*/ +#if defined(UART_DRIVER_EXT_INIT_HOOK) + UART_DRIVER_EXT_INIT_HOOK(uartp); +#endif +} + +/** + * @brief Configures and activates the UART peripheral. + * + * @param[in] uartp pointer to the @p UARTDriver object + * @param[in] config pointer to the @p UARTConfig object + * + * @api + */ +void uartStart(UARTDriver *uartp, const UARTConfig *config) { + + osalDbgCheck((uartp != NULL) && (config != NULL)); + + osalSysLock(); + osalDbgAssert((uartp->state == UART_STOP) || (uartp->state == UART_READY), + "invalid state"); + + uartp->config = config; + uart_lld_start(uartp); + uartp->state = UART_READY; + osalSysUnlock(); +} + +/** + * @brief Deactivates the UART peripheral. + * + * @param[in] uartp pointer to the @p UARTDriver object + * + * @api + */ +void uartStop(UARTDriver *uartp) { + + osalDbgCheck(uartp != NULL); + + osalSysLock(); + osalDbgAssert((uartp->state == UART_STOP) || (uartp->state == UART_READY), + "invalid state"); + + uart_lld_stop(uartp); + uartp->state = UART_STOP; + uartp->txstate = UART_TX_IDLE; + uartp->rxstate = UART_RX_IDLE; + osalSysUnlock(); +} + +/** + * @brief Starts a transmission on the UART peripheral. + * @note The buffers are organized as uint8_t arrays for data sizes below + * or equal to 8 bits else it is organized as uint16_t arrays. + * + * @param[in] uartp pointer to the @p UARTDriver object + * @param[in] n number of data frames to send + * @param[in] txbuf the pointer to the transmit buffer + * + * @api + */ +void uartStartSend(UARTDriver *uartp, size_t n, const void *txbuf) { + + osalDbgCheck((uartp != NULL) && (n > 0U) && (txbuf != NULL)); + + osalSysLock(); + osalDbgAssert(uartp->state == UART_READY, "is active"); + osalDbgAssert(uartp->txstate != UART_TX_ACTIVE, "tx active"); + + uart_lld_start_send(uartp, n, txbuf); + uartp->txstate = UART_TX_ACTIVE; + osalSysUnlock(); +} + +/** + * @brief Starts a transmission on the UART peripheral. + * @note The buffers are organized as uint8_t arrays for data sizes below + * or equal to 8 bits else it is organized as uint16_t arrays. + * @note This function has to be invoked from a lock zone. + * + * @param[in] uartp pointer to the @p UARTDriver object + * @param[in] n number of data frames to send + * @param[in] txbuf the pointer to the transmit buffer + * + * @iclass + */ +void uartStartSendI(UARTDriver *uartp, size_t n, const void *txbuf) { + + osalDbgCheckClassI(); + osalDbgCheck((uartp != NULL) && (n > 0U) && (txbuf != NULL)); + osalDbgAssert(uartp->state == UART_READY, "is active"); + osalDbgAssert(uartp->txstate != UART_TX_ACTIVE, "tx active"); + + uart_lld_start_send(uartp, n, txbuf); + uartp->txstate = UART_TX_ACTIVE; +} + +/** + * @brief Stops any ongoing transmission. + * @note Stopping a transmission also suppresses the transmission callbacks. + * + * @param[in] uartp pointer to the @p UARTDriver object + * + * @return The number of data frames not transmitted by the + * stopped transmit operation. + * @retval 0 There was no transmit operation in progress. + * + * @api + */ +size_t uartStopSend(UARTDriver *uartp) { + size_t n; + + osalDbgCheck(uartp != NULL); + + osalSysLock(); + osalDbgAssert(uartp->state == UART_READY, "not active"); + + if (uartp->txstate == UART_TX_ACTIVE) { + n = uart_lld_stop_send(uartp); + uartp->txstate = UART_TX_IDLE; + } + else { + n = 0; + } + osalSysUnlock(); + + return n; +} + +/** + * @brief Stops any ongoing transmission. + * @note Stopping a transmission also suppresses the transmission callbacks. + * @note This function has to be invoked from a lock zone. + * + * @param[in] uartp pointer to the @p UARTDriver object + * + * @return The number of data frames not transmitted by the + * stopped transmit operation. + * @retval 0 There was no transmit operation in progress. + * + * @iclass + */ +size_t uartStopSendI(UARTDriver *uartp) { + + osalDbgCheckClassI(); + osalDbgCheck(uartp != NULL); + osalDbgAssert(uartp->state == UART_READY, "not active"); + + if (uartp->txstate == UART_TX_ACTIVE) { + size_t n = uart_lld_stop_send(uartp); + uartp->txstate = UART_TX_IDLE; + return n; + } + return 0; +} + +/** + * @brief Starts a receive operation on the UART peripheral. + * @note The buffers are organized as uint8_t arrays for data sizes below + * or equal to 8 bits else it is organized as uint16_t arrays. + * + * @param[in] uartp pointer to the @p UARTDriver object + * @param[in] n number of data frames to receive + * @param[in] rxbuf the pointer to the receive buffer + * + * @api + */ +void uartStartReceive(UARTDriver *uartp, size_t n, void *rxbuf) { + + osalDbgCheck((uartp != NULL) && (n > 0U) && (rxbuf != NULL)); + + osalSysLock(); + osalDbgAssert(uartp->state == UART_READY, "is active"); + osalDbgAssert(uartp->rxstate != UART_RX_ACTIVE, "rx active"); + + uart_lld_start_receive(uartp, n, rxbuf); + uartp->rxstate = UART_RX_ACTIVE; + osalSysUnlock(); +} + +/** + * @brief Starts a receive operation on the UART peripheral. + * @note The buffers are organized as uint8_t arrays for data sizes below + * or equal to 8 bits else it is organized as uint16_t arrays. + * @note This function has to be invoked from a lock zone. + * + * @param[in] uartp pointer to the @p UARTDriver object + * @param[in] n number of data frames to receive + * @param[out] rxbuf the pointer to the receive buffer + * + * @iclass + */ +void uartStartReceiveI(UARTDriver *uartp, size_t n, void *rxbuf) { + + osalDbgCheckClassI(); + osalDbgCheck((uartp != NULL) && (n > 0U) && (rxbuf != NULL)); + osalDbgAssert(uartp->state == UART_READY, "is active"); + osalDbgAssert(uartp->rxstate != UART_RX_ACTIVE, "rx active"); + + uart_lld_start_receive(uartp, n, rxbuf); + uartp->rxstate = UART_RX_ACTIVE; +} + +/** + * @brief Stops any ongoing receive operation. + * @note Stopping a receive operation also suppresses the receive callbacks. + * + * @param[in] uartp pointer to the @p UARTDriver object + * + * @return The number of data frames not received by the + * stopped receive operation. + * @retval 0 There was no receive operation in progress. + * + * @api + */ +size_t uartStopReceive(UARTDriver *uartp) { + size_t n; + + osalDbgCheck(uartp != NULL); + + osalSysLock(); + osalDbgAssert(uartp->state == UART_READY, "not active"); + + if (uartp->rxstate == UART_RX_ACTIVE) { + n = uart_lld_stop_receive(uartp); + uartp->rxstate = UART_RX_IDLE; + } + else { + n = 0; + } + osalSysUnlock(); + + return n; +} + +/** + * @brief Stops any ongoing receive operation. + * @note Stopping a receive operation also suppresses the receive callbacks. + * @note This function has to be invoked from a lock zone. + * + * @param[in] uartp pointer to the @p UARTDriver object + * + * @return The number of data frames not received by the + * stopped receive operation. + * @retval 0 There was no receive operation in progress. + * + * @iclass + */ +size_t uartStopReceiveI(UARTDriver *uartp) { + + osalDbgCheckClassI(); + osalDbgCheck(uartp != NULL); + osalDbgAssert(uartp->state == UART_READY, "not active"); + + if (uartp->rxstate == UART_RX_ACTIVE) { + size_t n = uart_lld_stop_receive(uartp); + uartp->rxstate = UART_RX_IDLE; + return n; + } + return 0; +} + +#if (UART_USE_WAIT == TRUE) || defined(__DOXYGEN__) +/** + * @brief Performs a transmission on the UART peripheral. + * @note The function returns when the specified number of frames have been + * sent to the UART or on timeout. + * @note The buffers are organized as uint8_t arrays for data sizes below + * or equal to 8 bits else it is organized as uint16_t arrays. + * + * @param[in] uartp pointer to the @p UARTDriver object + * @param[in,out] np number of data frames to transmit, on exit the number + * of frames actually transmitted + * @param[in] txbuf the pointer to the transmit buffer + * @param[in] timeout operation timeout + * @return The operation status. + * @retval MSG_OK if the operation completed successfully. + * @retval MSG_TIMEOUT if the operation timed out. + * + * @api + */ +msg_t uartSendTimeout(UARTDriver *uartp, size_t *np, + const void *txbuf, systime_t timeout) { + msg_t msg; + + osalDbgCheck((uartp != NULL) && (*np > 0U) && (txbuf != NULL)); + + osalSysLock(); + osalDbgAssert(uartp->state == UART_READY, "is active"); + osalDbgAssert(uartp->txstate != UART_TX_ACTIVE, "tx active"); + + /* Transmission start.*/ + uartp->early = true; + uart_lld_start_send(uartp, *np, txbuf); + uartp->txstate = UART_TX_ACTIVE; + + /* Waiting for result.*/ + msg = osalThreadSuspendTimeoutS(&uartp->threadtx, timeout); + if (msg != MSG_OK) { + *np = uartStopSendI(uartp); + } + osalSysUnlock(); + + return msg; +} + +/** + * @brief Performs a transmission on the UART peripheral. + * @note The function returns when the specified number of frames have been + * physically transmitted or on timeout. + * @note The buffers are organized as uint8_t arrays for data sizes below + * or equal to 8 bits else it is organized as uint16_t arrays. + * + * @param[in] uartp pointer to the @p UARTDriver object + * @param[in,out] np number of data frames to transmit, on exit the number + * of frames actually transmitted + * @param[in] txbuf the pointer to the transmit buffer + * @param[in] timeout operation timeout + * @return The operation status. + * @retval MSG_OK if the operation completed successfully. + * @retval MSG_TIMEOUT if the operation timed out. + * + * @api + */ +msg_t uartSendFullTimeout(UARTDriver *uartp, size_t *np, + const void *txbuf, systime_t timeout) { + msg_t msg; + + osalDbgCheck((uartp != NULL) && (*np > 0U) && (txbuf != NULL)); + + osalSysLock(); + osalDbgAssert(uartp->state == UART_READY, "is active"); + osalDbgAssert(uartp->txstate != UART_TX_ACTIVE, "tx active"); + + /* Transmission start.*/ + uartp->early = false; + uart_lld_start_send(uartp, *np, txbuf); + uartp->txstate = UART_TX_ACTIVE; + + /* Waiting for result.*/ + msg = osalThreadSuspendTimeoutS(&uartp->threadtx, timeout); + if (msg != MSG_OK) { + *np = uartStopSendI(uartp); + } + osalSysUnlock(); + + return msg; +} + +/** + * @brief Performs a receive operation on the UART peripheral. + * @note The function returns when the specified number of frames have been + * received or on error/timeout. + * @note The buffers are organized as uint8_t arrays for data sizes below + * or equal to 8 bits else it is organized as uint16_t arrays. + * + * @param[in] uartp pointer to the @p UARTDriver object + * @param[in,out] np number of data frames to receive, on exit the number + * of frames actually received + * @param[in] rxbuf the pointer to the receive buffer + * @param[in] timeout operation timeout + * + * @return The operation status. + * @retval MSG_OK if the operation completed successfully. + * @retval MSG_TIMEOUT if the operation timed out. + * @retval MSG_RESET in case of a receive error. + * + * @api + */ +msg_t uartReceiveTimeout(UARTDriver *uartp, size_t *np, + void *rxbuf, systime_t timeout) { + msg_t msg; + + osalDbgCheck((uartp != NULL) && (*np > 0U) && (rxbuf != NULL)); + + osalSysLock(); + osalDbgAssert(uartp->state == UART_READY, "is active"); + osalDbgAssert(uartp->rxstate != UART_RX_ACTIVE, "rx active"); + + /* Receive start.*/ + uart_lld_start_receive(uartp, *np, rxbuf); + uartp->rxstate = UART_RX_ACTIVE; + + /* Waiting for result.*/ + msg = osalThreadSuspendTimeoutS(&uartp->threadrx, timeout); + if (msg != MSG_OK) { + *np = uartStopReceiveI(uartp); + } + osalSysUnlock(); + + return msg; +} +#endif + +#if (UART_USE_MUTUAL_EXCLUSION == TRUE) || defined(__DOXYGEN__) +/** + * @brief Gains exclusive access to the UART bus. + * @details This function tries to gain ownership to the UART bus, if the bus + * is already being used then the invoking thread is queued. + * @pre In order to use this function the option @p UART_USE_MUTUAL_EXCLUSION + * must be enabled. + * + * @param[in] uartp pointer to the @p UARTDriver object + * + * @api + */ +void uartAcquireBus(UARTDriver *uartp) { + + osalDbgCheck(uartp != NULL); + + osalMutexLock(&uartp->mutex); +} + +/** + * @brief Releases exclusive access to the UART bus. + * @pre In order to use this function the option @p UART_USE_MUTUAL_EXCLUSION + * must be enabled. + * + * @param[in] uartp pointer to the @p UARTDriver object + * + * @api + */ +void uartReleaseBus(UARTDriver *uartp) { + + osalDbgCheck(uartp != NULL); + + osalMutexUnlock(&uartp->mutex); +} +#endif + +#endif /* HAL_USE_UART == TRUE */ + +/** @} */ diff --git a/os/hal/src/hal_usb.c b/os/hal/src/hal_usb.c new file mode 100644 index 000000000..d9fbc091a --- /dev/null +++ b/os/hal/src/hal_usb.c @@ -0,0 +1,950 @@ +/* + ChibiOS - Copyright (C) 2006..2016 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 usb.c + * @brief USB Driver code. + * + * @addtogroup USB + * @{ + */ + +#include + +#include "hal.h" + +#if (HAL_USE_USB == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +static const uint8_t zero_status[] = {0x00, 0x00}; +static const uint8_t active_status[] ={0x00, 0x00}; +static const uint8_t halted_status[] = {0x01, 0x00}; + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static uint16_t get_hword(uint8_t *p) { + uint16_t hw; + + hw = (uint16_t)*p++; + hw |= (uint16_t)*p << 8U; + return hw; +} + +/** + * @brief SET ADDRESS transaction callback. + * + * @param[in] usbp pointer to the @p USBDriver object + */ +static void set_address(USBDriver *usbp) { + + usbp->address = usbp->setup[2]; + usb_lld_set_address(usbp); + _usb_isr_invoke_event_cb(usbp, USB_EVENT_ADDRESS); + usbp->state = USB_SELECTED; +} + +/** + * @brief Standard requests handler. + * @details This is the standard requests default handler, most standard + * requests are handled here, the user can override the standard + * handling using the @p requests_hook_cb hook in the + * @p USBConfig structure. + * + * @param[in] usbp pointer to the @p USBDriver object + * @return The request handling exit code. + * @retval false Request not recognized by the handler or error. + * @retval true Request handled. + */ +static bool default_handler(USBDriver *usbp) { + const USBDescriptor *dp; + + /* Decoding the request.*/ + switch ((((uint32_t)usbp->setup[0] & (USB_RTYPE_RECIPIENT_MASK | + USB_RTYPE_TYPE_MASK)) | + ((uint32_t)usbp->setup[1] << 8U))) { + case (uint32_t)USB_RTYPE_RECIPIENT_DEVICE | ((uint32_t)USB_REQ_GET_STATUS << 8): + /* Just returns the current status word.*/ + usbSetupTransfer(usbp, (uint8_t *)&usbp->status, 2, NULL); + return true; + case (uint32_t)USB_RTYPE_RECIPIENT_DEVICE | ((uint32_t)USB_REQ_CLEAR_FEATURE << 8): + /* Only the DEVICE_REMOTE_WAKEUP is handled here, any other feature + number is handled as an error.*/ + if (usbp->setup[2] == USB_FEATURE_DEVICE_REMOTE_WAKEUP) { + usbp->status &= ~2U; + usbSetupTransfer(usbp, NULL, 0, NULL); + return true; + } + return false; + case (uint32_t)USB_RTYPE_RECIPIENT_DEVICE | ((uint32_t)USB_REQ_SET_FEATURE << 8): + /* Only the DEVICE_REMOTE_WAKEUP is handled here, any other feature + number is handled as an error.*/ + if (usbp->setup[2] == USB_FEATURE_DEVICE_REMOTE_WAKEUP) { + usbp->status |= 2U; + usbSetupTransfer(usbp, NULL, 0, NULL); + return true; + } + return false; + case (uint32_t)USB_RTYPE_RECIPIENT_DEVICE | ((uint32_t)USB_REQ_SET_ADDRESS << 8): + /* The SET_ADDRESS handling can be performed here or postponed after + the status packed depending on the USB_SET_ADDRESS_MODE low + driver setting.*/ +#if USB_SET_ADDRESS_MODE == USB_EARLY_SET_ADDRESS + if ((usbp->setup[0] == USB_RTYPE_RECIPIENT_DEVICE) && + (usbp->setup[1] == USB_REQ_SET_ADDRESS)) { + set_address(usbp); + } + usbSetupTransfer(usbp, NULL, 0, NULL); +#else + usbSetupTransfer(usbp, NULL, 0, set_address); +#endif + return true; + case (uint32_t)USB_RTYPE_RECIPIENT_DEVICE | ((uint32_t)USB_REQ_GET_DESCRIPTOR << 8): + /* Handling descriptor requests from the host.*/ + dp = usbp->config->get_descriptor_cb(usbp, usbp->setup[3], + usbp->setup[2], + get_hword(&usbp->setup[4])); + if (dp == NULL) { + return false; + } + /*lint -save -e9005 [11.8] Removing const is fine.*/ + usbSetupTransfer(usbp, (uint8_t *)dp->ud_string, dp->ud_size, NULL); + /*lint -restore*/ + return true; + case (uint32_t)USB_RTYPE_RECIPIENT_DEVICE | ((uint32_t)USB_REQ_GET_CONFIGURATION << 8): + /* Returning the last selected configuration.*/ + usbSetupTransfer(usbp, &usbp->configuration, 1, NULL); + return true; + case (uint32_t)USB_RTYPE_RECIPIENT_DEVICE | ((uint32_t)USB_REQ_SET_CONFIGURATION << 8): + /* Handling configuration selection from the host.*/ + usbp->configuration = usbp->setup[2]; + if (usbp->configuration == 0U) { + usbp->state = USB_SELECTED; + } + else { + usbp->state = USB_ACTIVE; + } + _usb_isr_invoke_event_cb(usbp, USB_EVENT_CONFIGURED); + usbSetupTransfer(usbp, NULL, 0, NULL); + return true; + case (uint32_t)USB_RTYPE_RECIPIENT_INTERFACE | ((uint32_t)USB_REQ_GET_STATUS << 8): + case (uint32_t)USB_RTYPE_RECIPIENT_ENDPOINT | ((uint32_t)USB_REQ_SYNCH_FRAME << 8): + /* Just sending two zero bytes, the application can change the behavior + using a hook..*/ + /*lint -save -e9005 [11.8] Removing const is fine.*/ + usbSetupTransfer(usbp, (uint8_t *)zero_status, 2, NULL); + /*lint -restore*/ + return true; + case (uint32_t)USB_RTYPE_RECIPIENT_ENDPOINT | ((uint32_t)USB_REQ_GET_STATUS << 8): + /* Sending the EP status.*/ + if ((usbp->setup[4] & 0x80U) != 0U) { + switch (usb_lld_get_status_in(usbp, usbp->setup[4] & 0x0FU)) { + case EP_STATUS_STALLED: + /*lint -save -e9005 [11.8] Removing const is fine.*/ + usbSetupTransfer(usbp, (uint8_t *)halted_status, 2, NULL); + /*lint -restore*/ + return true; + case EP_STATUS_ACTIVE: + /*lint -save -e9005 [11.8] Removing const is fine.*/ + usbSetupTransfer(usbp, (uint8_t *)active_status, 2, NULL); + /*lint -restore*/ + return true; + case EP_STATUS_DISABLED: + default: + return false; + } + } + else { + switch (usb_lld_get_status_out(usbp, usbp->setup[4] & 0x0FU)) { + case EP_STATUS_STALLED: + /*lint -save -e9005 [11.8] Removing const is fine.*/ + usbSetupTransfer(usbp, (uint8_t *)halted_status, 2, NULL); + /*lint -restore*/ + return true; + case EP_STATUS_ACTIVE: + /*lint -save -e9005 [11.8] Removing const is fine.*/ + usbSetupTransfer(usbp, (uint8_t *)active_status, 2, NULL); + /*lint -restore*/ + return true; + case EP_STATUS_DISABLED: + default: + return false; + } + } + case (uint32_t)USB_RTYPE_RECIPIENT_ENDPOINT | ((uint32_t)USB_REQ_CLEAR_FEATURE << 8): + /* Only ENDPOINT_HALT is handled as feature.*/ + if (usbp->setup[2] != USB_FEATURE_ENDPOINT_HALT) { + return false; + } + /* Clearing the EP status, not valid for EP0, it is ignored in that case.*/ + if ((usbp->setup[4] & 0x0FU) != 0U) { + if ((usbp->setup[4] & 0x80U) != 0U) { + usb_lld_clear_in(usbp, usbp->setup[4] & 0x0FU); + } + else { + usb_lld_clear_out(usbp, usbp->setup[4] & 0x0FU); + } + } + usbSetupTransfer(usbp, NULL, 0, NULL); + return true; + case (uint32_t)USB_RTYPE_RECIPIENT_ENDPOINT | ((uint32_t)USB_REQ_SET_FEATURE << 8): + /* Only ENDPOINT_HALT is handled as feature.*/ + if (usbp->setup[2] != USB_FEATURE_ENDPOINT_HALT) { + return false; + } + /* Stalling the EP, not valid for EP0, it is ignored in that case.*/ + if ((usbp->setup[4] & 0x0FU) != 0U) { + if ((usbp->setup[4] & 0x80U) != 0U) { + usb_lld_stall_in(usbp, usbp->setup[4] & 0x0FU); + } + else { + usb_lld_stall_out(usbp, usbp->setup[4] & 0x0FU); + } + } + usbSetupTransfer(usbp, NULL, 0, NULL); + return true; + case (uint32_t)USB_RTYPE_RECIPIENT_DEVICE | ((uint32_t)USB_REQ_SET_DESCRIPTOR << 8): + case (uint32_t)USB_RTYPE_RECIPIENT_INTERFACE | ((uint32_t)USB_REQ_CLEAR_FEATURE << 8): + case (uint32_t)USB_RTYPE_RECIPIENT_INTERFACE | ((uint32_t)USB_REQ_SET_FEATURE << 8): + case (uint32_t)USB_RTYPE_RECIPIENT_INTERFACE | ((uint32_t)USB_REQ_GET_INTERFACE << 8): + case (uint32_t)USB_RTYPE_RECIPIENT_INTERFACE | ((uint32_t)USB_REQ_SET_INTERFACE << 8): + /* All the above requests are not handled here, if you need them then + use the hook mechanism and provide handling.*/ + default: + return false; + } +} + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief USB Driver initialization. + * @note This function is implicitly invoked by @p halInit(), there is + * no need to explicitly initialize the driver. + * + * @init + */ +void usbInit(void) { + + usb_lld_init(); +} + +/** + * @brief Initializes the standard part of a @p USBDriver structure. + * + * @param[out] usbp pointer to the @p USBDriver object + * + * @init + */ +void usbObjectInit(USBDriver *usbp) { + unsigned i; + + usbp->state = USB_STOP; + usbp->config = NULL; + for (i = 0; i < (unsigned)USB_MAX_ENDPOINTS; i++) { + usbp->in_params[i] = NULL; + usbp->out_params[i] = NULL; + } + usbp->transmitting = 0; + usbp->receiving = 0; +} + +/** + * @brief Configures and activates the USB peripheral. + * + * @param[in] usbp pointer to the @p USBDriver object + * @param[in] config pointer to the @p USBConfig object + * + * @api + */ +void usbStart(USBDriver *usbp, const USBConfig *config) { + unsigned i; + + osalDbgCheck((usbp != NULL) && (config != NULL)); + + osalSysLock(); + osalDbgAssert((usbp->state == USB_STOP) || (usbp->state == USB_READY), + "invalid state"); + usbp->config = config; + for (i = 0; i <= (unsigned)USB_MAX_ENDPOINTS; i++) { + usbp->epc[i] = NULL; + } + usb_lld_start(usbp); + usbp->state = USB_READY; + osalSysUnlock(); +} + +/** + * @brief Deactivates the USB peripheral. + * + * @param[in] usbp pointer to the @p USBDriver object + * + * @api + */ +void usbStop(USBDriver *usbp) { + unsigned i; + + osalDbgCheck(usbp != NULL); + + osalSysLock(); + osalDbgAssert((usbp->state == USB_STOP) || (usbp->state == USB_READY) || + (usbp->state == USB_SELECTED) || (usbp->state == USB_ACTIVE) || + (usbp->state == USB_SUSPENDED), + "invalid state"); + usb_lld_stop(usbp); + usbp->state = USB_STOP; + + /* Resetting all ongoing synchronous operations.*/ + for (i = 0; i <= (unsigned)USB_MAX_ENDPOINTS; i++) { +#if USB_USE_WAIT == TRUE + if (usbp->epc[i] != NULL) { + if (usbp->epc[i]->in_state != NULL) { + osalThreadResumeI(&usbp->epc[i]->in_state->thread, MSG_RESET); + } + if (usbp->epc[i]->out_state != NULL) { + osalThreadResumeI(&usbp->epc[i]->out_state->thread, MSG_RESET); + } + } +#endif + usbp->epc[i] = NULL; + } + osalOsRescheduleS(); + osalSysUnlock(); +} + +/** + * @brief Enables an endpoint. + * @details This function enables an endpoint, both IN and/or OUT directions + * depending on the configuration structure. + * @note This function must be invoked in response of a SET_CONFIGURATION + * or SET_INTERFACE message. + * + * @param[in] usbp pointer to the @p USBDriver object + * @param[in] ep endpoint number + * @param[in] epcp the endpoint configuration + * + * @iclass + */ +void usbInitEndpointI(USBDriver *usbp, usbep_t ep, + const USBEndpointConfig *epcp) { + + osalDbgCheckClassI(); + osalDbgCheck((usbp != NULL) && (epcp != NULL)); + osalDbgAssert(usbp->state == USB_ACTIVE, + "invalid state"); + osalDbgAssert(usbp->epc[ep] == NULL, "already initialized"); + + /* Logically enabling the endpoint in the USBDriver structure.*/ + usbp->epc[ep] = epcp; + + /* Clearing the state structures, custom fields as well.*/ + if (epcp->in_state != NULL) { + memset(epcp->in_state, 0, sizeof(USBInEndpointState)); + } + if (epcp->out_state != NULL) { + memset(epcp->out_state, 0, sizeof(USBOutEndpointState)); + } + + /* Low level endpoint activation.*/ + usb_lld_init_endpoint(usbp, ep); +} + +/** + * @brief Disables all the active endpoints. + * @details This function disables all the active endpoints except the + * endpoint zero. + * @note This function must be invoked in response of a SET_CONFIGURATION + * message with configuration number zero. + * + * @param[in] usbp pointer to the @p USBDriver object + * + * @iclass + */ +void usbDisableEndpointsI(USBDriver *usbp) { + unsigned i; + + osalDbgCheckClassI(); + osalDbgCheck(usbp != NULL); + osalDbgAssert(usbp->state == USB_SELECTED, "invalid state"); + + usbp->transmitting &= ~1U; + usbp->receiving &= ~1U; + for (i = 1; i <= (unsigned)USB_MAX_ENDPOINTS; i++) { +#if USB_USE_WAIT == TRUE + /* Signaling the event to threads waiting on endpoints.*/ + if (usbp->epc[i] != NULL) { + osalSysLockFromISR(); + if (usbp->epc[i]->in_state != NULL) { + osalThreadResumeI(&usbp->epc[i]->in_state->thread, MSG_RESET); + } + if (usbp->epc[i]->out_state != NULL) { + osalThreadResumeI(&usbp->epc[i]->out_state->thread, MSG_RESET); + } + osalSysUnlockFromISR(); + } +#endif + usbp->epc[i] = NULL; + } + + /* Low level endpoints deactivation.*/ + usb_lld_disable_endpoints(usbp); +} + +/** + * @brief Starts a receive transaction on an OUT endpoint. + * @note This function is meant to be called from ISR context outside + * critical zones because there is a potentially slow operation + * inside. + * + * @param[in] usbp pointer to the @p USBDriver object + * @param[in] ep endpoint number + * @param[out] buf buffer where to copy the received data + * @param[in] n transaction size. It is recommended a multiple of + * the packet size because the excess is discarded. + * + * @iclass + */ +void usbStartReceiveI(USBDriver *usbp, usbep_t ep, + uint8_t *buf, size_t n) { + USBOutEndpointState *osp; + + osalDbgCheckClassI(); + osalDbgCheck((usbp != NULL) && (ep <= (usbep_t)USB_MAX_ENDPOINTS)); + osalDbgAssert(!usbGetReceiveStatusI(usbp, ep), "already receiving"); + + /* Marking the endpoint as active.*/ + usbp->receiving |= (uint16_t)((unsigned)1U << (unsigned)ep); + + /* Setting up the transfer.*/ + /*lint -save -e661 [18.1] pclint is confused by the check on ep.*/ + osp = usbp->epc[ep]->out_state; + /*lint -restore*/ + osp->rxbuf = buf; + osp->rxsize = n; + osp->rxcnt = 0; +#if USB_USE_WAIT == TRUE + osp->thread = NULL; +#endif + + /* Starting transfer.*/ + usb_lld_start_out(usbp, ep); +} + +/** + * @brief Starts a transmit transaction on an IN endpoint. + * @note This function is meant to be called from ISR context outside + * critical zones because there is a potentially slow operation + * inside. + * + * @param[in] usbp pointer to the @p USBDriver object + * @param[in] ep endpoint number + * @param[in] buf buffer where to fetch the data to be transmitted + * @param[in] n transaction size + * + * @iclass + */ +void usbStartTransmitI(USBDriver *usbp, usbep_t ep, + const uint8_t *buf, size_t n) { + USBInEndpointState *isp; + + osalDbgCheckClassI(); + osalDbgCheck((usbp != NULL) && (ep <= (usbep_t)USB_MAX_ENDPOINTS)); + osalDbgAssert(!usbGetTransmitStatusI(usbp, ep), "already transmitting"); + + /* Marking the endpoint as active.*/ + usbp->transmitting |= (uint16_t)((unsigned)1U << (unsigned)ep); + + /* Setting up the transfer.*/ + /*lint -save -e661 [18.1] pclint is confused by the check on ep.*/ + isp = usbp->epc[ep]->in_state; + /*lint -restore*/ + isp->txbuf = buf; + isp->txsize = n; + isp->txcnt = 0; +#if USB_USE_WAIT == TRUE + isp->thread = NULL; +#endif + + /* Starting transfer.*/ + usb_lld_start_in(usbp, ep); +} + +#if (USB_USE_WAIT == TRUE) || defined(__DOXYGEN__) +/** + * @brief Performs a receive transaction on an OUT endpoint. + * + * @param[in] usbp pointer to the @p USBDriver object + * @param[in] ep endpoint number + * @param[out] buf buffer where to copy the received data + * @param[in] n transaction size. It is recommended a multiple of + * the packet size because the excess is discarded. + * + * @return The received effective data size, it can be less than + * the amount specified. + * @retval MSG_RESET driver not in @p USB_ACTIVE state or the operation + * has been aborted by an USB reset or a transition to + * the @p USB_SUSPENDED state. + * + * @api + */ +msg_t usbReceive(USBDriver *usbp, usbep_t ep, uint8_t *buf, size_t n) { + msg_t msg; + + osalSysLock(); + + if (usbGetDriverStateI(usbp) != USB_ACTIVE) { + osalSysUnlock(); + return MSG_RESET; + } + + usbStartReceiveI(usbp, ep, buf, n); + msg = osalThreadSuspendS(&usbp->epc[ep]->out_state->thread); + osalSysUnlock(); + + return msg; +} + +/** + * @brief Performs a transmit transaction on an IN endpoint. + * + * @param[in] usbp pointer to the @p USBDriver object + * @param[in] ep endpoint number + * @param[in] buf buffer where to fetch the data to be transmitted + * @param[in] n transaction size + * + * @return The operation status. + * @retval MSG_OK operation performed successfully. + * @retval MSG_RESET driver not in @p USB_ACTIVE state or the operation + * has been aborted by an USB reset or a transition to + * the @p USB_SUSPENDED state. + * + * @api + */ +msg_t usbTransmit(USBDriver *usbp, usbep_t ep, const uint8_t *buf, size_t n) { + msg_t msg; + + osalSysLock(); + + if (usbGetDriverStateI(usbp) != USB_ACTIVE) { + osalSysUnlock(); + return MSG_RESET; + } + + usbStartTransmitI(usbp, ep, buf, n); + msg = osalThreadSuspendS(&usbp->epc[ep]->in_state->thread); + osalSysUnlock(); + + return msg; +} +#endif /* USB_USE_WAIT == TRUE */ + +/** + * @brief Stalls an OUT endpoint. + * + * @param[in] usbp pointer to the @p USBDriver object + * @param[in] ep endpoint number + * + * @return The operation status. + * @retval false Endpoint stalled. + * @retval true Endpoint busy, not stalled. + * + * @iclass + */ +bool usbStallReceiveI(USBDriver *usbp, usbep_t ep) { + + osalDbgCheckClassI(); + osalDbgCheck(usbp != NULL); + + if (usbGetReceiveStatusI(usbp, ep)) { + return true; + } + + usb_lld_stall_out(usbp, ep); + return false; +} + +/** + * @brief Stalls an IN endpoint. + * + * @param[in] usbp pointer to the @p USBDriver object + * @param[in] ep endpoint number + * + * @return The operation status. + * @retval false Endpoint stalled. + * @retval true Endpoint busy, not stalled. + * + * @iclass + */ +bool usbStallTransmitI(USBDriver *usbp, usbep_t ep) { + + osalDbgCheckClassI(); + osalDbgCheck(usbp != NULL); + + if (usbGetTransmitStatusI(usbp, ep)) { + return true; + } + + usb_lld_stall_in(usbp, ep); + return false; +} + +/** + * @brief USB reset routine. + * @details This function must be invoked when an USB bus reset condition is + * detected. + * + * @param[in] usbp pointer to the @p USBDriver object + * + * @notapi + */ +void _usb_reset(USBDriver *usbp) { + unsigned i; + + /* State transition.*/ + usbp->state = USB_READY; + + /* Resetting internal state.*/ + usbp->status = 0; + usbp->address = 0; + usbp->configuration = 0; + usbp->transmitting = 0; + usbp->receiving = 0; + + /* Invalidates all endpoints into the USBDriver structure.*/ + for (i = 0; i <= (unsigned)USB_MAX_ENDPOINTS; i++) { +#if USB_USE_WAIT == TRUE + /* Signaling the event to threads waiting on endpoints.*/ + if (usbp->epc[i] != NULL) { + osalSysLockFromISR(); + if (usbp->epc[i]->in_state != NULL) { + osalThreadResumeI(&usbp->epc[i]->in_state->thread, MSG_RESET); + } + if (usbp->epc[i]->out_state != NULL) { + osalThreadResumeI(&usbp->epc[i]->out_state->thread, MSG_RESET); + } + osalSysUnlockFromISR(); + } +#endif + usbp->epc[i] = NULL; + } + + /* EP0 state machine initialization.*/ + usbp->ep0state = USB_EP0_WAITING_SETUP; + + /* Low level reset.*/ + usb_lld_reset(usbp); + + /* Notification of reset event.*/ + _usb_isr_invoke_event_cb(usbp, USB_EVENT_RESET); +} + +/** + * @brief USB suspend routine. + * @details This function must be invoked when an USB bus suspend condition is + * detected. + * + * @param[in] usbp pointer to the @p USBDriver object + * + * @notapi + */ +void _usb_suspend(USBDriver *usbp) { + + /* State transition.*/ + usbp->state = USB_SUSPENDED; + + /* Notification of suspend event.*/ + _usb_isr_invoke_event_cb(usbp, USB_EVENT_SUSPEND); + + /* Signaling the event to threads waiting on endpoints.*/ +#if USB_USE_WAIT == TRUE + { + unsigned i; + + for (i = 0; i <= (unsigned)USB_MAX_ENDPOINTS; i++) { + if (usbp->epc[i] != NULL) { + osalSysLockFromISR(); + if (usbp->epc[i]->in_state != NULL) { + osalThreadResumeI(&usbp->epc[i]->in_state->thread, MSG_RESET); + } + if (usbp->epc[i]->out_state != NULL) { + osalThreadResumeI(&usbp->epc[i]->out_state->thread, MSG_RESET); + } + osalSysUnlockFromISR(); + } + } + } +#endif +} + +/** + * @brief USB wake-up routine. + * @details This function must be invoked when an USB bus wake-up condition is + * detected. + * + * @param[in] usbp pointer to the @p USBDriver object + * + * @notapi + */ +void _usb_wakeup(USBDriver *usbp) { + + /* State transition.*/ + usbp->state = USB_ACTIVE; + + /* Notification of suspend event.*/ + _usb_isr_invoke_event_cb(usbp, USB_EVENT_WAKEUP); +} + +/** + * @brief Default EP0 SETUP callback. + * @details This function is used by the low level driver as default handler + * for EP0 SETUP events. + * + * @param[in] usbp pointer to the @p USBDriver object + * @param[in] ep endpoint number, always zero + * + * @notapi + */ +void _usb_ep0setup(USBDriver *usbp, usbep_t ep) { + size_t max; + + usbp->ep0state = USB_EP0_WAITING_SETUP; + usbReadSetup(usbp, ep, usbp->setup); + + /* First verify if the application has an handler installed for this + request.*/ + /*lint -save -e9007 [13.5] No side effects, it is intentional.*/ + if ((usbp->config->requests_hook_cb == NULL) || + !(usbp->config->requests_hook_cb(usbp))) { + /*lint -restore*/ + /* Invoking the default handler, if this fails then stalls the + endpoint zero as error.*/ + /*lint -save -e9007 [13.5] No side effects, it is intentional.*/ + if (((usbp->setup[0] & USB_RTYPE_TYPE_MASK) != USB_RTYPE_TYPE_STD) || + !default_handler(usbp)) { + /*lint -restore*/ + /* Error response, the state machine goes into an error state, the low + level layer will have to reset it to USB_EP0_WAITING_SETUP after + receiving a SETUP packet.*/ + usb_lld_stall_in(usbp, 0); + usb_lld_stall_out(usbp, 0); + _usb_isr_invoke_event_cb(usbp, USB_EVENT_STALLED); + usbp->ep0state = USB_EP0_ERROR; + return; + } + } +#if (USB_SET_ADDRESS_ACK_HANDLING == USB_SET_ADDRESS_ACK_HW) + if (usbp->setup[1] == USB_REQ_SET_ADDRESS) { + /* Zero-length packet sent by hardware */ + return; + } +#endif + /* Transfer preparation. The request handler must have populated + correctly the fields ep0next, ep0n and ep0endcb using the macro + usbSetupTransfer().*/ + max = (size_t)get_hword(&usbp->setup[6]); + /* The transfer size cannot exceed the specified amount.*/ + if (usbp->ep0n > max) { + usbp->ep0n = max; + } + if ((usbp->setup[0] & USB_RTYPE_DIR_MASK) == USB_RTYPE_DIR_DEV2HOST) { + /* IN phase.*/ + if (usbp->ep0n != 0U) { + /* Starts the transmit phase.*/ + usbp->ep0state = USB_EP0_TX; + osalSysLockFromISR(); + usbStartTransmitI(usbp, 0, usbp->ep0next, usbp->ep0n); + osalSysUnlockFromISR(); + } + else { + /* No transmission phase, directly receiving the zero sized status + packet.*/ + usbp->ep0state = USB_EP0_WAITING_STS; +#if (USB_EP0_STATUS_STAGE == USB_EP0_STATUS_STAGE_SW) + osalSysLockFromISR(); + usbStartReceiveI(usbp, 0, NULL, 0); + osalSysUnlockFromISR(); +#else + usb_lld_end_setup(usbp, ep); +#endif + } + } + else { + /* OUT phase.*/ + if (usbp->ep0n != 0U) { + /* Starts the receive phase.*/ + usbp->ep0state = USB_EP0_RX; + osalSysLockFromISR(); + usbStartReceiveI(usbp, 0, usbp->ep0next, usbp->ep0n); + osalSysUnlockFromISR(); + } + else { + /* No receive phase, directly sending the zero sized status + packet.*/ + usbp->ep0state = USB_EP0_SENDING_STS; +#if (USB_EP0_STATUS_STAGE == USB_EP0_STATUS_STAGE_SW) + osalSysLockFromISR(); + usbStartTransmitI(usbp, 0, NULL, 0); + osalSysUnlockFromISR(); +#else + usb_lld_end_setup(usbp, ep); +#endif + } + } +} + +/** + * @brief Default EP0 IN callback. + * @details This function is used by the low level driver as default handler + * for EP0 IN events. + * + * @param[in] usbp pointer to the @p USBDriver object + * @param[in] ep endpoint number, always zero + * + * @notapi + */ +void _usb_ep0in(USBDriver *usbp, usbep_t ep) { + size_t max; + + (void)ep; + switch (usbp->ep0state) { + case USB_EP0_TX: + max = (size_t)get_hword(&usbp->setup[6]); + /* If the transmitted size is less than the requested size and it is a + multiple of the maximum packet size then a zero size packet must be + transmitted.*/ + if ((usbp->ep0n < max) && + ((usbp->ep0n % usbp->epc[0]->in_maxsize) == 0U)) { + osalSysLockFromISR(); + usbStartTransmitI(usbp, 0, NULL, 0); + osalSysUnlockFromISR(); + usbp->ep0state = USB_EP0_WAITING_TX0; + return; + } + /* Falls into, it is intentional.*/ + case USB_EP0_WAITING_TX0: + /* Transmit phase over, receiving the zero sized status packet.*/ + usbp->ep0state = USB_EP0_WAITING_STS; +#if (USB_EP0_STATUS_STAGE == USB_EP0_STATUS_STAGE_SW) + osalSysLockFromISR(); + usbStartReceiveI(usbp, 0, NULL, 0); + osalSysUnlockFromISR(); +#else + usb_lld_end_setup(usbp, ep); +#endif + return; + case USB_EP0_SENDING_STS: + /* Status packet sent, invoking the callback if defined.*/ + if (usbp->ep0endcb != NULL) { + usbp->ep0endcb(usbp); + } + usbp->ep0state = USB_EP0_WAITING_SETUP; + return; + case USB_EP0_WAITING_SETUP: + case USB_EP0_WAITING_STS: + case USB_EP0_RX: + /* All the above are invalid states in the IN phase.*/ + osalDbgAssert(false, "EP0 state machine error"); + /* Falling through is intentional.*/ + case USB_EP0_ERROR: + /* Error response, the state machine goes into an error state, the low + level layer will have to reset it to USB_EP0_WAITING_SETUP after + receiving a SETUP packet.*/ + usb_lld_stall_in(usbp, 0); + usb_lld_stall_out(usbp, 0); + _usb_isr_invoke_event_cb(usbp, USB_EVENT_STALLED); + usbp->ep0state = USB_EP0_ERROR; + return; + default: + osalDbgAssert(false, "EP0 state machine invalid state"); + } +} + +/** + * @brief Default EP0 OUT callback. + * @details This function is used by the low level driver as default handler + * for EP0 OUT events. + * + * @param[in] usbp pointer to the @p USBDriver object + * @param[in] ep endpoint number, always zero + * + * @notapi + */ +void _usb_ep0out(USBDriver *usbp, usbep_t ep) { + + (void)ep; + switch (usbp->ep0state) { + case USB_EP0_RX: + /* Receive phase over, sending the zero sized status packet.*/ + usbp->ep0state = USB_EP0_SENDING_STS; +#if (USB_EP0_STATUS_STAGE == USB_EP0_STATUS_STAGE_SW) + osalSysLockFromISR(); + usbStartTransmitI(usbp, 0, NULL, 0); + osalSysUnlockFromISR(); +#else + usb_lld_end_setup(usbp, ep); +#endif + return; + case USB_EP0_WAITING_STS: + /* Status packet received, it must be zero sized, invoking the callback + if defined.*/ +#if (USB_EP0_STATUS_STAGE == USB_EP0_STATUS_STAGE_SW) + if (usbGetReceiveTransactionSizeX(usbp, 0) != 0U) { + break; + } +#endif + if (usbp->ep0endcb != NULL) { + usbp->ep0endcb(usbp); + } + usbp->ep0state = USB_EP0_WAITING_SETUP; + return; + case USB_EP0_WAITING_SETUP: + case USB_EP0_TX: + case USB_EP0_WAITING_TX0: + case USB_EP0_SENDING_STS: + /* All the above are invalid states in the IN phase.*/ + osalDbgAssert(false, "EP0 state machine error"); + /* Falling through is intentional.*/ + case USB_EP0_ERROR: + /* Error response, the state machine goes into an error state, the low + level layer will have to reset it to USB_EP0_WAITING_SETUP after + receiving a SETUP packet.*/ + usb_lld_stall_in(usbp, 0); + usb_lld_stall_out(usbp, 0); + _usb_isr_invoke_event_cb(usbp, USB_EVENT_STALLED); + usbp->ep0state = USB_EP0_ERROR; + return; + default: + osalDbgAssert(false, "EP0 state machine invalid state"); + } +} + +#endif /* HAL_USE_USB == TRUE */ + +/** @} */ diff --git a/os/hal/src/hal_wdg.c b/os/hal/src/hal_wdg.c new file mode 100644 index 000000000..a764864a4 --- /dev/null +++ b/os/hal/src/hal_wdg.c @@ -0,0 +1,120 @@ +/* + ChibiOS - Copyright (C) 2006..2016 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 wdg.c + * @brief WDG Driver code. + * + * @addtogroup WDG + * @{ + */ + +#include "hal.h" + +#if (HAL_USE_WDG == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief WDG Driver initialization. + * @note This function is implicitly invoked by @p halInit(), there is + * no need to explicitly initialize the driver. + * + * @init + */ +void wdgInit(void) { + + wdg_lld_init(); +} + +/** + * @brief Configures and activates the WDG peripheral. + * + * @param[in] wdgp pointer to the @p WDGDriver object + * @param[in] config pointer to the @p WDGConfig object + * + * @api + */ +void wdgStart(WDGDriver *wdgp, const WDGConfig *config) { + + osalDbgCheck((wdgp != NULL) && (config != NULL)); + + osalSysLock(); + osalDbgAssert((wdgp->state == WDG_STOP) || (wdgp->state == WDG_READY), + "invalid state"); + wdgp->config = config; + wdg_lld_start(wdgp); + wdgp->state = WDG_READY; + osalSysUnlock(); +} + +/** + * @brief Deactivates the WDG peripheral. + * + * @param[in] wdgp pointer to the @p WDGDriver object + * + * @api + */ +void wdgStop(WDGDriver *wdgp) { + + osalDbgCheck(wdgp != NULL); + + osalSysLock(); + osalDbgAssert((wdgp->state == WDG_STOP) || (wdgp->state == WDG_READY), + "invalid state"); + wdg_lld_stop(wdgp); + wdgp->state = WDG_STOP; + osalSysUnlock(); +} + +/** + * @brief Resets WDG's counter. + * + * @param[in] wdgp pointer to the @p WDGDriver object + * + * @api + */ +void wdgReset(WDGDriver *wdgp) { + + osalDbgCheck(wdgp != NULL); + + osalSysLock(); + osalDbgAssert(wdgp->state == WDG_READY, "not ready"); + wdgResetI(wdgp); + osalSysUnlock(); +} + +#endif /* HAL_USE_WDG == TRUE */ + +/** @} */ diff --git a/os/hal/src/i2c.c b/os/hal/src/i2c.c deleted file mode 100644 index 0ed77eeaf..000000000 --- a/os/hal/src/i2c.c +++ /dev/null @@ -1,283 +0,0 @@ -/* - ChibiOS - Copyright (C) 2006..2016 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. -*/ -/* - Concepts and parts of this file have been contributed by Uladzimir Pylinsky - aka barthess. - */ - -/** - * @file i2c.c - * @brief I2C Driver code. - * - * @addtogroup I2C - * @{ - */ -#include "hal.h" - -#if (HAL_USE_I2C == TRUE) || defined(__DOXYGEN__) - -/*===========================================================================*/ -/* Driver local definitions. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver exported variables. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver local variables and types. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver local functions. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver exported functions. */ -/*===========================================================================*/ - -/** - * @brief I2C Driver initialization. - * @note This function is implicitly invoked by @p halInit(), there is - * no need to explicitly initialize the driver. - * - * @init - */ -void i2cInit(void) { - - i2c_lld_init(); -} - -/** - * @brief Initializes the standard part of a @p I2CDriver structure. - * - * @param[out] i2cp pointer to the @p I2CDriver object - * - * @init - */ -void i2cObjectInit(I2CDriver *i2cp) { - - i2cp->state = I2C_STOP; - i2cp->config = NULL; - -#if I2C_USE_MUTUAL_EXCLUSION == TRUE - osalMutexObjectInit(&i2cp->mutex); -#endif - -#if defined(I2C_DRIVER_EXT_INIT_HOOK) - I2C_DRIVER_EXT_INIT_HOOK(i2cp); -#endif -} - -/** - * @brief Configures and activates the I2C peripheral. - * - * @param[in] i2cp pointer to the @p I2CDriver object - * @param[in] config pointer to the @p I2CConfig object - * - * @api - */ -void i2cStart(I2CDriver *i2cp, const I2CConfig *config) { - - osalDbgCheck((i2cp != NULL) && (config != NULL)); - osalDbgAssert((i2cp->state == I2C_STOP) || (i2cp->state == I2C_READY) || - (i2cp->state == I2C_LOCKED), "invalid state"); - - osalSysLock(); - i2cp->config = config; - i2c_lld_start(i2cp); - i2cp->state = I2C_READY; - osalSysUnlock(); -} - -/** - * @brief Deactivates the I2C peripheral. - * - * @param[in] i2cp pointer to the @p I2CDriver object - * - * @api - */ -void i2cStop(I2CDriver *i2cp) { - - osalDbgCheck(i2cp != NULL); - osalDbgAssert((i2cp->state == I2C_STOP) || (i2cp->state == I2C_READY) || - (i2cp->state == I2C_LOCKED), "invalid state"); - - osalSysLock(); - i2c_lld_stop(i2cp); - i2cp->state = I2C_STOP; - osalSysUnlock(); -} - -/** - * @brief Returns the errors mask associated to the previous operation. - * - * @param[in] i2cp pointer to the @p I2CDriver object - * @return The errors mask. - * - * @api - */ -i2cflags_t i2cGetErrors(I2CDriver *i2cp) { - - osalDbgCheck(i2cp != NULL); - - return i2c_lld_get_errors(i2cp); -} - -/** - * @brief Sends data via the I2C bus. - * @details Function designed to realize "read-through-write" transfer - * paradigm. If you want transmit data without any further read, - * than set @b rxbytes field to 0. - * - * @param[in] i2cp pointer to the @p I2CDriver object - * @param[in] addr slave device address (7 bits) without R/W bit - * @param[in] txbuf pointer to transmit buffer - * @param[in] txbytes number of bytes to be transmitted - * @param[out] rxbuf pointer to receive buffer - * @param[in] rxbytes number of bytes to be received, set it to 0 if - * you want transmit only - * @param[in] timeout the number of ticks before the operation timeouts, - * the following special values are allowed: - * - @a TIME_INFINITE no timeout. - * . - * - * @return The operation status. - * @retval MSG_OK if the function succeeded. - * @retval MSG_RESET if one or more I2C errors occurred, the errors can - * be retrieved using @p i2cGetErrors(). - * @retval MSG_TIMEOUT if a timeout occurred before operation end. - * - * @api - */ -msg_t i2cMasterTransmitTimeout(I2CDriver *i2cp, - i2caddr_t addr, - const uint8_t *txbuf, - size_t txbytes, - uint8_t *rxbuf, - size_t rxbytes, - systime_t timeout) { - msg_t rdymsg; - - osalDbgCheck((i2cp != NULL) && (addr != 0U) && - (txbytes > 0U) && (txbuf != NULL) && - ((rxbytes == 0U) || ((rxbytes > 0U) && (rxbuf != NULL))) && - (timeout != TIME_IMMEDIATE)); - - osalDbgAssert(i2cp->state == I2C_READY, "not ready"); - - osalSysLock(); - i2cp->errors = I2C_NO_ERROR; - i2cp->state = I2C_ACTIVE_TX; - rdymsg = i2c_lld_master_transmit_timeout(i2cp, addr, txbuf, txbytes, - rxbuf, rxbytes, timeout); - if (rdymsg == MSG_TIMEOUT) { - i2cp->state = I2C_LOCKED; - } - else { - i2cp->state = I2C_READY; - } - osalSysUnlock(); - return rdymsg; -} - -/** - * @brief Receives data from the I2C bus. - * - * @param[in] i2cp pointer to the @p I2CDriver object - * @param[in] addr slave device address (7 bits) without R/W bit - * @param[out] rxbuf pointer to receive buffer - * @param[in] rxbytes number of bytes to be received - * @param[in] timeout the number of ticks before the operation timeouts, - * the following special values are allowed: - * - @a TIME_INFINITE no timeout. - * . - * - * @return The operation status. - * @retval MSG_OK if the function succeeded. - * @retval MSG_RESET if one or more I2C errors occurred, the errors can - * be retrieved using @p i2cGetErrors(). - * @retval MSG_TIMEOUT if a timeout occurred before operation end. - * - * @api - */ -msg_t i2cMasterReceiveTimeout(I2CDriver *i2cp, - i2caddr_t addr, - uint8_t *rxbuf, - size_t rxbytes, - systime_t timeout){ - - msg_t rdymsg; - - osalDbgCheck((i2cp != NULL) && (addr != 0U) && - (rxbytes > 0U) && (rxbuf != NULL) && - (timeout != TIME_IMMEDIATE)); - - osalDbgAssert(i2cp->state == I2C_READY, "not ready"); - - osalSysLock(); - i2cp->errors = I2C_NO_ERROR; - i2cp->state = I2C_ACTIVE_RX; - rdymsg = i2c_lld_master_receive_timeout(i2cp, addr, rxbuf, rxbytes, timeout); - if (rdymsg == MSG_TIMEOUT) { - i2cp->state = I2C_LOCKED; - } - else { - i2cp->state = I2C_READY; - } - osalSysUnlock(); - return rdymsg; -} - -#if (I2C_USE_MUTUAL_EXCLUSION == TRUE) || defined(__DOXYGEN__) -/** - * @brief Gains exclusive access to the I2C bus. - * @details This function tries to gain ownership to the I2C bus, if the bus - * is already being used then the invoking thread is queued. - * @pre In order to use this function the option @p I2C_USE_MUTUAL_EXCLUSION - * must be enabled. - * - * @param[in] i2cp pointer to the @p I2CDriver object - * - * @api - */ -void i2cAcquireBus(I2CDriver *i2cp) { - - osalDbgCheck(i2cp != NULL); - - osalMutexLock(&i2cp->mutex); -} - -/** - * @brief Releases exclusive access to the I2C bus. - * @pre In order to use this function the option @p I2C_USE_MUTUAL_EXCLUSION - * must be enabled. - * - * @param[in] i2cp pointer to the @p I2CDriver object - * - * @api - */ -void i2cReleaseBus(I2CDriver *i2cp) { - - osalDbgCheck(i2cp != NULL); - - osalMutexUnlock(&i2cp->mutex); -} -#endif /* I2C_USE_MUTUAL_EXCLUSION == TRUE */ - -#endif /* HAL_USE_I2C == TRUE */ - -/** @} */ diff --git a/os/hal/src/i2s.c b/os/hal/src/i2s.c deleted file mode 100644 index 57a43a7e3..000000000 --- a/os/hal/src/i2s.c +++ /dev/null @@ -1,155 +0,0 @@ -/* - ChibiOS - Copyright (C) 2006..2016 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 i2s.c - * @brief I2S Driver code. - * - * @addtogroup I2S - * @{ - */ - -#include "hal.h" - -#if (HAL_USE_I2S == TRUE) || defined(__DOXYGEN__) - -/*===========================================================================*/ -/* Driver local definitions. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver exported variables. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver local variables and types. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver local functions. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver exported functions. */ -/*===========================================================================*/ - -/** - * @brief I2S Driver initialization. - * @note This function is implicitly invoked by @p halInit(), there is - * no need to explicitly initialize the driver. - * - * @init - */ -void i2sInit(void) { - - i2s_lld_init(); -} - -/** - * @brief Initializes the standard part of a @p I2SDriver structure. - * - * @param[out] i2sp pointer to the @p I2SDriver object - * - * @init - */ -void i2sObjectInit(I2SDriver *i2sp) { - - i2sp->state = I2S_STOP; - i2sp->config = NULL; -} - -/** - * @brief Configures and activates the I2S peripheral. - * - * @param[in] i2sp pointer to the @p I2SDriver object - * @param[in] config pointer to the @p I2SConfig object - * - * @api - */ -void i2sStart(I2SDriver *i2sp, const I2SConfig *config) { - - osalDbgCheck((i2sp != NULL) && (config != NULL)); - - osalSysLock(); - osalDbgAssert((i2sp->state == I2S_STOP) || (i2sp->state == I2S_READY), - "invalid state"); - i2sp->config = config; - i2s_lld_start(i2sp); - i2sp->state = I2S_READY; - osalSysUnlock(); -} - -/** - * @brief Deactivates the I2S peripheral. - * - * @param[in] i2sp pointer to the @p I2SDriver object - * - * @api - */ -void i2sStop(I2SDriver *i2sp) { - - osalDbgCheck(i2sp != NULL); - - osalSysLock(); - osalDbgAssert((i2sp->state == I2S_STOP) || (i2sp->state == I2S_READY), - "invalid state"); - i2s_lld_stop(i2sp); - i2sp->state = I2S_STOP; - osalSysUnlock(); -} - -/** - * @brief Starts a I2S data exchange. - * - * @param[in] i2sp pointer to the @p I2SDriver object - * - * @api - */ -void i2sStartExchange(I2SDriver *i2sp) { - - osalDbgCheck(i2sp != NULL); - - osalSysLock(); - osalDbgAssert(i2sp->state == I2S_READY, "not ready"); - i2sStartExchangeI(i2sp); - osalSysUnlock(); -} - -/** - * @brief Stops the ongoing data exchange. - * @details The ongoing data exchange, if any, is stopped, if the driver - * was not active the function does nothing. - * - * @param[in] i2sp pointer to the @p I2SDriver object - * - * @api - */ -void i2sStopExchange(I2SDriver *i2sp) { - - osalDbgCheck((i2sp != NULL)); - - osalSysLock(); - osalDbgAssert((i2sp->state == I2S_READY) || - (i2sp->state == I2S_ACTIVE) || - (i2sp->state == I2S_COMPLETE), - "invalid state"); - i2sStopExchangeI(i2sp); - osalSysUnlock(); -} - -#endif /* HAL_USE_I2S == TRUE */ - -/** @} */ diff --git a/os/hal/src/icu.c b/os/hal/src/icu.c deleted file mode 100644 index ab42dc8ce..000000000 --- a/os/hal/src/icu.c +++ /dev/null @@ -1,225 +0,0 @@ -/* - ChibiOS - Copyright (C) 2006..2016 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 icu.c - * @brief ICU Driver code. - * - * @addtogroup ICU - * @{ - */ - -#include "hal.h" - -#if (HAL_USE_ICU == TRUE) || defined(__DOXYGEN__) - -/*===========================================================================*/ -/* Driver local definitions. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver exported variables. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver local variables and types. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver local functions. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver exported functions. */ -/*===========================================================================*/ - -/** - * @brief ICU Driver initialization. - * @note This function is implicitly invoked by @p halInit(), there is - * no need to explicitly initialize the driver. - * - * @init - */ -void icuInit(void) { - - icu_lld_init(); -} - -/** - * @brief Initializes the standard part of a @p ICUDriver structure. - * - * @param[out] icup pointer to the @p ICUDriver object - * - * @init - */ -void icuObjectInit(ICUDriver *icup) { - - icup->state = ICU_STOP; - icup->config = NULL; -} - -/** - * @brief Configures and activates the ICU peripheral. - * - * @param[in] icup pointer to the @p ICUDriver object - * @param[in] config pointer to the @p ICUConfig object - * - * @api - */ -void icuStart(ICUDriver *icup, const ICUConfig *config) { - - osalDbgCheck((icup != NULL) && (config != NULL)); - - osalSysLock(); - osalDbgAssert((icup->state == ICU_STOP) || (icup->state == ICU_READY), - "invalid state"); - icup->config = config; - icu_lld_start(icup); - icup->state = ICU_READY; - osalSysUnlock(); -} - -/** - * @brief Deactivates the ICU peripheral. - * - * @param[in] icup pointer to the @p ICUDriver object - * - * @api - */ -void icuStop(ICUDriver *icup) { - - osalDbgCheck(icup != NULL); - - osalSysLock(); - osalDbgAssert((icup->state == ICU_STOP) || (icup->state == ICU_READY), - "invalid state"); - icu_lld_stop(icup); - icup->state = ICU_STOP; - osalSysUnlock(); -} - -/** - * @brief Starts the input capture. - * - * @param[in] icup pointer to the @p ICUDriver object - * - * @api - */ -void icuStartCapture(ICUDriver *icup) { - - osalDbgCheck(icup != NULL); - - osalSysLock(); - osalDbgAssert(icup->state == ICU_READY, "invalid state"); - icuStartCaptureI(icup); - osalSysUnlock(); -} - -/** - * @brief Waits for a completed capture. - * @note The operation could be performed in polled mode depending on. - * @note In order to use this function notifications must be disabled. - * @pre The driver must be in @p ICU_WAITING or @p ICU_ACTIVE states. - * @post After the capture is available the driver is in @p ICU_ACTIVE - * state. If a capture fails then the driver is in @p ICU_WAITING - * state. - * - * @param[in] icup pointer to the @p ICUDriver object - * @return The capture status. - * @retval false if the capture is successful. - * @retval true if a timer overflow occurred. - * - * @api - */ -bool icuWaitCapture(ICUDriver *icup) { - bool result; - - osalDbgCheck(icup != NULL); - - osalSysLock(); - osalDbgAssert((icup->state == ICU_WAITING) || (icup->state == ICU_ACTIVE), - "invalid state"); - osalDbgAssert(icuAreNotificationsEnabledX(icup) == false, - "notifications enabled"); - result = icu_lld_wait_capture(icup); - icup->state = result ? ICU_WAITING : ICU_ACTIVE; - osalSysUnlock(); - - return result; -} - -/** - * @brief Stops the input capture. - * - * @param[in] icup pointer to the @p ICUDriver object - * - * @api - */ -void icuStopCapture(ICUDriver *icup) { - - osalDbgCheck(icup != NULL); - - osalSysLock(); - osalDbgAssert((icup->state == ICU_READY) || (icup->state == ICU_WAITING) || - (icup->state == ICU_ACTIVE), - "invalid state"); - icuStopCaptureI(icup); - osalSysUnlock(); -} - -/** - * @brief Enables notifications. - * @pre The ICU unit must have been activated using @p icuStart(). - * @note If the notification is already enabled then the call has no effect. - * - * @param[in] icup pointer to the @p ICUDriver object - * - * @api - */ -void icuEnableNotifications(ICUDriver *icup) { - - osalDbgCheck(icup != NULL); - - osalSysLock(); - osalDbgAssert((icup->state == ICU_WAITING) || (icup->state == ICU_ACTIVE), - "invalid state"); - icuEnableNotificationsI(icup); - osalSysUnlock(); -} - -/** - * @brief Disables notifications. - * @pre The ICU unit must have been activated using @p icuStart(). - * @note If the notification is already disabled then the call has no effect. - * - * @param[in] icup pointer to the @p ICUDriver object - * - * @api - */ -void icuDisableNotifications(ICUDriver *icup) { - - osalDbgCheck(icup != NULL); - - osalSysLock(); - osalDbgAssert((icup->state == ICU_WAITING) || (icup->state == ICU_ACTIVE), - "invalid state"); - icuDisableNotificationsI(icup); - osalSysUnlock(); -} - -#endif /* HAL_USE_ICU == TRUE */ - -/** @} */ diff --git a/os/hal/src/mac.c b/os/hal/src/mac.c deleted file mode 100644 index 18add7560..000000000 --- a/os/hal/src/mac.c +++ /dev/null @@ -1,268 +0,0 @@ -/* - ChibiOS - Copyright (C) 2006..2016 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 mac.c - * @brief MAC Driver code. - * - * @addtogroup MAC - * @{ - */ - -#include "hal.h" - -#if (HAL_USE_MAC == TRUE) || defined(__DOXYGEN__) - -/*===========================================================================*/ -/* Driver local definitions. */ -/*===========================================================================*/ - -#if (MAC_USE_ZERO_COPY == TRUE) && (MAC_SUPPORTS_ZERO_COPY == FALSE) -#error "MAC_USE_ZERO_COPY not supported by this implementation" -#endif - -/*===========================================================================*/ -/* Driver exported variables. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver local variables and types. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver local functions. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver interrupt handlers. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver exported functions. */ -/*===========================================================================*/ - -/** - * @brief MAC Driver initialization. - * @note This function is implicitly invoked by @p halInit(), there is - * no need to explicitly initialize the driver. - * - * @init - */ -void macInit(void) { - - mac_lld_init(); -} - -/** - * @brief Initialize the standard part of a @p MACDriver structure. - * - * @param[out] macp pointer to the @p MACDriver object - * - * @init - */ -void macObjectInit(MACDriver *macp) { - - macp->state = MAC_STOP; - macp->config = NULL; - osalThreadQueueObjectInit(&macp->tdqueue); - osalThreadQueueObjectInit(&macp->rdqueue); -#if MAC_USE_EVENTS == TRUE - osalEventObjectInit(&macp->rdevent); -#endif -} - -/** - * @brief Configures and activates the MAC peripheral. - * - * @param[in] macp pointer to the @p MACDriver object - * @param[in] config pointer to the @p MACConfig object - * - * @api - */ -void macStart(MACDriver *macp, const MACConfig *config) { - - osalDbgCheck((macp != NULL) && (config != NULL)); - - osalSysLock(); - osalDbgAssert(macp->state == MAC_STOP, - "invalid state"); - macp->config = config; - mac_lld_start(macp); - macp->state = MAC_ACTIVE; - osalSysUnlock(); -} - -/** - * @brief Deactivates the MAC peripheral. - * - * @param[in] macp pointer to the @p MACDriver object - * - * @api - */ -void macStop(MACDriver *macp) { - - osalDbgCheck(macp != NULL); - - osalSysLock(); - osalDbgAssert((macp->state == MAC_STOP) || (macp->state == MAC_ACTIVE), - "invalid state"); - mac_lld_stop(macp); - macp->state = MAC_STOP; - osalSysUnlock(); -} - -/** - * @brief Allocates a transmission descriptor. - * @details One of the available transmission descriptors is locked and - * returned. If a descriptor is not currently available then the - * invoking thread is queued until one is freed. - * - * @param[in] macp pointer to the @p MACDriver object - * @param[out] tdp pointer to a @p MACTransmitDescriptor structure - * @param[in] timeout the number of ticks before the operation timeouts, - * the following special values are allowed: - * - @a TIME_IMMEDIATE immediate timeout. - * - @a TIME_INFINITE no timeout. - * . - * @return The operation status. - * @retval MSG_OK the descriptor was obtained. - * @retval MSG_TIMEOUT the operation timed out, descriptor not initialized. - * - * @api - */ -msg_t macWaitTransmitDescriptor(MACDriver *macp, - MACTransmitDescriptor *tdp, - systime_t timeout) { - msg_t msg; - systime_t now; - - osalDbgCheck((macp != NULL) && (tdp != NULL)); - osalDbgAssert(macp->state == MAC_ACTIVE, "not active"); - - while (((msg = mac_lld_get_transmit_descriptor(macp, tdp)) != MSG_OK) && - (timeout > (systime_t)0)) { - osalSysLock(); - now = osalOsGetSystemTimeX(); - msg = osalThreadEnqueueTimeoutS(&macp->tdqueue, timeout); - if (msg == MSG_TIMEOUT) { - osalSysUnlock(); - break; - } - if (timeout != TIME_INFINITE) { - timeout -= (osalOsGetSystemTimeX() - now); - } - osalSysUnlock(); - } - return msg; -} - -/** - * @brief Releases a transmit descriptor and starts the transmission of the - * enqueued data as a single frame. - * - * @param[in] tdp the pointer to the @p MACTransmitDescriptor structure - * - * @api - */ -void macReleaseTransmitDescriptor(MACTransmitDescriptor *tdp) { - - osalDbgCheck(tdp != NULL); - - mac_lld_release_transmit_descriptor(tdp); -} - -/** - * @brief Waits for a received frame. - * @details Stops until a frame is received and buffered. If a frame is - * not immediately available then the invoking thread is queued - * until one is received. - * - * @param[in] macp pointer to the @p MACDriver object - * @param[out] rdp pointer to a @p MACReceiveDescriptor structure - * @param[in] timeout the number of ticks before the operation timeouts, - * the following special values are allowed: - * - @a TIME_IMMEDIATE immediate timeout. - * - @a TIME_INFINITE no timeout. - * . - * @return The operation status. - * @retval MSG_OK the descriptor was obtained. - * @retval MSG_TIMEOUT the operation timed out, descriptor not initialized. - * - * @api - */ -msg_t macWaitReceiveDescriptor(MACDriver *macp, - MACReceiveDescriptor *rdp, - systime_t timeout) { - msg_t msg; - systime_t now; - - osalDbgCheck((macp != NULL) && (rdp != NULL)); - osalDbgAssert(macp->state == MAC_ACTIVE, "not active"); - - while (((msg = mac_lld_get_receive_descriptor(macp, rdp)) != MSG_OK) && - (timeout > (systime_t)0)) { - osalSysLock(); - now = osalOsGetSystemTimeX(); - msg = osalThreadEnqueueTimeoutS(&macp->rdqueue, timeout); - if (msg == MSG_TIMEOUT) { - osalSysUnlock(); - break; - } - if (timeout != TIME_INFINITE) { - timeout -= (osalOsGetSystemTimeX() - now); - } - osalSysUnlock(); - } - return msg; -} - -/** - * @brief Releases a receive descriptor. - * @details The descriptor and its buffer are made available for more incoming - * frames. - * - * @param[in] rdp the pointer to the @p MACReceiveDescriptor structure - * - * @api - */ -void macReleaseReceiveDescriptor(MACReceiveDescriptor *rdp) { - - osalDbgCheck(rdp != NULL); - - mac_lld_release_receive_descriptor(rdp); -} - -/** - * @brief Updates and returns the link status. - * - * @param[in] macp pointer to the @p MACDriver object - * @return The link status. - * @retval true if the link is active. - * @retval false if the link is down. - * - * @api - */ -bool macPollLinkStatus(MACDriver *macp) { - - osalDbgCheck(macp != NULL); - osalDbgAssert(macp->state == MAC_ACTIVE, "not active"); - - return mac_lld_poll_link_status(macp); -} - -#endif /* HAL_USE_MAC == TRUE */ - -/** @} */ diff --git a/os/hal/src/mmc_spi.c b/os/hal/src/mmc_spi.c deleted file mode 100644 index acb0d6d2e..000000000 --- a/os/hal/src/mmc_spi.c +++ /dev/null @@ -1,918 +0,0 @@ -/* - ChibiOS - Copyright (C) 2006..2016 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. -*/ -/* - Parts of this file have been contributed by Matthias Blaicher. - */ - -/** - * @file mmc_spi.c - * @brief MMC over SPI driver code. - * - * @addtogroup MMC_SPI - * @{ - */ - -#include - -#include "hal.h" - -#if (HAL_USE_MMC_SPI == TRUE) || defined(__DOXYGEN__) - -/*===========================================================================*/ -/* Driver local definitions. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver exported variables. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver local variables and types. */ -/*===========================================================================*/ - -/* Forward declarations required by mmc_vmt.*/ -static bool mmc_read(void *instance, uint32_t startblk, - uint8_t *buffer, uint32_t n); -static bool mmc_write(void *instance, uint32_t startblk, - const uint8_t *buffer, uint32_t n); - -/** - * @brief Virtual methods table. - */ -static const struct MMCDriverVMT mmc_vmt = { - (bool (*)(void *))mmc_lld_is_card_inserted, - (bool (*)(void *))mmc_lld_is_write_protected, - (bool (*)(void *))mmcConnect, - (bool (*)(void *))mmcDisconnect, - mmc_read, - mmc_write, - (bool (*)(void *))mmcSync, - (bool (*)(void *, BlockDeviceInfo *))mmcGetInfo -}; - -/** - * @brief Lookup table for CRC-7 ( based on polynomial x^7 + x^3 + 1). - */ -static const uint8_t crc7_lookup_table[256] = { - 0x00, 0x09, 0x12, 0x1b, 0x24, 0x2d, 0x36, 0x3f, 0x48, 0x41, 0x5a, 0x53, - 0x6c, 0x65, 0x7e, 0x77, 0x19, 0x10, 0x0b, 0x02, 0x3d, 0x34, 0x2f, 0x26, - 0x51, 0x58, 0x43, 0x4a, 0x75, 0x7c, 0x67, 0x6e, 0x32, 0x3b, 0x20, 0x29, - 0x16, 0x1f, 0x04, 0x0d, 0x7a, 0x73, 0x68, 0x61, 0x5e, 0x57, 0x4c, 0x45, - 0x2b, 0x22, 0x39, 0x30, 0x0f, 0x06, 0x1d, 0x14, 0x63, 0x6a, 0x71, 0x78, - 0x47, 0x4e, 0x55, 0x5c, 0x64, 0x6d, 0x76, 0x7f, 0x40, 0x49, 0x52, 0x5b, - 0x2c, 0x25, 0x3e, 0x37, 0x08, 0x01, 0x1a, 0x13, 0x7d, 0x74, 0x6f, 0x66, - 0x59, 0x50, 0x4b, 0x42, 0x35, 0x3c, 0x27, 0x2e, 0x11, 0x18, 0x03, 0x0a, - 0x56, 0x5f, 0x44, 0x4d, 0x72, 0x7b, 0x60, 0x69, 0x1e, 0x17, 0x0c, 0x05, - 0x3a, 0x33, 0x28, 0x21, 0x4f, 0x46, 0x5d, 0x54, 0x6b, 0x62, 0x79, 0x70, - 0x07, 0x0e, 0x15, 0x1c, 0x23, 0x2a, 0x31, 0x38, 0x41, 0x48, 0x53, 0x5a, - 0x65, 0x6c, 0x77, 0x7e, 0x09, 0x00, 0x1b, 0x12, 0x2d, 0x24, 0x3f, 0x36, - 0x58, 0x51, 0x4a, 0x43, 0x7c, 0x75, 0x6e, 0x67, 0x10, 0x19, 0x02, 0x0b, - 0x34, 0x3d, 0x26, 0x2f, 0x73, 0x7a, 0x61, 0x68, 0x57, 0x5e, 0x45, 0x4c, - 0x3b, 0x32, 0x29, 0x20, 0x1f, 0x16, 0x0d, 0x04, 0x6a, 0x63, 0x78, 0x71, - 0x4e, 0x47, 0x5c, 0x55, 0x22, 0x2b, 0x30, 0x39, 0x06, 0x0f, 0x14, 0x1d, - 0x25, 0x2c, 0x37, 0x3e, 0x01, 0x08, 0x13, 0x1a, 0x6d, 0x64, 0x7f, 0x76, - 0x49, 0x40, 0x5b, 0x52, 0x3c, 0x35, 0x2e, 0x27, 0x18, 0x11, 0x0a, 0x03, - 0x74, 0x7d, 0x66, 0x6f, 0x50, 0x59, 0x42, 0x4b, 0x17, 0x1e, 0x05, 0x0c, - 0x33, 0x3a, 0x21, 0x28, 0x5f, 0x56, 0x4d, 0x44, 0x7b, 0x72, 0x69, 0x60, - 0x0e, 0x07, 0x1c, 0x15, 0x2a, 0x23, 0x38, 0x31, 0x46, 0x4f, 0x54, 0x5d, - 0x62, 0x6b, 0x70, 0x79 -}; - -/*===========================================================================*/ -/* Driver local functions. */ -/*===========================================================================*/ - -static bool mmc_read(void *instance, uint32_t startblk, - uint8_t *buffer, uint32_t n) { - - if (mmcStartSequentialRead((MMCDriver *)instance, startblk)) { - return HAL_FAILED; - } - - while (n > 0U) { - if (mmcSequentialRead((MMCDriver *)instance, buffer)) { - return HAL_FAILED; - } - buffer += MMCSD_BLOCK_SIZE; - n--; - } - - if (mmcStopSequentialRead((MMCDriver *)instance)) { - return HAL_FAILED; - } - return HAL_SUCCESS; -} - -static bool mmc_write(void *instance, uint32_t startblk, - const uint8_t *buffer, uint32_t n) { - - if (mmcStartSequentialWrite((MMCDriver *)instance, startblk)) { - return HAL_FAILED; - } - - while (n > 0U) { - if (mmcSequentialWrite((MMCDriver *)instance, buffer)) { - return HAL_FAILED; - } - buffer += MMCSD_BLOCK_SIZE; - n--; - } - - if (mmcStopSequentialWrite((MMCDriver *)instance)) { - return HAL_FAILED; - } - return HAL_SUCCESS; -} - -/** - * @brief Calculate the MMC standard CRC-7 based on a lookup table. - * - * @param[in] crc start value for CRC - * @param[in] buffer pointer to data buffer - * @param[in] len length of data - * @return Calculated CRC - */ -static uint8_t crc7(uint8_t crc, const uint8_t *buffer, size_t len) { - - while (len > 0U) { - crc = crc7_lookup_table[(crc << 1) ^ (*buffer++)]; - len--; - } - return crc; -} - -/** - * @brief Waits an idle condition. - * - * @param[in] mmcp pointer to the @p MMCDriver object - * - * @notapi - */ -static void wait(MMCDriver *mmcp) { - int i; - uint8_t buf[4]; - - for (i = 0; i < 16; i++) { - spiReceive(mmcp->config->spip, 1, buf); - if (buf[0] == 0xFFU) { - return; - } - } - /* Looks like it is a long wait.*/ - while (true) { - spiReceive(mmcp->config->spip, 1, buf); - if (buf[0] == 0xFFU) { - break; - } -#if MMC_NICE_WAITING == TRUE - /* Trying to be nice with the other threads.*/ - osalThreadSleepMilliseconds(1); -#endif - } -} - -/** - * @brief Sends a command header. - * - * @param[in] mmcp pointer to the @p MMCDriver object - * @param[in] cmd the command id - * @param[in] arg the command argument - * - * @notapi - */ -static void send_hdr(MMCDriver *mmcp, uint8_t cmd, uint32_t arg) { - uint8_t buf[6]; - - /* Wait for the bus to become idle if a write operation was in progress.*/ - wait(mmcp); - - buf[0] = (uint8_t)0x40U | cmd; - buf[1] = (uint8_t)(arg >> 24U); - buf[2] = (uint8_t)(arg >> 16U); - buf[3] = (uint8_t)(arg >> 8U); - buf[4] = (uint8_t)arg; - /* Calculate CRC for command header, shift to right position, add stop bit.*/ - buf[5] = ((crc7(0, buf, 5U) & 0x7FU) << 1U) | 0x01U; - - spiSend(mmcp->config->spip, 6, buf); -} - -/** - * @brief Receives a single byte response. - * - * @param[in] mmcp pointer to the @p MMCDriver object - * @return The response as an @p uint8_t value. - * @retval 0xFF timed out. - * - * @notapi - */ -static uint8_t recvr1(MMCDriver *mmcp) { - int i; - uint8_t r1[1]; - - for (i = 0; i < 9; i++) { - spiReceive(mmcp->config->spip, 1, r1); - if (r1[0] != 0xFFU) { - return r1[0]; - } - } - return 0xFFU; -} - -/** - * @brief Receives a three byte response. - * - * @param[in] mmcp pointer to the @p MMCDriver object - * @param[out] buffer pointer to four bytes wide buffer - * @return First response byte as an @p uint8_t value. - * @retval 0xFF timed out. - * - * @notapi - */ -static uint8_t recvr3(MMCDriver *mmcp, uint8_t* buffer) { - uint8_t r1; - - r1 = recvr1(mmcp); - spiReceive(mmcp->config->spip, 4, buffer); - - return r1; -} - -/** - * @brief Sends a command an returns a single byte response. - * - * @param[in] mmcp pointer to the @p MMCDriver object - * @param[in] cmd the command id - * @param[in] arg the command argument - * @return The response as an @p uint8_t value. - * @retval 0xFF timed out. - * - * @notapi - */ -static uint8_t send_command_R1(MMCDriver *mmcp, uint8_t cmd, uint32_t arg) { - uint8_t r1; - - spiSelect(mmcp->config->spip); - send_hdr(mmcp, cmd, arg); - r1 = recvr1(mmcp); - spiUnselect(mmcp->config->spip); - return r1; -} - -/** - * @brief Sends a command which returns a five bytes response (R3). - * - * @param[in] mmcp pointer to the @p MMCDriver object - * @param[in] cmd the command id - * @param[in] arg the command argument - * @param[out] response pointer to four bytes wide uint8_t buffer - * @return The first byte of the response (R1) as an @p - * uint8_t value. - * @retval 0xFF timed out. - * - * @notapi - */ -static uint8_t send_command_R3(MMCDriver *mmcp, uint8_t cmd, uint32_t arg, - uint8_t *response) { - uint8_t r1; - - spiSelect(mmcp->config->spip); - send_hdr(mmcp, cmd, arg); - r1 = recvr3(mmcp, response); - spiUnselect(mmcp->config->spip); - return r1; -} - -/** - * @brief Reads the CSD. - * - * @param[in] mmcp pointer to the @p MMCDriver object - * @param[out] cmd command - * @param[out] cxd pointer to the CSD/CID buffer - * - * @return The operation status. - * @retval HAL_SUCCESS the operation succeeded. - * @retval HAL_FAILED the operation failed. - * - * @notapi - */ -static bool read_CxD(MMCDriver *mmcp, uint8_t cmd, uint32_t cxd[4]) { - unsigned i; - uint8_t *bp, buf[16]; - - spiSelect(mmcp->config->spip); - send_hdr(mmcp, cmd, 0); - if (recvr1(mmcp) != 0x00U) { - spiUnselect(mmcp->config->spip); - return HAL_FAILED; - } - - /* Wait for data availability.*/ - for (i = 0U; i < MMC_WAIT_DATA; i++) { - spiReceive(mmcp->config->spip, 1, buf); - if (buf[0] == 0xFEU) { - uint32_t *wp; - - spiReceive(mmcp->config->spip, 16, buf); - bp = buf; - for (wp = &cxd[3]; wp >= cxd; wp--) { - *wp = ((uint32_t)bp[0] << 24U) | ((uint32_t)bp[1] << 16U) | - ((uint32_t)bp[2] << 8U) | (uint32_t)bp[3]; - bp += 4; - } - - /* CRC ignored then end of transaction. */ - spiIgnore(mmcp->config->spip, 2); - spiUnselect(mmcp->config->spip); - - return HAL_SUCCESS; - } - } - return HAL_FAILED; -} - -/** - * @brief Waits that the card reaches an idle state. - * - * @param[in] mmcp pointer to the @p MMCDriver object - * - * @notapi - */ -static void sync(MMCDriver *mmcp) { - uint8_t buf[1]; - - spiSelect(mmcp->config->spip); - while (true) { - spiReceive(mmcp->config->spip, 1, buf); - if (buf[0] == 0xFFU) { - break; - } -#if MMC_NICE_WAITING == TRUE - /* Trying to be nice with the other threads.*/ - osalThreadSleepMilliseconds(1); -#endif - } - spiUnselect(mmcp->config->spip); -} - -/*===========================================================================*/ -/* Driver exported functions. */ -/*===========================================================================*/ - -/** - * @brief MMC over SPI driver initialization. - * @note This function is implicitly invoked by @p halInit(), there is - * no need to explicitly initialize the driver. - * - * @init - */ -void mmcInit(void) { - -} - -/** - * @brief Initializes an instance. - * - * @param[out] mmcp pointer to the @p MMCDriver object - * - * @init - */ -void mmcObjectInit(MMCDriver *mmcp) { - - mmcp->vmt = &mmc_vmt; - mmcp->state = BLK_STOP; - mmcp->config = NULL; - mmcp->block_addresses = false; -} - -/** - * @brief Configures and activates the MMC peripheral. - * - * @param[in] mmcp pointer to the @p MMCDriver object - * @param[in] config pointer to the @p MMCConfig object. - * - * @api - */ -void mmcStart(MMCDriver *mmcp, const MMCConfig *config) { - - osalDbgCheck((mmcp != NULL) && (config != NULL)); - osalDbgAssert((mmcp->state == BLK_STOP) || (mmcp->state == BLK_ACTIVE), - "invalid state"); - - mmcp->config = config; - mmcp->state = BLK_ACTIVE; -} - -/** - * @brief Disables the MMC peripheral. - * - * @param[in] mmcp pointer to the @p MMCDriver object - * - * @api - */ -void mmcStop(MMCDriver *mmcp) { - - osalDbgCheck(mmcp != NULL); - osalDbgAssert((mmcp->state == BLK_STOP) || (mmcp->state == BLK_ACTIVE), - "invalid state"); - - spiStop(mmcp->config->spip); - mmcp->state = BLK_STOP; -} - -/** - * @brief Performs the initialization procedure on the inserted card. - * @details This function should be invoked when a card is inserted and - * brings the driver in the @p MMC_READY state where it is possible - * to perform read and write operations. - * @note It is possible to invoke this function from the insertion event - * handler. - * - * @param[in] mmcp pointer to the @p MMCDriver object - * - * @return The operation status. - * @retval HAL_SUCCESS the operation succeeded and the driver is now - * in the @p MMC_READY state. - * @retval HAL_FAILED the operation failed. - * - * @api - */ -bool mmcConnect(MMCDriver *mmcp) { - unsigned i; - uint8_t r3[4]; - - osalDbgCheck(mmcp != NULL); - - osalDbgAssert((mmcp->state == BLK_ACTIVE) || (mmcp->state == BLK_READY), - "invalid state"); - - /* Connection procedure in progress.*/ - mmcp->state = BLK_CONNECTING; - mmcp->block_addresses = false; - - /* Slow clock mode and 128 clock pulses.*/ - spiStart(mmcp->config->spip, mmcp->config->lscfg); - spiIgnore(mmcp->config->spip, 16); - - /* SPI mode selection.*/ - i = 0; - while (true) { - if (send_command_R1(mmcp, MMCSD_CMD_GO_IDLE_STATE, 0) == 0x01U) { - break; - } - if (++i >= MMC_CMD0_RETRY) { - goto failed; - } - osalThreadSleepMilliseconds(10); - } - - /* Try to detect if this is a high capacity card and switch to block - addresses if possible. - This method is based on "How to support SDC Ver2 and high capacity cards" - by ElmChan.*/ - if (send_command_R3(mmcp, MMCSD_CMD_SEND_IF_COND, - MMCSD_CMD8_PATTERN, r3) != 0x05U) { - - /* Switch to SDHC mode.*/ - i = 0; - while (true) { - /*lint -save -e9007 [13.5] Side effect unimportant.*/ - if ((send_command_R1(mmcp, MMCSD_CMD_APP_CMD, 0) == 0x01U) && - (send_command_R3(mmcp, MMCSD_CMD_APP_OP_COND, 0x400001AAU, r3) == 0x00U)) { - /*lint -restore*/ - break; - } - - if (++i >= MMC_ACMD41_RETRY) { - goto failed; - } - osalThreadSleepMilliseconds(10); - } - - /* Execute dedicated read on OCR register */ - (void) send_command_R3(mmcp, MMCSD_CMD_READ_OCR, 0, r3); - - /* Check if CCS is set in response. Card operates in block mode if set.*/ - if ((r3[0] & 0x40U) != 0U) { - mmcp->block_addresses = true; - } - } - - /* Initialization.*/ - i = 0; - while (true) { - uint8_t b = send_command_R1(mmcp, MMCSD_CMD_INIT, 0); - if (b == 0x00U) { - break; - } - if (b != 0x01U) { - goto failed; - } - if (++i >= MMC_CMD1_RETRY) { - goto failed; - } - osalThreadSleepMilliseconds(10); - } - - /* Initialization complete, full speed.*/ - spiStart(mmcp->config->spip, mmcp->config->hscfg); - - /* Setting block size.*/ - if (send_command_R1(mmcp, MMCSD_CMD_SET_BLOCKLEN, - MMCSD_BLOCK_SIZE) != 0x00U) { - goto failed; - } - - /* Determine capacity.*/ - if (read_CxD(mmcp, MMCSD_CMD_SEND_CSD, mmcp->csd)) { - goto failed; - } - - mmcp->capacity = _mmcsd_get_capacity(mmcp->csd); - if (mmcp->capacity == 0U) { - goto failed; - } - - if (read_CxD(mmcp, MMCSD_CMD_SEND_CID, mmcp->cid)) { - goto failed; - } - - mmcp->state = BLK_READY; - return HAL_SUCCESS; - - /* Connection failed, state reset to BLK_ACTIVE.*/ -failed: - spiStop(mmcp->config->spip); - mmcp->state = BLK_ACTIVE; - return HAL_FAILED; -} - -/** - * @brief Brings the driver in a state safe for card removal. - * - * @param[in] mmcp pointer to the @p MMCDriver object - * @return The operation status. - * - * @retval HAL_SUCCESS the operation succeeded and the driver is now - * in the @p MMC_INSERTED state. - * @retval HAL_FAILED the operation failed. - * - * @api - */ -bool mmcDisconnect(MMCDriver *mmcp) { - - osalDbgCheck(mmcp != NULL); - - osalSysLock(); - osalDbgAssert((mmcp->state == BLK_ACTIVE) || (mmcp->state == BLK_READY), - "invalid state"); - if (mmcp->state == BLK_ACTIVE) { - osalSysUnlock(); - return HAL_SUCCESS; - } - mmcp->state = BLK_DISCONNECTING; - osalSysUnlock(); - - /* Wait for the pending write operations to complete.*/ - spiStart(mmcp->config->spip, mmcp->config->hscfg); - sync(mmcp); - - spiStop(mmcp->config->spip); - mmcp->state = BLK_ACTIVE; - return HAL_SUCCESS; -} - -/** - * @brief Starts a sequential read. - * - * @param[in] mmcp pointer to the @p MMCDriver object - * @param[in] startblk first block to read - * - * @return The operation status. - * @retval HAL_SUCCESS the operation succeeded. - * @retval HAL_FAILED the operation failed. - * - * @api - */ -bool mmcStartSequentialRead(MMCDriver *mmcp, uint32_t startblk) { - - osalDbgCheck(mmcp != NULL); - osalDbgAssert(mmcp->state == BLK_READY, "invalid state"); - - /* Read operation in progress.*/ - mmcp->state = BLK_READING; - - /* (Re)starting the SPI in case it has been reprogrammed externally, it can - happen if the SPI bus is shared among multiple peripherals.*/ - spiStart(mmcp->config->spip, mmcp->config->hscfg); - spiSelect(mmcp->config->spip); - - if (mmcp->block_addresses) { - send_hdr(mmcp, MMCSD_CMD_READ_MULTIPLE_BLOCK, startblk); - } - else { - send_hdr(mmcp, MMCSD_CMD_READ_MULTIPLE_BLOCK, startblk * MMCSD_BLOCK_SIZE); - } - - if (recvr1(mmcp) != 0x00U) { - spiStop(mmcp->config->spip); - mmcp->state = BLK_READY; - return HAL_FAILED; - } - return HAL_SUCCESS; -} - -/** - * @brief Reads a block within a sequential read operation. - * - * @param[in] mmcp pointer to the @p MMCDriver object - * @param[out] buffer pointer to the read buffer - * - * @return The operation status. - * @retval HAL_SUCCESS the operation succeeded. - * @retval HAL_FAILED the operation failed. - * - * @api - */ -bool mmcSequentialRead(MMCDriver *mmcp, uint8_t *buffer) { - unsigned i; - - osalDbgCheck((mmcp != NULL) && (buffer != NULL)); - - if (mmcp->state != BLK_READING) { - return HAL_FAILED; - } - - for (i = 0; i < MMC_WAIT_DATA; i++) { - spiReceive(mmcp->config->spip, 1, buffer); - if (buffer[0] == 0xFEU) { - spiReceive(mmcp->config->spip, MMCSD_BLOCK_SIZE, buffer); - /* CRC ignored. */ - spiIgnore(mmcp->config->spip, 2); - return HAL_SUCCESS; - } - } - /* Timeout.*/ - spiUnselect(mmcp->config->spip); - spiStop(mmcp->config->spip); - mmcp->state = BLK_READY; - return HAL_FAILED; -} - -/** - * @brief Stops a sequential read gracefully. - * - * @param[in] mmcp pointer to the @p MMCDriver object - * - * @return The operation status. - * @retval HAL_SUCCESS the operation succeeded. - * @retval HAL_FAILED the operation failed. - * - * @api - */ -bool mmcStopSequentialRead(MMCDriver *mmcp) { - static const uint8_t stopcmd[] = { - (uint8_t)(0x40U | MMCSD_CMD_STOP_TRANSMISSION), 0, 0, 0, 0, 1, 0xFF - }; - - osalDbgCheck(mmcp != NULL); - - if (mmcp->state != BLK_READING) { - return HAL_FAILED; - } - - spiSend(mmcp->config->spip, sizeof(stopcmd), stopcmd); -/* result = recvr1(mmcp) != 0x00U;*/ - /* Note, ignored r1 response, it can be not zero, unknown issue.*/ - (void) recvr1(mmcp); - - /* Read operation finished.*/ - spiUnselect(mmcp->config->spip); - mmcp->state = BLK_READY; - return HAL_SUCCESS; -} - -/** - * @brief Starts a sequential write. - * - * @param[in] mmcp pointer to the @p MMCDriver object - * @param[in] startblk first block to write - * - * @return The operation status. - * @retval HAL_SUCCESS the operation succeeded. - * @retval HAL_FAILED the operation failed. - * - * @api - */ -bool mmcStartSequentialWrite(MMCDriver *mmcp, uint32_t startblk) { - - osalDbgCheck(mmcp != NULL); - osalDbgAssert(mmcp->state == BLK_READY, "invalid state"); - - /* Write operation in progress.*/ - mmcp->state = BLK_WRITING; - - spiStart(mmcp->config->spip, mmcp->config->hscfg); - spiSelect(mmcp->config->spip); - if (mmcp->block_addresses) { - send_hdr(mmcp, MMCSD_CMD_WRITE_MULTIPLE_BLOCK, startblk); - } - else { - send_hdr(mmcp, MMCSD_CMD_WRITE_MULTIPLE_BLOCK, - startblk * MMCSD_BLOCK_SIZE); - } - - if (recvr1(mmcp) != 0x00U) { - spiStop(mmcp->config->spip); - mmcp->state = BLK_READY; - return HAL_FAILED; - } - return HAL_SUCCESS; -} - -/** - * @brief Writes a block within a sequential write operation. - * - * @param[in] mmcp pointer to the @p MMCDriver object - * @param[out] buffer pointer to the write buffer - * - * @return The operation status. - * @retval HAL_SUCCESS the operation succeeded. - * @retval HAL_FAILED the operation failed. - * - * @api - */ -bool mmcSequentialWrite(MMCDriver *mmcp, const uint8_t *buffer) { - static const uint8_t start[] = {0xFF, 0xFC}; - uint8_t b[1]; - - osalDbgCheck((mmcp != NULL) && (buffer != NULL)); - - if (mmcp->state != BLK_WRITING) { - return HAL_FAILED; - } - - spiSend(mmcp->config->spip, sizeof(start), start); /* Data prologue. */ - spiSend(mmcp->config->spip, MMCSD_BLOCK_SIZE, buffer);/* Data. */ - spiIgnore(mmcp->config->spip, 2); /* CRC ignored. */ - spiReceive(mmcp->config->spip, 1, b); - if ((b[0] & 0x1FU) == 0x05U) { - wait(mmcp); - return HAL_SUCCESS; - } - - /* Error.*/ - spiUnselect(mmcp->config->spip); - spiStop(mmcp->config->spip); - mmcp->state = BLK_READY; - return HAL_FAILED; -} - -/** - * @brief Stops a sequential write gracefully. - * - * @param[in] mmcp pointer to the @p MMCDriver object - * - * @return The operation status. - * @retval HAL_SUCCESS the operation succeeded. - * @retval HAL_FAILED the operation failed. - * - * @api - */ -bool mmcStopSequentialWrite(MMCDriver *mmcp) { - static const uint8_t stop[] = {0xFD, 0xFF}; - - osalDbgCheck(mmcp != NULL); - - if (mmcp->state != BLK_WRITING) { - return HAL_FAILED; - } - - spiSend(mmcp->config->spip, sizeof(stop), stop); - spiUnselect(mmcp->config->spip); - - /* Write operation finished.*/ - mmcp->state = BLK_READY; - return HAL_SUCCESS; -} - -/** - * @brief Waits for card idle condition. - * - * @param[in] mmcp pointer to the @p MMCDriver object - * - * @return The operation status. - * @retval HAL_SUCCESS the operation succeeded. - * @retval HAL_FAILED the operation failed. - * - * @api - */ -bool mmcSync(MMCDriver *mmcp) { - - osalDbgCheck(mmcp != NULL); - - if (mmcp->state != BLK_READY) { - return HAL_FAILED; - } - - /* Synchronization operation in progress.*/ - mmcp->state = BLK_SYNCING; - - spiStart(mmcp->config->spip, mmcp->config->hscfg); - sync(mmcp); - - /* Synchronization operation finished.*/ - mmcp->state = BLK_READY; - return HAL_SUCCESS; -} - -/** - * @brief Returns the media info. - * - * @param[in] mmcp pointer to the @p MMCDriver object - * @param[out] bdip pointer to a @p BlockDeviceInfo structure - * - * @return The operation status. - * @retval HAL_SUCCESS the operation succeeded. - * @retval HAL_FAILED the operation failed. - * - * @api - */ -bool mmcGetInfo(MMCDriver *mmcp, BlockDeviceInfo *bdip) { - - osalDbgCheck((mmcp != NULL) && (bdip != NULL)); - - if (mmcp->state != BLK_READY) { - return HAL_FAILED; - } - - bdip->blk_num = mmcp->capacity; - bdip->blk_size = MMCSD_BLOCK_SIZE; - - return HAL_SUCCESS; -} - -/** - * @brief Erases blocks. - * - * @param[in] mmcp pointer to the @p MMCDriver object - * @param[in] startblk starting block number - * @param[in] endblk ending block number - * - * @return The operation status. - * @retval HAL_SUCCESS the operation succeeded. - * @retval HAL_FAILED the operation failed. - * - * @api - */ -bool mmcErase(MMCDriver *mmcp, uint32_t startblk, uint32_t endblk) { - - osalDbgCheck((mmcp != NULL)); - - /* Erase operation in progress.*/ - mmcp->state = BLK_WRITING; - - /* Handling command differences between HC and normal cards.*/ - if (!mmcp->block_addresses) { - startblk *= MMCSD_BLOCK_SIZE; - endblk *= MMCSD_BLOCK_SIZE; - } - - if (send_command_R1(mmcp, MMCSD_CMD_ERASE_RW_BLK_START, startblk) != 0x00U) { - goto failed; - } - - if (send_command_R1(mmcp, MMCSD_CMD_ERASE_RW_BLK_END, endblk) != 0x00U) { - goto failed; - } - - if (send_command_R1(mmcp, MMCSD_CMD_ERASE, 0) != 0x00U) { - goto failed; - } - - mmcp->state = BLK_READY; - return HAL_SUCCESS; - - /* Command failed, state reset to BLK_ACTIVE.*/ -failed: - spiStop(mmcp->config->spip); - mmcp->state = BLK_READY; - return HAL_FAILED; -} - -#endif /* HAL_USE_MMC_SPI == TRUE */ - -/** @} */ diff --git a/os/hal/src/pal.c b/os/hal/src/pal.c deleted file mode 100644 index f75e8d481..000000000 --- a/os/hal/src/pal.c +++ /dev/null @@ -1,122 +0,0 @@ -/* - ChibiOS - Copyright (C) 2006..2016 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 pal.c - * @brief I/O Ports Abstraction Layer code. - * - * @addtogroup PAL - * @{ - */ - -#include "hal.h" - -#if (HAL_USE_PAL == TRUE) || defined(__DOXYGEN__) - -/*===========================================================================*/ -/* Driver local definitions. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver exported variables. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver local variables and types. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver local functions. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver exported functions. */ -/*===========================================================================*/ - -/** - * @brief Read from an I/O bus. - * @note The operation is not guaranteed to be atomic on all the - * architectures, for atomicity and/or portability reasons you may - * need to enclose port I/O operations between @p osalSysLock() and - * @p osalSysUnlock(). - * @note The function internally uses the @p palReadGroup() macro. The use - * of this function is preferred when you value code size, readability - * and error checking over speed. - * @note The function can be called from any context. - * - * @param[in] bus the I/O bus, pointer to a @p IOBus structure - * @return The bus logical states. - * - * @special - */ -ioportmask_t palReadBus(IOBus *bus) { - - osalDbgCheck((bus != NULL) && (bus->offset < PAL_IOPORTS_WIDTH)); - - return palReadGroup(bus->portid, bus->mask, bus->offset); -} - -/** - * @brief Write to an I/O bus. - * @note The operation is not guaranteed to be atomic on all the - * architectures, for atomicity and/or portability reasons you may - * need to enclose port I/O operations between @p osalSysLock() and - * @p osalSysUnlock(). - * @note The default implementation is non atomic and not necessarily - * optimal. Low level drivers may optimize the function by using - * specific hardware or coding. - * @note The function can be called from any context. - * - * @param[in] bus the I/O bus, pointer to a @p IOBus structure - * @param[in] bits the bits to be written on the I/O bus. Values exceeding - * the bus width are masked so most significant bits are - * lost. - * - * @special - */ -void palWriteBus(IOBus *bus, ioportmask_t bits) { - - osalDbgCheck((bus != NULL) && (bus->offset < PAL_IOPORTS_WIDTH)); - - palWriteGroup(bus->portid, bus->mask, bus->offset, bits); -} - -/** - * @brief Programs a bus with the specified mode. - * @note The operation is not guaranteed to be atomic on all the - * architectures, for atomicity and/or portability reasons you may - * need to enclose port I/O operations between @p osalSysLock() and - * @p osalSysUnlock(). - * @note The default implementation is non atomic and not necessarily - * optimal. Low level drivers may optimize the function by using - * specific hardware or coding. - * @note The function can be called from any context. - * - * @param[in] bus the I/O bus, pointer to a @p IOBus structure - * @param[in] mode the mode - * - * @special - */ -void palSetBusMode(IOBus *bus, iomode_t mode) { - - osalDbgCheck((bus != NULL) && (bus->offset < PAL_IOPORTS_WIDTH)); - - palSetGroupMode(bus->portid, bus->mask, bus->offset, mode); -} - -#endif /* HAL_USE_PAL == TRUE */ - -/** @} */ diff --git a/os/hal/src/pwm.c b/os/hal/src/pwm.c deleted file mode 100644 index f74bf534c..000000000 --- a/os/hal/src/pwm.c +++ /dev/null @@ -1,309 +0,0 @@ -/* - ChibiOS - Copyright (C) 2006..2016 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 pwm.c - * @brief PWM Driver code. - * - * @addtogroup PWM - * @{ - */ - -#include "hal.h" - -#if (HAL_USE_PWM == TRUE) || defined(__DOXYGEN__) - -/*===========================================================================*/ -/* Driver local definitions. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver exported variables. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver local variables and types. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver local functions. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver exported functions. */ -/*===========================================================================*/ - -/** - * @brief PWM Driver initialization. - * @note This function is implicitly invoked by @p halInit(), there is - * no need to explicitly initialize the driver. - * - * @init - */ -void pwmInit(void) { - - pwm_lld_init(); -} - -/** - * @brief Initializes the standard part of a @p PWMDriver structure. - * - * @param[out] pwmp pointer to a @p PWMDriver object - * - * @init - */ -void pwmObjectInit(PWMDriver *pwmp) { - - pwmp->state = PWM_STOP; - pwmp->config = NULL; - pwmp->enabled = 0; - pwmp->channels = 0; -#if defined(PWM_DRIVER_EXT_INIT_HOOK) - PWM_DRIVER_EXT_INIT_HOOK(pwmp); -#endif -} - -/** - * @brief Configures and activates the PWM peripheral. - * @note Starting a driver that is already in the @p PWM_READY state - * disables all the active channels. - * - * @param[in] pwmp pointer to a @p PWMDriver object - * @param[in] config pointer to a @p PWMConfig object - * - * @api - */ -void pwmStart(PWMDriver *pwmp, const PWMConfig *config) { - - osalDbgCheck((pwmp != NULL) && (config != NULL)); - - osalSysLock(); - osalDbgAssert((pwmp->state == PWM_STOP) || (pwmp->state == PWM_READY), - "invalid state"); - pwmp->config = config; - pwmp->period = config->period; - pwm_lld_start(pwmp); - pwmp->enabled = 0; - pwmp->state = PWM_READY; - osalSysUnlock(); -} - -/** - * @brief Deactivates the PWM peripheral. - * - * @param[in] pwmp pointer to a @p PWMDriver object - * - * @api - */ -void pwmStop(PWMDriver *pwmp) { - - osalDbgCheck(pwmp != NULL); - - osalSysLock(); - osalDbgAssert((pwmp->state == PWM_STOP) || (pwmp->state == PWM_READY), - "invalid state"); - pwm_lld_stop(pwmp); - pwmp->enabled = 0; - pwmp->state = PWM_STOP; - osalSysUnlock(); -} - -/** - * @brief Changes the period the PWM peripheral. - * @details This function changes the period of a PWM unit that has already - * been activated using @p pwmStart(). - * @pre The PWM unit must have been activated using @p pwmStart(). - * @post The PWM unit period is changed to the new value. - * @note If a period is specified that is shorter than the pulse width - * programmed in one of the channels then the behavior is not - * guaranteed. - * - * @param[in] pwmp pointer to a @p PWMDriver object - * @param[in] period new cycle time in ticks - * - * @api - */ -void pwmChangePeriod(PWMDriver *pwmp, pwmcnt_t period) { - - osalDbgCheck(pwmp != NULL); - - osalSysLock(); - osalDbgAssert(pwmp->state == PWM_READY, "invalid state"); - pwmChangePeriodI(pwmp, period); - osalSysUnlock(); -} - -/** - * @brief Enables a PWM channel. - * @pre The PWM unit must have been activated using @p pwmStart(). - * @post The channel is active using the specified configuration. - * @note Depending on the hardware implementation this function has - * effect starting on the next cycle (recommended implementation) - * or immediately (fallback implementation). - * - * @param[in] pwmp pointer to a @p PWMDriver object - * @param[in] channel PWM channel identifier (0...channels-1) - * @param[in] width PWM pulse width as clock pulses number - * - * @api - */ -void pwmEnableChannel(PWMDriver *pwmp, - pwmchannel_t channel, - pwmcnt_t width) { - - osalDbgCheck((pwmp != NULL) && (channel < pwmp->channels)); - - osalSysLock(); - - osalDbgAssert(pwmp->state == PWM_READY, "not ready"); - - pwmEnableChannelI(pwmp, channel, width); - - osalSysUnlock(); -} - -/** - * @brief Disables a PWM channel and its notification. - * @pre The PWM unit must have been activated using @p pwmStart(). - * @post The channel is disabled and its output line returned to the - * idle state. - * @note Depending on the hardware implementation this function has - * effect starting on the next cycle (recommended implementation) - * or immediately (fallback implementation). - * - * @param[in] pwmp pointer to a @p PWMDriver object - * @param[in] channel PWM channel identifier (0...channels-1) - * - * @api - */ -void pwmDisableChannel(PWMDriver *pwmp, pwmchannel_t channel) { - - osalDbgCheck((pwmp != NULL) && (channel < pwmp->channels)); - - osalSysLock(); - - osalDbgAssert(pwmp->state == PWM_READY, "not ready"); - - pwmDisableChannelI(pwmp, channel); - - osalSysUnlock(); -} - -/** - * @brief Enables the periodic activation edge notification. - * @pre The PWM unit must have been activated using @p pwmStart(). - * @note If the notification is already enabled then the call has no effect. - * - * @param[in] pwmp pointer to a @p PWMDriver object - * - * @api - */ -void pwmEnablePeriodicNotification(PWMDriver *pwmp) { - - osalDbgCheck(pwmp != NULL); - - osalSysLock(); - - osalDbgAssert(pwmp->state == PWM_READY, "not ready"); - osalDbgAssert(pwmp->config->callback != NULL, "undefined periodic callback"); - - pwmEnablePeriodicNotificationI(pwmp); - - osalSysUnlock(); -} - -/** - * @brief Disables the periodic activation edge notification. - * @pre The PWM unit must have been activated using @p pwmStart(). - * @note If the notification is already disabled then the call has no effect. - * - * @param[in] pwmp pointer to a @p PWMDriver object - * - * @api - */ -void pwmDisablePeriodicNotification(PWMDriver *pwmp) { - - osalDbgCheck(pwmp != NULL); - - osalSysLock(); - - osalDbgAssert(pwmp->state == PWM_READY, "not ready"); - osalDbgAssert(pwmp->config->callback != NULL, "undefined periodic callback"); - - pwmDisablePeriodicNotificationI(pwmp); - - osalSysUnlock(); -} - -/** - * @brief Enables a channel de-activation edge notification. - * @pre The PWM unit must have been activated using @p pwmStart(). - * @pre The channel must have been activated using @p pwmEnableChannel(). - * @note If the notification is already enabled then the call has no effect. - * - * @param[in] pwmp pointer to a @p PWMDriver object - * @param[in] channel PWM channel identifier (0...channels-1) - * - * @api - */ -void pwmEnableChannelNotification(PWMDriver *pwmp, pwmchannel_t channel) { - - osalDbgCheck((pwmp != NULL) && (channel < pwmp->channels)); - - osalSysLock(); - - osalDbgAssert(pwmp->state == PWM_READY, "not ready"); - osalDbgAssert((pwmp->enabled & ((pwmchnmsk_t)1U << (pwmchnmsk_t)channel)) != 0U, - "channel not enabled"); - osalDbgAssert(pwmp->config->channels[channel].callback != NULL, - "undefined channel callback"); - - pwmEnableChannelNotificationI(pwmp, channel); - - osalSysUnlock(); -} - -/** - * @brief Disables a channel de-activation edge notification. - * @pre The PWM unit must have been activated using @p pwmStart(). - * @pre The channel must have been activated using @p pwmEnableChannel(). - * @note If the notification is already disabled then the call has no effect. - * - * @param[in] pwmp pointer to a @p PWMDriver object - * @param[in] channel PWM channel identifier (0...channels-1) - * - * @api - */ -void pwmDisableChannelNotification(PWMDriver *pwmp, pwmchannel_t channel) { - - osalDbgCheck((pwmp != NULL) && (channel < pwmp->channels)); - - osalSysLock(); - - osalDbgAssert(pwmp->state == PWM_READY, "not ready"); - osalDbgAssert((pwmp->enabled & ((pwmchnmsk_t)1U << (pwmchnmsk_t)channel)) != 0U, - "channel not enabled"); - osalDbgAssert(pwmp->config->channels[channel].callback != NULL, - "undefined channel callback"); - - pwmDisableChannelNotificationI(pwmp, channel); - - osalSysUnlock(); -} - -#endif /* HAL_USE_PWM == TRUE */ - -/** @} */ diff --git a/os/hal/src/rtc.c b/os/hal/src/rtc.c deleted file mode 100644 index 252bb7ab1..000000000 --- a/os/hal/src/rtc.c +++ /dev/null @@ -1,321 +0,0 @@ -/* - ChibiOS - Copyright (C) 2006..2016 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. -*/ -/* - Concepts and parts of this file have been contributed by Uladzimir Pylinsky - aka barthess. - */ - -/** - * @file rtc.c - * @brief RTC Driver code. - * - * @addtogroup RTC - * @{ - */ - -#include "hal.h" - -#if (HAL_USE_RTC == TRUE) || defined(__DOXYGEN__) - -/*===========================================================================*/ -/* Driver local definitions. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver exported variables. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver local variables and types. */ -/*===========================================================================*/ - -/* - * Lookup table with months' length - */ -static const uint8_t month_len[12] = { - 31, 30, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 -}; - -/*===========================================================================*/ -/* Driver local functions. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver exported functions. */ -/*===========================================================================*/ - -/** - * @brief RTC Driver initialization. - * @note This function is implicitly invoked by @p halInit(), there is - * no need to explicitly initialize the driver. - * - * @init - */ -void rtcInit(void) { - - rtc_lld_init(); -} - -/** - * @brief Initializes a generic RTC driver object. - * @details The HW dependent part of the initialization has to be performed - * outside, usually in the hardware initialization code. - * - * @param[out] rtcp pointer to RTC driver structure - * - * @init - */ -void rtcObjectInit(RTCDriver *rtcp) { - -#if RTC_HAS_STORAGE == TRUE - rtcp->vmt = &_rtc_lld_vmt; -#else - (void)rtcp; -#endif -} - -/** - * @brief Set current time. - * @note This function can be called from any context but limitations - * could be imposed by the low level implementation. It is - * guaranteed that the function can be called from thread - * context. - * @note The function can be reentrant or not reentrant depending on - * the low level implementation. - * - * @param[in] rtcp pointer to RTC driver structure - * @param[in] timespec pointer to a @p RTCDateTime structure - * - * @special - */ -void rtcSetTime(RTCDriver *rtcp, const RTCDateTime *timespec) { - - osalDbgCheck((rtcp != NULL) && (timespec != NULL)); - - rtc_lld_set_time(rtcp, timespec); -} - -/** - * @brief Get current time. - * @note This function can be called from any context but limitations - * could be imposed by the low level implementation. It is - * guaranteed that the function can be called from thread - * context. - * @note The function can be reentrant or not reentrant depending on - * the low level implementation. - * - * @param[in] rtcp pointer to RTC driver structure - * @param[out] timespec pointer to a @p RTCDateTime structure - * - * @special - */ -void rtcGetTime(RTCDriver *rtcp, RTCDateTime *timespec) { - - osalDbgCheck((rtcp != NULL) && (timespec != NULL)); - - rtc_lld_get_time(rtcp, timespec); -} - -#if (RTC_ALARMS > 0) || defined(__DOXYGEN__) -/** - * @brief Set alarm time. - * @note This function can be called from any context but limitations - * could be imposed by the low level implementation. It is - * guaranteed that the function can be called from thread - * context. - * @note The function can be reentrant or not reentrant depending on - * the low level implementation. - * - * @param[in] rtcp pointer to RTC driver structure - * @param[in] alarm alarm identifier - * @param[in] alarmspec pointer to a @p RTCAlarm structure or @p NULL - * - * @special - */ -void rtcSetAlarm(RTCDriver *rtcp, - rtcalarm_t alarm, - const RTCAlarm *alarmspec) { - - osalDbgCheck((rtcp != NULL) && (alarm < (rtcalarm_t)RTC_ALARMS)); - - rtc_lld_set_alarm(rtcp, alarm, alarmspec); -} - -/** - * @brief Get current alarm. - * @note If an alarm has not been set then the returned alarm specification - * is not meaningful. - * @note This function can be called from any context but limitations - * could be imposed by the low level implementation. It is - * guaranteed that the function can be called from thread - * context. - * @note The function can be reentrant or not reentrant depending on - * the low level implementation. - * - * @param[in] rtcp pointer to RTC driver structure - * @param[in] alarm alarm identifier - * @param[out] alarmspec pointer to a @p RTCAlarm structure - * - * @special - */ -void rtcGetAlarm(RTCDriver *rtcp, - rtcalarm_t alarm, - RTCAlarm *alarmspec) { - - osalDbgCheck((rtcp != NULL) && - (alarm < (rtcalarm_t)RTC_ALARMS) && - (alarmspec != NULL)); - - rtc_lld_get_alarm(rtcp, alarm, alarmspec); -} -#endif /* RTC_ALARMS > 0 */ - -#if (RTC_SUPPORTS_CALLBACKS == TRUE) || defined(__DOXYGEN__) -/** - * @brief Enables or disables RTC callbacks. - * @details This function enables or disables the callback, use a @p NULL - * pointer in order to disable it. - * @note This function can be called from any context but limitations - * could be imposed by the low level implementation. It is - * guaranteed that the function can be called from thread - * context. - * @note The function can be reentrant or not reentrant depending on - * the low level implementation. - * - * @param[in] rtcp pointer to RTC driver structure - * @param[in] callback callback function pointer or @p NULL - * - * @special - */ -void rtcSetCallback(RTCDriver *rtcp, rtccb_t callback) { - - osalDbgCheck(rtcp != NULL); - - rtc_lld_set_callback(rtcp, callback); -} -#endif /* RTC_SUPPORTS_CALLBACKS == TRUE */ - -/** - * @brief Convert @p RTCDateTime to broken-down time structure. - * - * @param[in] timespec pointer to a @p RTCDateTime structure - * @param[out] timp pointer to a broken-down time structure - * @param[out] tv_msec pointer to milliseconds value or @p NULL - * - * @api - */ -void rtcConvertDateTimeToStructTm(const RTCDateTime *timespec, - struct tm *timp, - uint32_t *tv_msec) { - int sec; - - timp->tm_year = (int)timespec->year + (1980 - 1900); - timp->tm_mon = (int)timespec->month - 1; - timp->tm_mday = (int)timespec->day; - timp->tm_isdst = (int)timespec->dstflag; - timp->tm_wday = (int)timespec->dayofweek - 1; - - sec = (int)timespec->millisecond / 1000; - timp->tm_hour = sec / 3600; - sec %= 3600; - timp->tm_min = sec / 60; - timp->tm_sec = sec % 60; - - if (NULL != tv_msec) { - *tv_msec = (uint32_t)timespec->millisecond % 1000U; - } -} - -/** - * @brief Convert broken-down time structure to @p RTCDateTime. - * - * @param[in] timp pointer to a broken-down time structure - * @param[in] tv_msec milliseconds value - * @param[out] timespec pointer to a @p RTCDateTime structure - * - * @api - */ -void rtcConvertStructTmToDateTime(const struct tm *timp, - uint32_t tv_msec, - RTCDateTime *timespec) { - - /*lint -save -e9034 [10.4] Verified assignments to bit fields.*/ - timespec->year = (uint32_t)timp->tm_year - (1980U - 1900U); - timespec->month = (uint32_t)timp->tm_mon + 1U; - timespec->day = (uint32_t)timp->tm_mday; - timespec->dayofweek = (uint32_t)timp->tm_wday + 1U; - if (-1 == timp->tm_isdst) { - timespec->dstflag = 0U; /* set zero if dst is unknown */ - } - else { - timespec->dstflag = (uint32_t)timp->tm_isdst; - } - /*lint -restore*/ - /*lint -save -e9033 [10.8] Verified assignments to bit fields.*/ - timespec->millisecond = tv_msec + (uint32_t)(((timp->tm_hour * 3600) + - (timp->tm_min * 60) + - timp->tm_sec) * 1000); - /*lint -restore*/ -} - -/** - * @brief Get current time in format suitable for usage in FAT file system. - * @note The information about day of week and DST is lost in DOS - * format, the second field loses its least significant bit. - * - * @param[out] timespec pointer to a @p RTCDateTime structure - * @return FAT date/time value. - * - * @api - */ -uint32_t rtcConvertDateTimeToFAT(const RTCDateTime *timespec) { - uint32_t fattime; - uint32_t sec, min, hour, day, month; - - sec = timespec->millisecond / 1000U; - hour = sec / 3600U; - sec %= 3600U; - min = sec / 60U; - sec %= 60U; - day = timespec->day; - month = timespec->month; - - /* handle DST flag */ - if (1U == timespec->dstflag) { - hour += 1U; - if (hour == 24U) { - hour = 0U; - day += 1U; - if (day > month_len[month - 1U]) { - day = 1U; - month += 1U; - } - } - } - - fattime = sec >> 1U; - fattime |= min << 5U; - fattime |= hour << 11U; - fattime |= day << 16U; - fattime |= month << 21U; - fattime |= (uint32_t)timespec->year << 25U; - - return fattime; -} - -#endif /* HAL_USE_RTC == TRUE */ - -/** @} */ diff --git a/os/hal/src/sdc.c b/os/hal/src/sdc.c deleted file mode 100644 index bd2c0bef6..000000000 --- a/os/hal/src/sdc.c +++ /dev/null @@ -1,1005 +0,0 @@ -/* - ChibiOS - Copyright (C) 2006..2016 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 sdc.c - * @brief SDC Driver code. - * - * @addtogroup SDC - * @{ - */ - -#include - -#include "hal.h" - -#if (HAL_USE_SDC == TRUE) || defined(__DOXYGEN__) - -/*===========================================================================*/ -/* Driver local definitions. */ -/*===========================================================================*/ - -/** - * @brief MMC switch mode. - */ -typedef enum { - MMC_SWITCH_COMMAND_SET = 0, - MMC_SWITCH_SET_BITS = 1, - MMC_SWITCH_CLEAR_BITS = 2, - MMC_SWITCH_WRITE_BYTE = 3 -} mmc_switch_t; - -/** - * @brief SDC switch mode. - */ -typedef enum { - SD_SWITCH_CHECK = 0, - SD_SWITCH_SET = 1 -} sd_switch_t; - -/** - * @brief SDC switch function. - */ -typedef enum { - SD_SWITCH_FUNCTION_SPEED = 0, - SD_SWITCH_FUNCTION_CMD_SYSTEM = 1, - SD_SWITCH_FUNCTION_DRIVER_STRENGTH = 2, - SD_SWITCH_FUNCTION_CURRENT_LIMIT = 3 -} sd_switch_function_t; - -/*===========================================================================*/ -/* Driver exported variables. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver local variables and types. */ -/*===========================================================================*/ - -/** - * @brief Virtual methods table. - */ -static const struct SDCDriverVMT sdc_vmt = { - (bool (*)(void *))sdc_lld_is_card_inserted, - (bool (*)(void *))sdc_lld_is_write_protected, - (bool (*)(void *))sdcConnect, - (bool (*)(void *))sdcDisconnect, - (bool (*)(void *, uint32_t, uint8_t *, uint32_t))sdcRead, - (bool (*)(void *, uint32_t, const uint8_t *, uint32_t))sdcWrite, - (bool (*)(void *))sdcSync, - (bool (*)(void *, BlockDeviceInfo *))sdcGetInfo -}; - -/*===========================================================================*/ -/* Driver local functions. */ -/*===========================================================================*/ -/** - * @brief Detects card mode. - * - * @param[in] sdcp pointer to the @p SDCDriver object - * - * @return The operation status. - * @retval HAL_SUCCESS operation succeeded. - * @retval HAL_FAILED operation failed. - * - * @notapi - */ -static bool mode_detect(SDCDriver *sdcp) { - uint32_t resp[1]; - - /* V2.0 cards detection.*/ - if (!sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_SEND_IF_COND, - MMCSD_CMD8_PATTERN, resp)) { - sdcp->cardmode = SDC_MODE_CARDTYPE_SDV20; - /* Voltage verification.*/ - if (((resp[0] >> 8U) & 0xFU) != 1U) { - return HAL_FAILED; - } - if (sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_APP_CMD, 0, resp) || - MMCSD_R1_ERROR(resp[0])) { - return HAL_FAILED; - } - } - else { - /* MMC or SD V1.1 detection.*/ - if (sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_APP_CMD, 0, resp) || - MMCSD_R1_ERROR(resp[0])) { - sdcp->cardmode = SDC_MODE_CARDTYPE_MMC; - } - else { - sdcp->cardmode = SDC_MODE_CARDTYPE_SDV11; - - /* Reset error flag illegal command.*/ - sdc_lld_send_cmd_none(sdcp, MMCSD_CMD_GO_IDLE_STATE, 0); - } - } - - return HAL_SUCCESS; -} - -/** - * @brief Init procedure for MMC. - * - * @param[in] sdcp pointer to the @p SDCDriver object - * - * @return The operation status. - * @retval HAL_SUCCESS operation succeeded. - * @retval HAL_FAILED operation failed. - * - * @notapi - */ -static bool mmc_init(SDCDriver *sdcp) { - uint32_t ocr; - unsigned i; - uint32_t resp[1]; - - ocr = 0xC0FF8000U; - i = 0; - while (true) { - if (sdc_lld_send_cmd_short(sdcp, MMCSD_CMD_INIT, ocr, resp)) { - return HAL_FAILED; - } - if ((resp[0] & 0x80000000U) != 0U) { - if ((resp[0] & 0x40000000U) != 0U) { - sdcp->cardmode |= SDC_MODE_HIGH_CAPACITY; - } - break; - } - if (++i >= (unsigned)SDC_INIT_RETRY) { - return HAL_FAILED; - } - osalThreadSleepMilliseconds(10); - } - - return HAL_SUCCESS; -} - -/** - * @brief Init procedure for SDC. - * - * @param[in] sdcp pointer to the @p SDCDriver object - * - * @return The operation status. - * @retval HAL_SUCCESS operation succeeded. - * @retval HAL_FAILED operation failed. - * - * @notapi - */ -static bool sdc_init(SDCDriver *sdcp) { - unsigned i; - uint32_t ocr; - uint32_t resp[1]; - - if ((sdcp->cardmode & SDC_MODE_CARDTYPE_MASK) == SDC_MODE_CARDTYPE_SDV20) { - ocr = 0xC0100000U; - } - else { - ocr = 0x80100000U; - } - - i = 0; - while (true) { - if (sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_APP_CMD, 0, resp) || - MMCSD_R1_ERROR(resp[0])) { - return HAL_FAILED; - } - if (sdc_lld_send_cmd_short(sdcp, MMCSD_CMD_APP_OP_COND, ocr, resp)) { - return HAL_FAILED; - } - if ((resp[0] & 0x80000000U) != 0U) { - if ((resp[0] & 0x40000000U) != 0U) { - sdcp->cardmode |= SDC_MODE_HIGH_CAPACITY; - } - break; - } - if (++i >= (unsigned)SDC_INIT_RETRY) { - return HAL_FAILED; - } - osalThreadSleepMilliseconds(10); - } - - return HAL_SUCCESS; -} - -/** - * @brief Constructs CMD6 argument for MMC. - * - * @param[in] access EXT_CSD access mode - * @param[in] idx EXT_CSD byte number - * @param[in] value value to be written in target field - * @param[in] cmd_set switch current command set - * - * @return CMD6 argument. - * - * @notapi - */ -static uint32_t mmc_cmd6_construct(mmc_switch_t access, uint32_t idx, - uint32_t value, uint32_t cmd_set) { - - osalDbgAssert(idx <= 191U, "This field is not writable"); - osalDbgAssert(cmd_set < 8U, "This field has only 3 bits"); - - return ((uint32_t)access << 24U) | (idx << 16U) | (value << 8U) | cmd_set; -} - -/** - * @brief Constructs CMD6 argument for SDC. - * - * @param[in] mode switch/test mode - * @param[in] function function number to be switched - * @param[in] value value to be written in target function - * - * @return CMD6 argument. - * - * @notapi - */ -static uint32_t sdc_cmd6_construct(sd_switch_t mode, - sd_switch_function_t function, - uint32_t value) { - uint32_t ret = 0xFFFFFF; - - osalDbgAssert((value < 16U), "This field has only 4 bits"); - - ret &= ~((uint32_t)0xFU << ((uint32_t)function * 4U)); - ret |= value << ((uint32_t)function * 4U); - return ret | ((uint32_t)mode << 31U); -} - -/** - * @brief Extracts information from CMD6 answer. - * - * @param[in] function function number to be switched - * @param[in] buf buffer with answer - * - * @return extracted answer. - * - * @notapi - */ -static uint16_t sdc_cmd6_extract_info(sd_switch_function_t function, - const uint8_t *buf) { - - unsigned start = 12U - ((unsigned)function * 2U); - - return ((uint16_t)buf[start] << 8U) | (uint16_t)buf[start + 1U]; -} - -/** - * @brief Checks status after switching using CMD6. - * - * @param[in] function function number to be switched - * @param[in] buf buffer with answer - * - * @return The operation status. - * @retval HAL_SUCCESS operation succeeded. - * @retval HAL_FAILED operation failed. - * - * @notapi - */ -static bool sdc_cmd6_check_status(sd_switch_function_t function, - const uint8_t *buf) { - - uint32_t tmp; - uint32_t status; - - tmp = ((uint32_t)buf[14] << 16U) | - ((uint32_t)buf[15] << 8U) | - (uint32_t)buf[16]; - status = (tmp >> ((uint32_t)function * 4U)) & 0xFU; - if (0xFU != status) { - return HAL_SUCCESS; - } - return HAL_FAILED; -} - -/** - * @brief Reads supported bus clock and switch SDC to appropriate mode. - * - * @param[in] sdcp pointer to the @p SDCDriver object - * @param[out] clk pointer to clock enum - * - * @return The operation status. - * @retval HAL_SUCCESS operation succeeded. - * @retval HAL_FAILED operation failed. - * - * @notapi - */ -static bool sdc_detect_bus_clk(SDCDriver *sdcp, sdcbusclk_t *clk) { - uint32_t cmdarg; - const size_t N = 64; - uint8_t tmp[N]; - - /* Safe default.*/ - *clk = SDC_CLK_25MHz; - - /* Looks like only "high capacity" cards produce meaningful results during - this clock detection procedure.*/ - if (0U == _mmcsd_get_slice(sdcp->csd, MMCSD_CSD_10_CSD_STRUCTURE_SLICE)) { - *clk = SDC_CLK_25MHz; - return HAL_SUCCESS; - } - - /* Read switch functions' register.*/ - if (sdc_lld_read_special(sdcp, tmp, N, MMCSD_CMD_SWITCH, 0)) { - return HAL_FAILED; - } - - /* Check card capabilities parsing acquired data.*/ - if ((sdc_cmd6_extract_info(SD_SWITCH_FUNCTION_SPEED, tmp) & 2U) == 2U) { - /* Construct command to set the bus speed.*/ - cmdarg = sdc_cmd6_construct(SD_SWITCH_SET, SD_SWITCH_FUNCTION_SPEED, 1); - - /* Write constructed command and read operation status in single call.*/ - if (sdc_lld_read_special(sdcp, tmp, N, MMCSD_CMD_SWITCH, cmdarg)) { - return HAL_FAILED; - } - - /* Check card answer for success status bits.*/ - if (HAL_SUCCESS == sdc_cmd6_check_status(SD_SWITCH_FUNCTION_SPEED, tmp)) { - *clk = SDC_CLK_50MHz; - } - else { - *clk = SDC_CLK_25MHz; - } - } - - return HAL_SUCCESS; -} - -/** - * @brief Reads supported bus clock and switch MMC to appropriate mode. - * - * @param[in] sdcp pointer to the @p SDCDriver object - * @param[out] clk pointer to clock enum - * - * @return The operation status. - * @retval HAL_SUCCESS operation succeeded. - * @retval HAL_FAILED operation failed. - * - * @notapi - */ -static bool mmc_detect_bus_clk(SDCDriver *sdcp, sdcbusclk_t *clk) { - uint32_t cmdarg; - uint32_t resp[1]; - uint8_t *scratchpad = sdcp->config->scratchpad; - - /* Safe default.*/ - *clk = SDC_CLK_25MHz; - - /* Use safe default when there is no space for data.*/ - if (NULL == scratchpad) { - return HAL_SUCCESS; - } - - cmdarg = mmc_cmd6_construct(MMC_SWITCH_WRITE_BYTE, 185, 1, 0); - if (!(sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_SWITCH, cmdarg, resp) || - MMCSD_R1_ERROR(resp[0]))) { - *clk = SDC_CLK_50MHz; - } - - return HAL_SUCCESS; -} - -/** - * @brief Reads supported bus clock and switch card to appropriate mode. - * - * @param[in] sdcp pointer to the @p SDCDriver object - * @param[out] clk pointer to clock enum - * - * @return The operation status. - * @retval HAL_SUCCESS operation succeeded. - * @retval HAL_FAILED operation failed. - * - * @notapi - */ -static bool detect_bus_clk(SDCDriver *sdcp, sdcbusclk_t *clk) { - - if (SDC_MODE_CARDTYPE_MMC == (sdcp->cardmode & SDC_MODE_CARDTYPE_MASK)) { - return mmc_detect_bus_clk(sdcp, clk); - } - return sdc_detect_bus_clk(sdcp, clk); -} - -/** - * @brief Sets bus width for SDC. - * - * @param[in] sdcp pointer to the @p SDCDriver object - * - * @return The operation status. - * @retval HAL_SUCCESS operation succeeded. - * @retval HAL_FAILED operation failed. - * - * @notapi - */ -static bool sdc_set_bus_width(SDCDriver *sdcp) { - uint32_t resp[1]; - - if (SDC_MODE_1BIT == sdcp->config->bus_width) { - /* Nothing to do. Bus is already in 1bit mode.*/ - return HAL_SUCCESS; - } - else if (SDC_MODE_4BIT == sdcp->config->bus_width) { - sdc_lld_set_bus_mode(sdcp, SDC_MODE_4BIT); - if (sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_APP_CMD, sdcp->rca, resp) || - MMCSD_R1_ERROR(resp[0])) { - return HAL_FAILED; - } - - if (sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_SET_BUS_WIDTH, 2, resp) || - MMCSD_R1_ERROR(resp[0])) { - return HAL_FAILED; - } - } - else { - /* SD card does not support 8bit bus.*/ - return HAL_FAILED; - } - - return HAL_SUCCESS; -} - -/** - * @brief Sets bus width for MMC. - * - * @param[in] sdcp pointer to the @p SDCDriver object - * - * @return The operation status. - * @retval HAL_SUCCESS operation succeeded. - * @retval HAL_FAILED operation failed. - * - * @notapi - */ -static bool mmc_set_bus_width(SDCDriver *sdcp) { - uint32_t resp[1]; - uint32_t cmdarg = mmc_cmd6_construct(MMC_SWITCH_WRITE_BYTE, 183, 0, 0); - - switch(sdcp->config->bus_width){ - case SDC_MODE_1BIT: - /* Nothing to do. Bus is already in 1bit mode.*/ - return HAL_SUCCESS; - case SDC_MODE_4BIT: - cmdarg = mmc_cmd6_construct(MMC_SWITCH_WRITE_BYTE, 183, 1, 0); - break; - case SDC_MODE_8BIT: - cmdarg = mmc_cmd6_construct(MMC_SWITCH_WRITE_BYTE, 183, 2, 0); - break; - default: - osalDbgAssert(false, "unexpected case"); - break; - } - - sdc_lld_set_bus_mode(sdcp, sdcp->config->bus_width); - if (sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_SWITCH, cmdarg, resp) || - MMCSD_R1_ERROR(resp[0])) { - return HAL_FAILED; - } - - return HAL_SUCCESS; -} - -/** - * @brief Wait for the card to complete pending operations. - * - * @param[in] sdcp pointer to the @p SDCDriver object - * - * @return The operation status. - * @retval HAL_SUCCESS operation succeeded. - * @retval HAL_FAILED operation failed. - * - * @notapi - */ -bool _sdc_wait_for_transfer_state(SDCDriver *sdcp) { - uint32_t resp[1]; - - while (true) { - if (sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_SEND_STATUS, - sdcp->rca, resp) || - MMCSD_R1_ERROR(resp[0])) { - return HAL_FAILED; - } - - switch (MMCSD_R1_STS(resp[0])) { - case MMCSD_STS_TRAN: - return HAL_SUCCESS; - case MMCSD_STS_DATA: - case MMCSD_STS_RCV: - case MMCSD_STS_PRG: -#if SDC_NICE_WAITING == TRUE - osalThreadSleepMilliseconds(1); -#endif - continue; - default: - /* The card should have been initialized so any other state is not - valid and is reported as an error.*/ - return HAL_FAILED; - } - } -} - -/*===========================================================================*/ -/* Driver exported functions. */ -/*===========================================================================*/ - -/** - * @brief SDC Driver initialization. - * @note This function is implicitly invoked by @p halInit(), there is - * no need to explicitly initialize the driver. - * - * @init - */ -void sdcInit(void) { - - sdc_lld_init(); -} - -/** - * @brief Initializes the standard part of a @p SDCDriver structure. - * - * @param[out] sdcp pointer to the @p SDCDriver object - * - * @init - */ -void sdcObjectInit(SDCDriver *sdcp) { - - sdcp->vmt = &sdc_vmt; - sdcp->state = BLK_STOP; - sdcp->errors = SDC_NO_ERROR; - sdcp->config = NULL; - sdcp->capacity = 0; -} - -/** - * @brief Configures and activates the SDC peripheral. - * - * @param[in] sdcp pointer to the @p SDCDriver object - * @param[in] config pointer to the @p SDCConfig object, can be @p NULL if - * the driver supports a default configuration or - * requires no configuration - * - * @api - */ -void sdcStart(SDCDriver *sdcp, const SDCConfig *config) { - - osalDbgCheck(sdcp != NULL); - - osalSysLock(); - osalDbgAssert((sdcp->state == BLK_STOP) || (sdcp->state == BLK_ACTIVE), - "invalid state"); - sdcp->config = config; - sdc_lld_start(sdcp); - sdcp->state = BLK_ACTIVE; - osalSysUnlock(); -} - -/** - * @brief Deactivates the SDC peripheral. - * - * @param[in] sdcp pointer to the @p SDCDriver object - * - * @api - */ -void sdcStop(SDCDriver *sdcp) { - - osalDbgCheck(sdcp != NULL); - - osalSysLock(); - osalDbgAssert((sdcp->state == BLK_STOP) || (sdcp->state == BLK_ACTIVE), - "invalid state"); - sdc_lld_stop(sdcp); - sdcp->state = BLK_STOP; - osalSysUnlock(); -} - -/** - * @brief Performs the initialization procedure on the inserted card. - * @details This function should be invoked when a card is inserted and - * brings the driver in the @p BLK_READY state where it is possible - * to perform read and write operations. - * - * @param[in] sdcp pointer to the @p SDCDriver object - * - * @return The operation status. - * @retval HAL_SUCCESS operation succeeded. - * @retval HAL_FAILED operation failed. - * - * @api - */ -bool sdcConnect(SDCDriver *sdcp) { - uint32_t resp[1]; - sdcbusclk_t clk = SDC_CLK_25MHz; - - osalDbgCheck(sdcp != NULL); - osalDbgAssert((sdcp->state == BLK_ACTIVE) || (sdcp->state == BLK_READY), - "invalid state"); - - /* Connection procedure in progress.*/ - sdcp->state = BLK_CONNECTING; - - /* Card clock initialization.*/ - sdc_lld_start_clk(sdcp); - - /* Enforces the initial card state.*/ - sdc_lld_send_cmd_none(sdcp, MMCSD_CMD_GO_IDLE_STATE, 0); - - /* Detect card type.*/ - if (HAL_FAILED == mode_detect(sdcp)) { - goto failed; - } - - /* Perform specific initialization procedure.*/ - if ((sdcp->cardmode & SDC_MODE_CARDTYPE_MASK) == SDC_MODE_CARDTYPE_MMC) { - if (HAL_FAILED == mmc_init(sdcp)) { - goto failed; - } - } - else { - if (HAL_FAILED == sdc_init(sdcp)) { - goto failed; - } - } - - /* Reads CID.*/ - if (sdc_lld_send_cmd_long_crc(sdcp, MMCSD_CMD_ALL_SEND_CID, 0, sdcp->cid)) { - goto failed; - } - - /* Asks for the RCA.*/ - if (sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_SEND_RELATIVE_ADDR, - 0, &sdcp->rca)) { - goto failed; - } - - /* Reads CSD.*/ - if (sdc_lld_send_cmd_long_crc(sdcp, MMCSD_CMD_SEND_CSD, - sdcp->rca, sdcp->csd)) { - goto failed; - } - - /* Selects the card for operations.*/ - if (sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_SEL_DESEL_CARD, - sdcp->rca, resp)) { - goto failed; - } - - /* Switches to high speed.*/ - if (HAL_SUCCESS != detect_bus_clk(sdcp, &clk)) { - goto failed; - } - sdc_lld_set_data_clk(sdcp, clk); - - /* Reads extended CSD if needed and possible.*/ - if (SDC_MODE_CARDTYPE_MMC == (sdcp->cardmode & SDC_MODE_CARDTYPE_MASK)) { - - /* The card is a MMC, checking if it is a large device.*/ - if (_mmcsd_get_slice(sdcp->csd, MMCSD_CSD_MMC_CSD_STRUCTURE_SLICE) > 1U) { - uint8_t *ext_csd = sdcp->config->scratchpad; - - /* Size detection requires the buffer.*/ - if (NULL == ext_csd) { - goto failed; - } - - if(sdc_lld_read_special(sdcp, ext_csd, 512, MMCSD_CMD_SEND_EXT_CSD, 0)) { - goto failed; - } - - /* Capacity from the EXT_CSD.*/ - sdcp->capacity = _mmcsd_get_capacity_ext(ext_csd); - } - else { - /* Capacity from the normal CSD.*/ - sdcp->capacity = _mmcsd_get_capacity(sdcp->csd); - } - } - else { - /* The card is an SDC, capacity from the normal CSD.*/ - sdcp->capacity = _mmcsd_get_capacity(sdcp->csd); - } - - /* Block length fixed at 512 bytes.*/ - if (sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_SET_BLOCKLEN, - MMCSD_BLOCK_SIZE, resp) || - MMCSD_R1_ERROR(resp[0])) { - goto failed; - } - - /* Switches to wide bus mode.*/ - switch (sdcp->cardmode & SDC_MODE_CARDTYPE_MASK) { - case SDC_MODE_CARDTYPE_SDV11: - case SDC_MODE_CARDTYPE_SDV20: - if (HAL_FAILED == sdc_set_bus_width(sdcp)) { - goto failed; - } - break; - case SDC_MODE_CARDTYPE_MMC: - if (HAL_FAILED == mmc_set_bus_width(sdcp)) { - goto failed; - } - break; - default: - /* Unknown type.*/ - goto failed; - } - - /* Initialization complete.*/ - sdcp->state = BLK_READY; - return HAL_SUCCESS; - - /* Connection failed, state reset to BLK_ACTIVE.*/ -failed: - sdc_lld_stop_clk(sdcp); - sdcp->state = BLK_ACTIVE; - return HAL_FAILED; -} - -/** - * @brief Brings the driver in a state safe for card removal. - * - * @param[in] sdcp pointer to the @p SDCDriver object - * - * @return The operation status. - * @retval HAL_SUCCESS operation succeeded. - * @retval HAL_FAILED operation failed. - * - * @api - */ -bool sdcDisconnect(SDCDriver *sdcp) { - - osalDbgCheck(sdcp != NULL); - - osalSysLock(); - osalDbgAssert((sdcp->state == BLK_ACTIVE) || (sdcp->state == BLK_READY), - "invalid state"); - if (sdcp->state == BLK_ACTIVE) { - osalSysUnlock(); - return HAL_SUCCESS; - } - sdcp->state = BLK_DISCONNECTING; - osalSysUnlock(); - - /* Waits for eventual pending operations completion.*/ - if (_sdc_wait_for_transfer_state(sdcp)) { - sdc_lld_stop_clk(sdcp); - sdcp->state = BLK_ACTIVE; - return HAL_FAILED; - } - - /* Card clock stopped.*/ - sdc_lld_stop_clk(sdcp); - sdcp->state = BLK_ACTIVE; - return HAL_SUCCESS; -} - -/** - * @brief Reads one or more blocks. - * @pre The driver must be in the @p BLK_READY state after a successful - * sdcConnect() invocation. - * - * @param[in] sdcp pointer to the @p SDCDriver object - * @param[in] startblk first block to read - * @param[out] buf pointer to the read buffer - * @param[in] n number of blocks to read - * - * @return The operation status. - * @retval HAL_SUCCESS operation succeeded. - * @retval HAL_FAILED operation failed. - * - * @api - */ -bool sdcRead(SDCDriver *sdcp, uint32_t startblk, uint8_t *buf, uint32_t n) { - bool status; - - osalDbgCheck((sdcp != NULL) && (buf != NULL) && (n > 0U)); - osalDbgAssert(sdcp->state == BLK_READY, "invalid state"); - - if ((startblk + n - 1U) > sdcp->capacity){ - sdcp->errors |= SDC_OVERFLOW_ERROR; - return HAL_FAILED; - } - - /* Read operation in progress.*/ - sdcp->state = BLK_READING; - - status = sdc_lld_read(sdcp, startblk, buf, n); - - /* Read operation finished.*/ - sdcp->state = BLK_READY; - return status; -} - -/** - * @brief Writes one or more blocks. - * @pre The driver must be in the @p BLK_READY state after a successful - * sdcConnect() invocation. - * - * @param[in] sdcp pointer to the @p SDCDriver object - * @param[in] startblk first block to write - * @param[out] buf pointer to the write buffer - * @param[in] n number of blocks to write - * - * @return The operation status. - * @retval HAL_SUCCESS operation succeeded. - * @retval HAL_FAILED operation failed. - * - * @api - */ -bool sdcWrite(SDCDriver *sdcp, uint32_t startblk, - const uint8_t *buf, uint32_t n) { - bool status; - - osalDbgCheck((sdcp != NULL) && (buf != NULL) && (n > 0U)); - osalDbgAssert(sdcp->state == BLK_READY, "invalid state"); - - if ((startblk + n - 1U) > sdcp->capacity){ - sdcp->errors |= SDC_OVERFLOW_ERROR; - return HAL_FAILED; - } - - /* Write operation in progress.*/ - sdcp->state = BLK_WRITING; - - status = sdc_lld_write(sdcp, startblk, buf, n); - - /* Write operation finished.*/ - sdcp->state = BLK_READY; - return status; -} - -/** - * @brief Returns the errors mask associated to the previous operation. - * - * @param[in] sdcp pointer to the @p SDCDriver object - * @return The errors mask. - * - * @api - */ -sdcflags_t sdcGetAndClearErrors(SDCDriver *sdcp) { - sdcflags_t flags; - - osalDbgCheck(sdcp != NULL); - osalDbgAssert(sdcp->state == BLK_READY, "invalid state"); - - osalSysLock(); - flags = sdcp->errors; - sdcp->errors = SDC_NO_ERROR; - osalSysUnlock(); - return flags; -} - -/** - * @brief Waits for card idle condition. - * - * @param[in] sdcp pointer to the @p SDCDriver object - * - * @return The operation status. - * @retval HAL_SUCCESS the operation succeeded. - * @retval HAL_FAILED the operation failed. - * - * @api - */ -bool sdcSync(SDCDriver *sdcp) { - bool result; - - osalDbgCheck(sdcp != NULL); - - if (sdcp->state != BLK_READY) { - return HAL_FAILED; - } - - /* Synchronization operation in progress.*/ - sdcp->state = BLK_SYNCING; - - result = sdc_lld_sync(sdcp); - - /* Synchronization operation finished.*/ - sdcp->state = BLK_READY; - return result; -} - -/** - * @brief Returns the media info. - * - * @param[in] sdcp pointer to the @p SDCDriver object - * @param[out] bdip pointer to a @p BlockDeviceInfo structure - * - * @return The operation status. - * @retval HAL_SUCCESS the operation succeeded. - * @retval HAL_FAILED the operation failed. - * - * @api - */ -bool sdcGetInfo(SDCDriver *sdcp, BlockDeviceInfo *bdip) { - - osalDbgCheck((sdcp != NULL) && (bdip != NULL)); - - if (sdcp->state != BLK_READY) { - return HAL_FAILED; - } - - bdip->blk_num = sdcp->capacity; - bdip->blk_size = MMCSD_BLOCK_SIZE; - - return HAL_SUCCESS; -} - -/** - * @brief Erases the supplied blocks. - * - * @param[in] sdcp pointer to the @p SDCDriver object - * @param[in] startblk starting block number - * @param[in] endblk ending block number - * - * @return The operation status. - * @retval HAL_SUCCESS the operation succeeded. - * @retval HAL_FAILED the operation failed. - * - * @api - */ -bool sdcErase(SDCDriver *sdcp, uint32_t startblk, uint32_t endblk) { - uint32_t resp[1]; - - osalDbgCheck((sdcp != NULL)); - osalDbgAssert(sdcp->state == BLK_READY, "invalid state"); - - /* Erase operation in progress.*/ - sdcp->state = BLK_WRITING; - - /* Handling command differences between HC and normal cards.*/ - if ((sdcp->cardmode & SDC_MODE_HIGH_CAPACITY) != 0U) { - startblk *= MMCSD_BLOCK_SIZE; - endblk *= MMCSD_BLOCK_SIZE; - } - - if (_sdc_wait_for_transfer_state(sdcp)) { - goto failed; - } - - if ((sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_ERASE_RW_BLK_START, - startblk, resp) != HAL_SUCCESS) || - MMCSD_R1_ERROR(resp[0])) { - goto failed; - } - - if ((sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_ERASE_RW_BLK_END, - endblk, resp) != HAL_SUCCESS) || - MMCSD_R1_ERROR(resp[0])) { - goto failed; - } - - if ((sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_ERASE, - 0, resp) != HAL_SUCCESS) || - MMCSD_R1_ERROR(resp[0])) { - goto failed; - } - - /* Quick sleep to allow it to transition to programming or receiving state */ - /* TODO: ??????????????????????????? */ - - /* Wait for it to return to transfer state to indicate it has finished erasing */ - if (_sdc_wait_for_transfer_state(sdcp)) { - goto failed; - } - - sdcp->state = BLK_READY; - return HAL_SUCCESS; - -failed: - sdcp->state = BLK_READY; - return HAL_FAILED; -} - -#endif /* HAL_USE_SDC == TRUE */ - -/** @} */ - diff --git a/os/hal/src/serial.c b/os/hal/src/serial.c deleted file mode 100644 index a0956ba9a..000000000 --- a/os/hal/src/serial.c +++ /dev/null @@ -1,289 +0,0 @@ -/* - ChibiOS - Copyright (C) 2006..2016 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 serial.c - * @brief Serial Driver code. - * - * @addtogroup SERIAL - * @{ - */ - -#include "hal.h" - -#if (HAL_USE_SERIAL == TRUE) || defined(__DOXYGEN__) - -/*===========================================================================*/ -/* Driver local definitions. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver exported variables. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver local variables and types. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver local functions. */ -/*===========================================================================*/ - -/* - * Interface implementation, the following functions just invoke the equivalent - * queue-level function or macro. - */ - -static size_t write(void *ip, const uint8_t *bp, size_t n) { - - return oqWriteTimeout(&((SerialDriver *)ip)->oqueue, bp, - n, TIME_INFINITE); -} - -static size_t read(void *ip, uint8_t *bp, size_t n) { - - return iqReadTimeout(&((SerialDriver *)ip)->iqueue, bp, - n, TIME_INFINITE); -} - -static msg_t put(void *ip, uint8_t b) { - - return oqPutTimeout(&((SerialDriver *)ip)->oqueue, b, TIME_INFINITE); -} - -static msg_t get(void *ip) { - - return iqGetTimeout(&((SerialDriver *)ip)->iqueue, TIME_INFINITE); -} - -static msg_t putt(void *ip, uint8_t b, systime_t timeout) { - - return oqPutTimeout(&((SerialDriver *)ip)->oqueue, b, timeout); -} - -static msg_t gett(void *ip, systime_t timeout) { - - return iqGetTimeout(&((SerialDriver *)ip)->iqueue, timeout); -} - -static size_t writet(void *ip, const uint8_t *bp, size_t n, systime_t timeout) { - - return oqWriteTimeout(&((SerialDriver *)ip)->oqueue, bp, n, timeout); -} - -static size_t readt(void *ip, uint8_t *bp, size_t n, systime_t timeout) { - - return iqReadTimeout(&((SerialDriver *)ip)->iqueue, bp, n, timeout); -} - -static const struct SerialDriverVMT vmt = { - write, read, put, get, - putt, gett, writet, readt -}; - -/*===========================================================================*/ -/* Driver exported functions. */ -/*===========================================================================*/ - -/** - * @brief Serial Driver initialization. - * @note This function is implicitly invoked by @p halInit(), there is - * no need to explicitly initialize the driver. - * - * @init - */ -void sdInit(void) { - - sd_lld_init(); -} - -/** - * @brief Initializes a generic full duplex driver object. - * @details The HW dependent part of the initialization has to be performed - * outside, usually in the hardware initialization code. - * - * @param[out] sdp pointer to a @p SerialDriver structure - * @param[in] inotify pointer to a callback function that is invoked when - * some data is read from the Queue. The value can be - * @p NULL. - * @param[in] onotify pointer to a callback function that is invoked when - * some data is written in the Queue. The value can be - * @p NULL. - * - * @init - */ -void sdObjectInit(SerialDriver *sdp, qnotify_t inotify, qnotify_t onotify) { - - sdp->vmt = &vmt; - osalEventObjectInit(&sdp->event); - sdp->state = SD_STOP; - iqObjectInit(&sdp->iqueue, sdp->ib, SERIAL_BUFFERS_SIZE, inotify, sdp); - oqObjectInit(&sdp->oqueue, sdp->ob, SERIAL_BUFFERS_SIZE, onotify, sdp); -} - -/** - * @brief Configures and starts the driver. - * - * @param[in] sdp pointer to a @p SerialDriver object - * @param[in] config the architecture-dependent serial driver configuration. - * If this parameter is set to @p NULL then a default - * configuration is used. - * - * @api - */ -void sdStart(SerialDriver *sdp, const SerialConfig *config) { - - osalDbgCheck(sdp != NULL); - - osalSysLock(); - osalDbgAssert((sdp->state == SD_STOP) || (sdp->state == SD_READY), - "invalid state"); - sd_lld_start(sdp, config); - sdp->state = SD_READY; - osalSysUnlock(); -} - -/** - * @brief Stops the driver. - * @details Any thread waiting on the driver's queues will be awakened with - * the message @p MSG_RESET. - * - * @param[in] sdp pointer to a @p SerialDriver object - * - * @api - */ -void sdStop(SerialDriver *sdp) { - - osalDbgCheck(sdp != NULL); - - osalSysLock(); - osalDbgAssert((sdp->state == SD_STOP) || (sdp->state == SD_READY), - "invalid state"); - sd_lld_stop(sdp); - sdp->state = SD_STOP; - oqResetI(&sdp->oqueue); - iqResetI(&sdp->iqueue); - osalOsRescheduleS(); - osalSysUnlock(); -} - -/** - * @brief Handles incoming data. - * @details This function must be called from the input interrupt service - * routine in order to enqueue incoming data and generate the - * related events. - * @note The incoming data event is only generated when the input queue - * becomes non-empty. - * @note In order to gain some performance it is suggested to not use - * this function directly but copy this code directly into the - * interrupt service routine. - * - * @param[in] sdp pointer to a @p SerialDriver structure - * @param[in] b the byte to be written in the driver's Input Queue - * - * @iclass - */ -void sdIncomingDataI(SerialDriver *sdp, uint8_t b) { - - osalDbgCheckClassI(); - osalDbgCheck(sdp != NULL); - - if (iqIsEmptyI(&sdp->iqueue)) - chnAddFlagsI(sdp, CHN_INPUT_AVAILABLE); - if (iqPutI(&sdp->iqueue, b) < MSG_OK) - chnAddFlagsI(sdp, SD_OVERRUN_ERROR); -} - -/** - * @brief Handles outgoing data. - * @details Must be called from the output interrupt service routine in order - * to get the next byte to be transmitted. - * @note In order to gain some performance it is suggested to not use - * this function directly but copy this code directly into the - * interrupt service routine. - * - * @param[in] sdp pointer to a @p SerialDriver structure - * @return The byte value read from the driver's output queue. - * @retval MSG_TIMEOUT if the queue is empty (the lower driver usually - * disables the interrupt source when this happens). - * - * @iclass - */ -msg_t sdRequestDataI(SerialDriver *sdp) { - msg_t b; - - osalDbgCheckClassI(); - osalDbgCheck(sdp != NULL); - - b = oqGetI(&sdp->oqueue); - if (b < MSG_OK) - chnAddFlagsI(sdp, CHN_OUTPUT_EMPTY); - return b; -} - -/** - * @brief Direct output check on a @p SerialDriver. - * @note This function bypasses the indirect access to the channel and - * checks directly the output queue. This is faster but cannot - * be used to check different channels implementations. - * - * @param[in] sdp pointer to a @p SerialDriver structure - * @return The queue status. - * @retval false if the next write operation would not block. - * @retval true if the next write operation would block. - * - * @deprecated - * - * @api - */ -bool sdPutWouldBlock(SerialDriver *sdp) { - bool b; - - osalSysLock(); - b = oqIsFullI(&sdp->oqueue); - osalSysUnlock(); - - return b; -} - -/** - * @brief Direct input check on a @p SerialDriver. - * @note This function bypasses the indirect access to the channel and - * checks directly the input queue. This is faster but cannot - * be used to check different channels implementations. - * - * @param[in] sdp pointer to a @p SerialDriver structure - * @return The queue status. - * @retval false if the next write operation would not block. - * @retval true if the next write operation would block. - * - * @deprecated - * - * @api - */ -bool sdGetWouldBlock(SerialDriver *sdp) { - bool b; - - osalSysLock(); - b = iqIsEmptyI(&sdp->iqueue); - osalSysUnlock(); - - return b; -} - -#endif /* HAL_USE_SERIAL == TRUE */ - -/** @} */ diff --git a/os/hal/src/serial_usb.c b/os/hal/src/serial_usb.c deleted file mode 100644 index 9c21f7b56..000000000 --- a/os/hal/src/serial_usb.c +++ /dev/null @@ -1,502 +0,0 @@ -/* - ChibiOS - Copyright (C) 2006..2016 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 serial_usb.c - * @brief Serial over USB Driver code. - * - * @addtogroup SERIAL_USB - * @{ - */ - -#include "hal.h" - -#if (HAL_USE_SERIAL_USB == TRUE) || defined(__DOXYGEN__) - -/*===========================================================================*/ -/* Driver local definitions. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver exported variables. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver local variables and types. */ -/*===========================================================================*/ - -/* - * Current Line Coding. - */ -static cdc_linecoding_t linecoding = { - {0x00, 0x96, 0x00, 0x00}, /* 38400. */ - LC_STOP_1, LC_PARITY_NONE, 8 -}; - -/*===========================================================================*/ -/* Driver local functions. */ -/*===========================================================================*/ - -/* - * Interface implementation. - */ - -static size_t write(void *ip, const uint8_t *bp, size_t n) { - - if (usbGetDriverStateI(((SerialUSBDriver *)ip)->config->usbp) != USB_ACTIVE) { - return 0; - } - - return obqWriteTimeout(&((SerialUSBDriver *)ip)->obqueue, bp, - n, TIME_INFINITE); -} - -static size_t read(void *ip, uint8_t *bp, size_t n) { - - if (usbGetDriverStateI(((SerialUSBDriver *)ip)->config->usbp) != USB_ACTIVE) { - return 0; - } - - return ibqReadTimeout(&((SerialUSBDriver *)ip)->ibqueue, bp, - n, TIME_INFINITE); -} - -static msg_t put(void *ip, uint8_t b) { - - if (usbGetDriverStateI(((SerialUSBDriver *)ip)->config->usbp) != USB_ACTIVE) { - return MSG_RESET; - } - - return obqPutTimeout(&((SerialUSBDriver *)ip)->obqueue, b, TIME_INFINITE); -} - -static msg_t get(void *ip) { - - if (usbGetDriverStateI(((SerialUSBDriver *)ip)->config->usbp) != USB_ACTIVE) { - return MSG_RESET; - } - - return ibqGetTimeout(&((SerialUSBDriver *)ip)->ibqueue, TIME_INFINITE); -} - -static msg_t putt(void *ip, uint8_t b, systime_t timeout) { - - if (usbGetDriverStateI(((SerialUSBDriver *)ip)->config->usbp) != USB_ACTIVE) { - return MSG_RESET; - } - - return obqPutTimeout(&((SerialUSBDriver *)ip)->obqueue, b, timeout); -} - -static msg_t gett(void *ip, systime_t timeout) { - - if (usbGetDriverStateI(((SerialUSBDriver *)ip)->config->usbp) != USB_ACTIVE) { - return MSG_RESET; - } - - return ibqGetTimeout(&((SerialUSBDriver *)ip)->ibqueue, timeout); -} - -static size_t writet(void *ip, const uint8_t *bp, size_t n, systime_t timeout) { - - if (usbGetDriverStateI(((SerialUSBDriver *)ip)->config->usbp) != USB_ACTIVE) { - return 0; - } - - return obqWriteTimeout(&((SerialUSBDriver *)ip)->obqueue, bp, n, timeout); -} - -static size_t readt(void *ip, uint8_t *bp, size_t n, systime_t timeout) { - - if (usbGetDriverStateI(((SerialUSBDriver *)ip)->config->usbp) != USB_ACTIVE) { - return 0; - } - - return ibqReadTimeout(&((SerialUSBDriver *)ip)->ibqueue, bp, n, timeout); -} - -static const struct SerialUSBDriverVMT vmt = { - write, read, put, get, - putt, gett, writet, readt -}; - -/** - * @brief Notification of empty buffer released into the input buffers queue. - * - * @param[in] bqp the buffers queue pointer. - */ -static void ibnotify(io_buffers_queue_t *bqp) { - SerialUSBDriver *sdup = bqGetLinkX(bqp); - - /* If the USB driver is not in the appropriate state then transactions - must not be started.*/ - if ((usbGetDriverStateI(sdup->config->usbp) != USB_ACTIVE) || - (sdup->state != SDU_READY)) { - return; - } - - /* Checking if there is already a transaction ongoing on the endpoint.*/ - if (!usbGetReceiveStatusI(sdup->config->usbp, sdup->config->bulk_out)) { - /* Trying to get a free buffer.*/ - uint8_t *buf = ibqGetEmptyBufferI(&sdup->ibqueue); - if (buf != NULL) { - /* Buffer found, starting a new transaction.*/ - usbStartReceiveI(sdup->config->usbp, sdup->config->bulk_out, - buf, SERIAL_USB_BUFFERS_SIZE); - } - } -} - -/** - * @brief Notification of filled buffer inserted into the output buffers queue. - * - * @param[in] bqp the buffers queue pointer. - */ -static void obnotify(io_buffers_queue_t *bqp) { - size_t n; - SerialUSBDriver *sdup = bqGetLinkX(bqp); - - /* If the USB driver is not in the appropriate state then transactions - must not be started.*/ - if ((usbGetDriverStateI(sdup->config->usbp) != USB_ACTIVE) || - (sdup->state != SDU_READY)) { - return; - } - - /* Checking if there is already a transaction ongoing on the endpoint.*/ - if (!usbGetTransmitStatusI(sdup->config->usbp, sdup->config->bulk_in)) { - /* Trying to get a full buffer.*/ - uint8_t *buf = obqGetFullBufferI(&sdup->obqueue, &n); - if (buf != NULL) { - /* Buffer found, starting a new transaction.*/ - usbStartTransmitI(sdup->config->usbp, sdup->config->bulk_in, buf, n); - } - } -} - -/*===========================================================================*/ -/* Driver exported functions. */ -/*===========================================================================*/ - -/** - * @brief Serial Driver initialization. - * @note This function is implicitly invoked by @p halInit(), there is - * no need to explicitly initialize the driver. - * - * @init - */ -void sduInit(void) { -} - -/** - * @brief Initializes a generic full duplex driver object. - * @details The HW dependent part of the initialization has to be performed - * outside, usually in the hardware initialization code. - * - * @param[out] sdup pointer to a @p SerialUSBDriver structure - * - * @init - */ -void sduObjectInit(SerialUSBDriver *sdup) { - - sdup->vmt = &vmt; - osalEventObjectInit(&sdup->event); - sdup->state = SDU_STOP; - ibqObjectInit(&sdup->ibqueue, sdup->ib, - SERIAL_USB_BUFFERS_SIZE, SERIAL_USB_BUFFERS_NUMBER, - ibnotify, sdup); - obqObjectInit(&sdup->obqueue, sdup->ob, - SERIAL_USB_BUFFERS_SIZE, SERIAL_USB_BUFFERS_NUMBER, - obnotify, sdup); -} - -/** - * @brief Configures and starts the driver. - * - * @param[in] sdup pointer to a @p SerialUSBDriver object - * @param[in] config the serial over USB driver configuration - * - * @api - */ -void sduStart(SerialUSBDriver *sdup, const SerialUSBConfig *config) { - USBDriver *usbp = config->usbp; - - osalDbgCheck(sdup != NULL); - - osalSysLock(); - osalDbgAssert((sdup->state == SDU_STOP) || (sdup->state == SDU_READY), - "invalid state"); - usbp->in_params[config->bulk_in - 1U] = sdup; - usbp->out_params[config->bulk_out - 1U] = sdup; - if (config->int_in > 0U) { - usbp->in_params[config->int_in - 1U] = sdup; - } - sdup->config = config; - sdup->state = SDU_READY; - osalSysUnlock(); -} - -/** - * @brief Stops the driver. - * @details Any thread waiting on the driver's queues will be awakened with - * the message @p MSG_RESET. - * - * @param[in] sdup pointer to a @p SerialUSBDriver object - * - * @api - */ -void sduStop(SerialUSBDriver *sdup) { - USBDriver *usbp = sdup->config->usbp; - - osalDbgCheck(sdup != NULL); - - osalSysLock(); - osalDbgAssert((sdup->state == SDU_STOP) || (sdup->state == SDU_READY), - "invalid state"); - - /* Driver in stopped state.*/ - usbp->in_params[sdup->config->bulk_in - 1U] = NULL; - usbp->out_params[sdup->config->bulk_out - 1U] = NULL; - if (sdup->config->int_in > 0U) { - usbp->in_params[sdup->config->int_in - 1U] = NULL; - } - sdup->state = SDU_STOP; - - /* Enforces a disconnection.*/ - sduDisconnectI(sdup); - osalOsRescheduleS(); - osalSysUnlock(); -} - -/** - * @brief USB device disconnection handler. - * @note If this function is not called from an ISR then an explicit call - * to @p osalOsRescheduleS() in necessary afterward. - * - * @param[in] sdup pointer to a @p SerialUSBDriver object - * - * @iclass - */ -void sduDisconnectI(SerialUSBDriver *sdup) { - - /* Queues reset in order to signal the driver stop to the application.*/ - chnAddFlagsI(sdup, CHN_DISCONNECTED); - ibqResetI(&sdup->ibqueue); - obqResetI(&sdup->obqueue); -} - -/** - * @brief USB device configured handler. - * - * @param[in] sdup pointer to a @p SerialUSBDriver object - * - * @iclass - */ -void sduConfigureHookI(SerialUSBDriver *sdup) { - uint8_t *buf; - - ibqResetI(&sdup->ibqueue); - obqResetI(&sdup->obqueue); - chnAddFlagsI(sdup, CHN_CONNECTED); - - /* Starts the first OUT transaction immediately.*/ - buf = ibqGetEmptyBufferI(&sdup->ibqueue); - - osalDbgAssert(buf != NULL, "no free buffer"); - - usbStartReceiveI(sdup->config->usbp, sdup->config->bulk_out, - buf, SERIAL_USB_BUFFERS_SIZE); -} - -/** - * @brief Default requests hook. - * @details Applications wanting to use the Serial over USB driver can use - * this function as requests hook in the USB configuration. - * The following requests are emulated: - * - CDC_GET_LINE_CODING. - * - CDC_SET_LINE_CODING. - * - CDC_SET_CONTROL_LINE_STATE. - * . - * - * @param[in] usbp pointer to the @p USBDriver object - * @return The hook status. - * @retval true Message handled internally. - * @retval false Message not handled. - */ -bool sduRequestsHook(USBDriver *usbp) { - - if ((usbp->setup[0] & USB_RTYPE_TYPE_MASK) == USB_RTYPE_TYPE_CLASS) { - switch (usbp->setup[1]) { - case CDC_GET_LINE_CODING: - usbSetupTransfer(usbp, (uint8_t *)&linecoding, sizeof(linecoding), NULL); - return true; - case CDC_SET_LINE_CODING: - usbSetupTransfer(usbp, (uint8_t *)&linecoding, sizeof(linecoding), NULL); - return true; - case CDC_SET_CONTROL_LINE_STATE: - /* Nothing to do, there are no control lines.*/ - usbSetupTransfer(usbp, NULL, 0, NULL); - return true; - default: - return false; - } - } - return false; -} - -/** - * @brief SOF handler. - * @details The SOF interrupt is used for automatic flushing of incomplete - * buffers pending in the output queue. - * - * @param[in] sdup pointer to a @p SerialUSBDriver object - * - * @iclass - */ -void sduSOFHookI(SerialUSBDriver *sdup) { - - /* If the USB driver is not in the appropriate state then transactions - must not be started.*/ - if ((usbGetDriverStateI(sdup->config->usbp) != USB_ACTIVE) || - (sdup->state != SDU_READY)) { - return; - } - - /* If there is already a transaction ongoing then another one cannot be - started.*/ - if (usbGetTransmitStatusI(sdup->config->usbp, sdup->config->bulk_in)) { - return; - } - - /* Checking if there only a buffer partially filled, if so then it is - enforced in the queue and transmitted.*/ - if (obqTryFlushI(&sdup->obqueue)) { - size_t n; - uint8_t *buf = obqGetFullBufferI(&sdup->obqueue, &n); - - osalDbgAssert(buf != NULL, "queue is empty"); - - usbStartTransmitI(sdup->config->usbp, sdup->config->bulk_in, buf, n); - } -} - -/** - * @brief Default data transmitted callback. - * @details The application must use this function as callback for the IN - * data endpoint. - * - * @param[in] usbp pointer to the @p USBDriver object - * @param[in] ep IN endpoint number - */ -void sduDataTransmitted(USBDriver *usbp, usbep_t ep) { - uint8_t *buf; - size_t n; - SerialUSBDriver *sdup = usbp->in_params[ep - 1U]; - - if (sdup == NULL) { - return; - } - - osalSysLockFromISR(); - - /* Signaling that space is available in the output queue.*/ - chnAddFlagsI(sdup, CHN_OUTPUT_EMPTY); - - /* Freeing the buffer just transmitted, if it was not a zero size packet.*/ - if (usbp->epc[ep]->in_state->txsize > 0U) { - obqReleaseEmptyBufferI(&sdup->obqueue); - } - - /* Checking if there is a buffer ready for transmission.*/ - buf = obqGetFullBufferI(&sdup->obqueue, &n); - - if (buf != NULL) { - /* The endpoint cannot be busy, we are in the context of the callback, - so it is safe to transmit without a check.*/ - usbStartTransmitI(usbp, ep, buf, n); - } - else if ((usbp->epc[ep]->in_state->txsize > 0U) && - ((usbp->epc[ep]->in_state->txsize & - ((size_t)usbp->epc[ep]->in_maxsize - 1U)) == 0U)) { - /* Transmit zero sized packet in case the last one has maximum allowed - size. Otherwise the recipient may expect more data coming soon and - not return buffered data to app. See section 5.8.3 Bulk Transfer - Packet Size Constraints of the USB Specification document.*/ - usbStartTransmitI(usbp, ep, usbp->setup, 0); - - } - else { - /* Nothing to transmit.*/ - } - - osalSysUnlockFromISR(); -} - -/** - * @brief Default data received callback. - * @details The application must use this function as callback for the OUT - * data endpoint. - * - * @param[in] usbp pointer to the @p USBDriver object - * @param[in] ep OUT endpoint number - */ -void sduDataReceived(USBDriver *usbp, usbep_t ep) { - uint8_t *buf; - SerialUSBDriver *sdup = usbp->out_params[ep - 1U]; - - if (sdup == NULL) { - return; - } - - osalSysLockFromISR(); - - /* Signaling that data is available in the input queue.*/ - chnAddFlagsI(sdup, CHN_INPUT_AVAILABLE); - - /* Posting the filled buffer in the queue.*/ - ibqPostFullBufferI(&sdup->ibqueue, - usbGetReceiveTransactionSizeX(sdup->config->usbp, - sdup->config->bulk_out)); - - /* The endpoint cannot be busy, we are in the context of the callback, - so a packet is in the buffer for sure. Trying to get a free buffer - for the next transaction.*/ - buf = ibqGetEmptyBufferI(&sdup->ibqueue); - if (buf != NULL) { - /* Buffer found, starting a new transaction.*/ - usbStartReceiveI(sdup->config->usbp, sdup->config->bulk_out, - buf, SERIAL_USB_BUFFERS_SIZE); - } - osalSysUnlockFromISR(); -} - -/** - * @brief Default data received callback. - * @details The application must use this function as callback for the IN - * interrupt endpoint. - * - * @param[in] usbp pointer to the @p USBDriver object - * @param[in] ep endpoint number - */ -void sduInterruptTransmitted(USBDriver *usbp, usbep_t ep) { - - (void)usbp; - (void)ep; -} - -#endif /* HAL_USE_SERIAL_USB == TRUE */ - -/** @} */ diff --git a/os/hal/src/spi.c b/os/hal/src/spi.c deleted file mode 100644 index 90907e8f4..000000000 --- a/os/hal/src/spi.c +++ /dev/null @@ -1,416 +0,0 @@ -/* - ChibiOS - Copyright (C) 2006..2016 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 spi.c - * @brief SPI Driver code. - * - * @addtogroup SPI - * @{ - */ - -#include "hal.h" - -#if (HAL_USE_SPI == TRUE) || defined(__DOXYGEN__) - -/*===========================================================================*/ -/* Driver local definitions. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver exported variables. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver local variables and types. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver local functions. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver exported functions. */ -/*===========================================================================*/ - -/** - * @brief SPI Driver initialization. - * @note This function is implicitly invoked by @p halInit(), there is - * no need to explicitly initialize the driver. - * - * @init - */ -void spiInit(void) { - - spi_lld_init(); -} - -/** - * @brief Initializes the standard part of a @p SPIDriver structure. - * - * @param[out] spip pointer to the @p SPIDriver object - * - * @init - */ -void spiObjectInit(SPIDriver *spip) { - - spip->state = SPI_STOP; - spip->config = NULL; -#if SPI_USE_WAIT == TRUE - spip->thread = NULL; -#endif -#if SPI_USE_MUTUAL_EXCLUSION == TRUE - osalMutexObjectInit(&spip->mutex); -#endif -#if defined(SPI_DRIVER_EXT_INIT_HOOK) - SPI_DRIVER_EXT_INIT_HOOK(spip); -#endif -} - -/** - * @brief Configures and activates the SPI peripheral. - * - * @param[in] spip pointer to the @p SPIDriver object - * @param[in] config pointer to the @p SPIConfig object - * - * @api - */ -void spiStart(SPIDriver *spip, const SPIConfig *config) { - - osalDbgCheck((spip != NULL) && (config != NULL)); - - osalSysLock(); - osalDbgAssert((spip->state == SPI_STOP) || (spip->state == SPI_READY), - "invalid state"); - spip->config = config; - spi_lld_start(spip); - spip->state = SPI_READY; - osalSysUnlock(); -} - -/** - * @brief Deactivates the SPI peripheral. - * @note Deactivating the peripheral also enforces a release of the slave - * select line. - * - * @param[in] spip pointer to the @p SPIDriver object - * - * @api - */ -void spiStop(SPIDriver *spip) { - - osalDbgCheck(spip != NULL); - - osalSysLock(); - osalDbgAssert((spip->state == SPI_STOP) || (spip->state == SPI_READY), - "invalid state"); - spi_lld_stop(spip); - spip->state = SPI_STOP; - osalSysUnlock(); -} - -/** - * @brief Asserts the slave select signal and prepares for transfers. - * - * @param[in] spip pointer to the @p SPIDriver object - * - * @api - */ -void spiSelect(SPIDriver *spip) { - - osalDbgCheck(spip != NULL); - - osalSysLock(); - osalDbgAssert(spip->state == SPI_READY, "not ready"); - spiSelectI(spip); - osalSysUnlock(); -} - -/** - * @brief Deasserts the slave select signal. - * @details The previously selected peripheral is unselected. - * - * @param[in] spip pointer to the @p SPIDriver object - * - * @api - */ -void spiUnselect(SPIDriver *spip) { - - osalDbgCheck(spip != NULL); - - osalSysLock(); - osalDbgAssert(spip->state == SPI_READY, "not ready"); - spiUnselectI(spip); - osalSysUnlock(); -} - -/** - * @brief Ignores data on the SPI bus. - * @details This asynchronous function starts the transmission of a series of - * idle words on the SPI bus and ignores the received data. - * @pre A slave must have been selected using @p spiSelect() or - * @p spiSelectI(). - * @post At the end of the operation the configured callback is invoked. - * - * @param[in] spip pointer to the @p SPIDriver object - * @param[in] n number of words to be ignored - * - * @api - */ -void spiStartIgnore(SPIDriver *spip, size_t n) { - - osalDbgCheck((spip != NULL) && (n > 0U)); - - osalSysLock(); - osalDbgAssert(spip->state == SPI_READY, "not ready"); - spiStartIgnoreI(spip, n); - osalSysUnlock(); -} - -/** - * @brief Exchanges data on the SPI bus. - * @details This asynchronous function starts a simultaneous transmit/receive - * operation. - * @pre A slave must have been selected using @p spiSelect() or - * @p spiSelectI(). - * @post At the end of the operation the configured callback is invoked. - * @note The buffers are organized as uint8_t arrays for data sizes below - * or equal to 8 bits else it is organized as uint16_t arrays. - * - * @param[in] spip pointer to the @p SPIDriver object - * @param[in] n number of words to be exchanged - * @param[in] txbuf the pointer to the transmit buffer - * @param[out] rxbuf the pointer to the receive buffer - * - * @api - */ -void spiStartExchange(SPIDriver *spip, size_t n, - const void *txbuf, void *rxbuf) { - - osalDbgCheck((spip != NULL) && (n > 0U) && - (rxbuf != NULL) && (txbuf != NULL)); - - osalSysLock(); - osalDbgAssert(spip->state == SPI_READY, "not ready"); - spiStartExchangeI(spip, n, txbuf, rxbuf); - osalSysUnlock(); -} - -/** - * @brief Sends data over the SPI bus. - * @details This asynchronous function starts a transmit operation. - * @pre A slave must have been selected using @p spiSelect() or - * @p spiSelectI(). - * @post At the end of the operation the configured callback is invoked. - * @note The buffers are organized as uint8_t arrays for data sizes below - * or equal to 8 bits else it is organized as uint16_t arrays. - * - * @param[in] spip pointer to the @p SPIDriver object - * @param[in] n number of words to send - * @param[in] txbuf the pointer to the transmit buffer - * - * @api - */ -void spiStartSend(SPIDriver *spip, size_t n, const void *txbuf) { - - osalDbgCheck((spip != NULL) && (n > 0U) && (txbuf != NULL)); - - osalSysLock(); - osalDbgAssert(spip->state == SPI_READY, "not ready"); - spiStartSendI(spip, n, txbuf); - osalSysUnlock(); -} - -/** - * @brief Receives data from the SPI bus. - * @details This asynchronous function starts a receive operation. - * @pre A slave must have been selected using @p spiSelect() or - * @p spiSelectI(). - * @post At the end of the operation the configured callback is invoked. - * @note The buffers are organized as uint8_t arrays for data sizes below - * or equal to 8 bits else it is organized as uint16_t arrays. - * - * @param[in] spip pointer to the @p SPIDriver object - * @param[in] n number of words to receive - * @param[out] rxbuf the pointer to the receive buffer - * - * @api - */ -void spiStartReceive(SPIDriver *spip, size_t n, void *rxbuf) { - - osalDbgCheck((spip != NULL) && (n > 0U) && (rxbuf != NULL)); - - osalSysLock(); - osalDbgAssert(spip->state == SPI_READY, "not ready"); - spiStartReceiveI(spip, n, rxbuf); - osalSysUnlock(); -} - -#if (SPI_USE_WAIT == TRUE) || defined(__DOXYGEN__) -/** - * @brief Ignores data on the SPI bus. - * @details This synchronous function performs the transmission of a series of - * idle words on the SPI bus and ignores the received data. - * @pre In order to use this function the option @p SPI_USE_WAIT must be - * enabled. - * @pre In order to use this function the driver must have been configured - * without callbacks (@p end_cb = @p NULL). - * - * @param[in] spip pointer to the @p SPIDriver object - * @param[in] n number of words to be ignored - * - * @api - */ -void spiIgnore(SPIDriver *spip, size_t n) { - - osalDbgCheck((spip != NULL) && (n > 0U)); - - osalSysLock(); - osalDbgAssert(spip->state == SPI_READY, "not ready"); - osalDbgAssert(spip->config->end_cb == NULL, "has callback"); - spiStartIgnoreI(spip, n); - (void) osalThreadSuspendS(&spip->thread); - osalSysUnlock(); -} - -/** - * @brief Exchanges data on the SPI bus. - * @details This synchronous function performs a simultaneous transmit/receive - * operation. - * @pre In order to use this function the option @p SPI_USE_WAIT must be - * enabled. - * @pre In order to use this function the driver must have been configured - * without callbacks (@p end_cb = @p NULL). - * @note The buffers are organized as uint8_t arrays for data sizes below - * or equal to 8 bits else it is organized as uint16_t arrays. - * - * @param[in] spip pointer to the @p SPIDriver object - * @param[in] n number of words to be exchanged - * @param[in] txbuf the pointer to the transmit buffer - * @param[out] rxbuf the pointer to the receive buffer - * - * @api - */ -void spiExchange(SPIDriver *spip, size_t n, - const void *txbuf, void *rxbuf) { - - osalDbgCheck((spip != NULL) && (n > 0U) && - (rxbuf != NULL) && (txbuf != NULL)); - - osalSysLock(); - osalDbgAssert(spip->state == SPI_READY, "not ready"); - osalDbgAssert(spip->config->end_cb == NULL, "has callback"); - spiStartExchangeI(spip, n, txbuf, rxbuf); - (void) osalThreadSuspendS(&spip->thread); - osalSysUnlock(); -} - -/** - * @brief Sends data over the SPI bus. - * @details This synchronous function performs a transmit operation. - * @pre In order to use this function the option @p SPI_USE_WAIT must be - * enabled. - * @pre In order to use this function the driver must have been configured - * without callbacks (@p end_cb = @p NULL). - * @note The buffers are organized as uint8_t arrays for data sizes below - * or equal to 8 bits else it is organized as uint16_t arrays. - * - * @param[in] spip pointer to the @p SPIDriver object - * @param[in] n number of words to send - * @param[in] txbuf the pointer to the transmit buffer - * - * @api - */ -void spiSend(SPIDriver *spip, size_t n, const void *txbuf) { - - osalDbgCheck((spip != NULL) && (n > 0U) && (txbuf != NULL)); - - osalSysLock(); - osalDbgAssert(spip->state == SPI_READY, "not ready"); - osalDbgAssert(spip->config->end_cb == NULL, "has callback"); - spiStartSendI(spip, n, txbuf); - (void) osalThreadSuspendS(&spip->thread); - osalSysUnlock(); -} - -/** - * @brief Receives data from the SPI bus. - * @details This synchronous function performs a receive operation. - * @pre In order to use this function the option @p SPI_USE_WAIT must be - * enabled. - * @pre In order to use this function the driver must have been configured - * without callbacks (@p end_cb = @p NULL). - * @note The buffers are organized as uint8_t arrays for data sizes below - * or equal to 8 bits else it is organized as uint16_t arrays. - * - * @param[in] spip pointer to the @p SPIDriver object - * @param[in] n number of words to receive - * @param[out] rxbuf the pointer to the receive buffer - * - * @api - */ -void spiReceive(SPIDriver *spip, size_t n, void *rxbuf) { - - osalDbgCheck((spip != NULL) && (n > 0U) && (rxbuf != NULL)); - - osalSysLock(); - osalDbgAssert(spip->state == SPI_READY, "not ready"); - osalDbgAssert(spip->config->end_cb == NULL, "has callback"); - spiStartReceiveI(spip, n, rxbuf); - (void) osalThreadSuspendS(&spip->thread); - osalSysUnlock(); -} -#endif /* SPI_USE_WAIT == TRUE */ - -#if (SPI_USE_MUTUAL_EXCLUSION == TRUE) || defined(__DOXYGEN__) -/** - * @brief Gains exclusive access to the SPI bus. - * @details This function tries to gain ownership to the SPI bus, if the bus - * is already being used then the invoking thread is queued. - * @pre In order to use this function the option @p SPI_USE_MUTUAL_EXCLUSION - * must be enabled. - * - * @param[in] spip pointer to the @p SPIDriver object - * - * @api - */ -void spiAcquireBus(SPIDriver *spip) { - - osalDbgCheck(spip != NULL); - - osalMutexLock(&spip->mutex); -} - -/** - * @brief Releases exclusive access to the SPI bus. - * @pre In order to use this function the option @p SPI_USE_MUTUAL_EXCLUSION - * must be enabled. - * - * @param[in] spip pointer to the @p SPIDriver object - * - * @api - */ -void spiReleaseBus(SPIDriver *spip) { - - osalDbgCheck(spip != NULL); - - osalMutexUnlock(&spip->mutex); -} -#endif /* SPI_USE_MUTUAL_EXCLUSION == TRUE */ - -#endif /* HAL_USE_SPI == TRUE */ - -/** @} */ diff --git a/os/hal/src/st.c b/os/hal/src/st.c deleted file mode 100644 index cf654f882..000000000 --- a/os/hal/src/st.c +++ /dev/null @@ -1,130 +0,0 @@ -/* - ChibiOS - Copyright (C) 2006..2016 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 st.c - * @brief ST Driver code. - * - * @addtogroup ST - * @{ - */ - -#include "hal.h" - -#if (OSAL_ST_MODE != OSAL_ST_MODE_NONE) || defined(__DOXYGEN__) - -/*===========================================================================*/ -/* Driver local definitions. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver exported variables. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver local types. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver local variables. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver local functions. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver exported functions. */ -/*===========================================================================*/ - -/** - * @brief ST Driver initialization. - * @note This function is implicitly invoked by @p halInit(), there is - * no need to explicitly initialize the driver. - * - * @init - */ -void stInit(void) { - - st_lld_init(); -} - - -/** - * @brief Starts the alarm. - * @note Makes sure that no spurious alarms are triggered after - * this call. - * @note This functionality is only available in free running mode, the - * behavior in periodic mode is undefined. - * - * @param[in] abstime the time to be set for the first alarm - * - * @api - */ -void stStartAlarm(systime_t abstime) { - - osalDbgAssert(stIsAlarmActive() == false, "already active"); - - st_lld_start_alarm(abstime); -} - -/** - * @brief Stops the alarm interrupt. - * @note This functionality is only available in free running mode, the - * behavior in periodic mode is undefined. - * - * @api - */ -void stStopAlarm(void) { - - st_lld_stop_alarm(); -} - -/** - * @brief Sets the alarm time. - * @note This functionality is only available in free running mode, the - * behavior in periodic mode is undefined. - * - * @param[in] abstime the time to be set for the next alarm - * - * @api - */ -void stSetAlarm(systime_t abstime) { - - osalDbgAssert(stIsAlarmActive() != false, "not active"); - - st_lld_set_alarm(abstime); -} - -/** - * @brief Returns the current alarm time. - * @note This functionality is only available in free running mode, the - * behavior in periodic mode is undefined. - * - * @return The currently set alarm time. - * - * @api - */ -systime_t stGetAlarm(void) { - - osalDbgAssert(stIsAlarmActive() != false, "not active"); - - return st_lld_get_alarm(); -} - -#endif /* OSAL_ST_MODE != OSAL_ST_MODE_NONE */ - -/** @} */ diff --git a/os/hal/src/uart.c b/os/hal/src/uart.c deleted file mode 100644 index 7bf0e5d74..000000000 --- a/os/hal/src/uart.c +++ /dev/null @@ -1,515 +0,0 @@ -/* - ChibiOS - Copyright (C) 2006..2016 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 uart.c - * @brief UART Driver code. - * - * @addtogroup UART - * @{ - */ - -#include "hal.h" - -#if (HAL_USE_UART == TRUE) || defined(__DOXYGEN__) - -/*===========================================================================*/ -/* Driver local definitions. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver exported variables. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver local variables and types. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver local functions. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver exported functions. */ -/*===========================================================================*/ - -/** - * @brief UART Driver initialization. - * @note This function is implicitly invoked by @p halInit(), there is - * no need to explicitly initialize the driver. - * - * @init - */ -void uartInit(void) { - - uart_lld_init(); -} - -/** - * @brief Initializes the standard part of a @p UARTDriver structure. - * - * @param[out] uartp pointer to the @p UARTDriver object - * - * @init - */ -void uartObjectInit(UARTDriver *uartp) { - - uartp->state = UART_STOP; - uartp->txstate = UART_TX_IDLE; - uartp->rxstate = UART_RX_IDLE; - uartp->config = NULL; -#if UART_USE_WAIT == TRUE - uartp->early = false; - uartp->threadrx = NULL; - uartp->threadtx = NULL; -#endif /* UART_USE_WAIT */ -#if UART_USE_MUTUAL_EXCLUSION == TRUE - osalMutexObjectInit(&uartp->mutex); -#endif /* UART_USE_MUTUAL_EXCLUSION */ - - /* Optional, user-defined initializer.*/ -#if defined(UART_DRIVER_EXT_INIT_HOOK) - UART_DRIVER_EXT_INIT_HOOK(uartp); -#endif -} - -/** - * @brief Configures and activates the UART peripheral. - * - * @param[in] uartp pointer to the @p UARTDriver object - * @param[in] config pointer to the @p UARTConfig object - * - * @api - */ -void uartStart(UARTDriver *uartp, const UARTConfig *config) { - - osalDbgCheck((uartp != NULL) && (config != NULL)); - - osalSysLock(); - osalDbgAssert((uartp->state == UART_STOP) || (uartp->state == UART_READY), - "invalid state"); - - uartp->config = config; - uart_lld_start(uartp); - uartp->state = UART_READY; - osalSysUnlock(); -} - -/** - * @brief Deactivates the UART peripheral. - * - * @param[in] uartp pointer to the @p UARTDriver object - * - * @api - */ -void uartStop(UARTDriver *uartp) { - - osalDbgCheck(uartp != NULL); - - osalSysLock(); - osalDbgAssert((uartp->state == UART_STOP) || (uartp->state == UART_READY), - "invalid state"); - - uart_lld_stop(uartp); - uartp->state = UART_STOP; - uartp->txstate = UART_TX_IDLE; - uartp->rxstate = UART_RX_IDLE; - osalSysUnlock(); -} - -/** - * @brief Starts a transmission on the UART peripheral. - * @note The buffers are organized as uint8_t arrays for data sizes below - * or equal to 8 bits else it is organized as uint16_t arrays. - * - * @param[in] uartp pointer to the @p UARTDriver object - * @param[in] n number of data frames to send - * @param[in] txbuf the pointer to the transmit buffer - * - * @api - */ -void uartStartSend(UARTDriver *uartp, size_t n, const void *txbuf) { - - osalDbgCheck((uartp != NULL) && (n > 0U) && (txbuf != NULL)); - - osalSysLock(); - osalDbgAssert(uartp->state == UART_READY, "is active"); - osalDbgAssert(uartp->txstate != UART_TX_ACTIVE, "tx active"); - - uart_lld_start_send(uartp, n, txbuf); - uartp->txstate = UART_TX_ACTIVE; - osalSysUnlock(); -} - -/** - * @brief Starts a transmission on the UART peripheral. - * @note The buffers are organized as uint8_t arrays for data sizes below - * or equal to 8 bits else it is organized as uint16_t arrays. - * @note This function has to be invoked from a lock zone. - * - * @param[in] uartp pointer to the @p UARTDriver object - * @param[in] n number of data frames to send - * @param[in] txbuf the pointer to the transmit buffer - * - * @iclass - */ -void uartStartSendI(UARTDriver *uartp, size_t n, const void *txbuf) { - - osalDbgCheckClassI(); - osalDbgCheck((uartp != NULL) && (n > 0U) && (txbuf != NULL)); - osalDbgAssert(uartp->state == UART_READY, "is active"); - osalDbgAssert(uartp->txstate != UART_TX_ACTIVE, "tx active"); - - uart_lld_start_send(uartp, n, txbuf); - uartp->txstate = UART_TX_ACTIVE; -} - -/** - * @brief Stops any ongoing transmission. - * @note Stopping a transmission also suppresses the transmission callbacks. - * - * @param[in] uartp pointer to the @p UARTDriver object - * - * @return The number of data frames not transmitted by the - * stopped transmit operation. - * @retval 0 There was no transmit operation in progress. - * - * @api - */ -size_t uartStopSend(UARTDriver *uartp) { - size_t n; - - osalDbgCheck(uartp != NULL); - - osalSysLock(); - osalDbgAssert(uartp->state == UART_READY, "not active"); - - if (uartp->txstate == UART_TX_ACTIVE) { - n = uart_lld_stop_send(uartp); - uartp->txstate = UART_TX_IDLE; - } - else { - n = 0; - } - osalSysUnlock(); - - return n; -} - -/** - * @brief Stops any ongoing transmission. - * @note Stopping a transmission also suppresses the transmission callbacks. - * @note This function has to be invoked from a lock zone. - * - * @param[in] uartp pointer to the @p UARTDriver object - * - * @return The number of data frames not transmitted by the - * stopped transmit operation. - * @retval 0 There was no transmit operation in progress. - * - * @iclass - */ -size_t uartStopSendI(UARTDriver *uartp) { - - osalDbgCheckClassI(); - osalDbgCheck(uartp != NULL); - osalDbgAssert(uartp->state == UART_READY, "not active"); - - if (uartp->txstate == UART_TX_ACTIVE) { - size_t n = uart_lld_stop_send(uartp); - uartp->txstate = UART_TX_IDLE; - return n; - } - return 0; -} - -/** - * @brief Starts a receive operation on the UART peripheral. - * @note The buffers are organized as uint8_t arrays for data sizes below - * or equal to 8 bits else it is organized as uint16_t arrays. - * - * @param[in] uartp pointer to the @p UARTDriver object - * @param[in] n number of data frames to receive - * @param[in] rxbuf the pointer to the receive buffer - * - * @api - */ -void uartStartReceive(UARTDriver *uartp, size_t n, void *rxbuf) { - - osalDbgCheck((uartp != NULL) && (n > 0U) && (rxbuf != NULL)); - - osalSysLock(); - osalDbgAssert(uartp->state == UART_READY, "is active"); - osalDbgAssert(uartp->rxstate != UART_RX_ACTIVE, "rx active"); - - uart_lld_start_receive(uartp, n, rxbuf); - uartp->rxstate = UART_RX_ACTIVE; - osalSysUnlock(); -} - -/** - * @brief Starts a receive operation on the UART peripheral. - * @note The buffers are organized as uint8_t arrays for data sizes below - * or equal to 8 bits else it is organized as uint16_t arrays. - * @note This function has to be invoked from a lock zone. - * - * @param[in] uartp pointer to the @p UARTDriver object - * @param[in] n number of data frames to receive - * @param[out] rxbuf the pointer to the receive buffer - * - * @iclass - */ -void uartStartReceiveI(UARTDriver *uartp, size_t n, void *rxbuf) { - - osalDbgCheckClassI(); - osalDbgCheck((uartp != NULL) && (n > 0U) && (rxbuf != NULL)); - osalDbgAssert(uartp->state == UART_READY, "is active"); - osalDbgAssert(uartp->rxstate != UART_RX_ACTIVE, "rx active"); - - uart_lld_start_receive(uartp, n, rxbuf); - uartp->rxstate = UART_RX_ACTIVE; -} - -/** - * @brief Stops any ongoing receive operation. - * @note Stopping a receive operation also suppresses the receive callbacks. - * - * @param[in] uartp pointer to the @p UARTDriver object - * - * @return The number of data frames not received by the - * stopped receive operation. - * @retval 0 There was no receive operation in progress. - * - * @api - */ -size_t uartStopReceive(UARTDriver *uartp) { - size_t n; - - osalDbgCheck(uartp != NULL); - - osalSysLock(); - osalDbgAssert(uartp->state == UART_READY, "not active"); - - if (uartp->rxstate == UART_RX_ACTIVE) { - n = uart_lld_stop_receive(uartp); - uartp->rxstate = UART_RX_IDLE; - } - else { - n = 0; - } - osalSysUnlock(); - - return n; -} - -/** - * @brief Stops any ongoing receive operation. - * @note Stopping a receive operation also suppresses the receive callbacks. - * @note This function has to be invoked from a lock zone. - * - * @param[in] uartp pointer to the @p UARTDriver object - * - * @return The number of data frames not received by the - * stopped receive operation. - * @retval 0 There was no receive operation in progress. - * - * @iclass - */ -size_t uartStopReceiveI(UARTDriver *uartp) { - - osalDbgCheckClassI(); - osalDbgCheck(uartp != NULL); - osalDbgAssert(uartp->state == UART_READY, "not active"); - - if (uartp->rxstate == UART_RX_ACTIVE) { - size_t n = uart_lld_stop_receive(uartp); - uartp->rxstate = UART_RX_IDLE; - return n; - } - return 0; -} - -#if (UART_USE_WAIT == TRUE) || defined(__DOXYGEN__) -/** - * @brief Performs a transmission on the UART peripheral. - * @note The function returns when the specified number of frames have been - * sent to the UART or on timeout. - * @note The buffers are organized as uint8_t arrays for data sizes below - * or equal to 8 bits else it is organized as uint16_t arrays. - * - * @param[in] uartp pointer to the @p UARTDriver object - * @param[in,out] np number of data frames to transmit, on exit the number - * of frames actually transmitted - * @param[in] txbuf the pointer to the transmit buffer - * @param[in] timeout operation timeout - * @return The operation status. - * @retval MSG_OK if the operation completed successfully. - * @retval MSG_TIMEOUT if the operation timed out. - * - * @api - */ -msg_t uartSendTimeout(UARTDriver *uartp, size_t *np, - const void *txbuf, systime_t timeout) { - msg_t msg; - - osalDbgCheck((uartp != NULL) && (*np > 0U) && (txbuf != NULL)); - - osalSysLock(); - osalDbgAssert(uartp->state == UART_READY, "is active"); - osalDbgAssert(uartp->txstate != UART_TX_ACTIVE, "tx active"); - - /* Transmission start.*/ - uartp->early = true; - uart_lld_start_send(uartp, *np, txbuf); - uartp->txstate = UART_TX_ACTIVE; - - /* Waiting for result.*/ - msg = osalThreadSuspendTimeoutS(&uartp->threadtx, timeout); - if (msg != MSG_OK) { - *np = uartStopSendI(uartp); - } - osalSysUnlock(); - - return msg; -} - -/** - * @brief Performs a transmission on the UART peripheral. - * @note The function returns when the specified number of frames have been - * physically transmitted or on timeout. - * @note The buffers are organized as uint8_t arrays for data sizes below - * or equal to 8 bits else it is organized as uint16_t arrays. - * - * @param[in] uartp pointer to the @p UARTDriver object - * @param[in,out] np number of data frames to transmit, on exit the number - * of frames actually transmitted - * @param[in] txbuf the pointer to the transmit buffer - * @param[in] timeout operation timeout - * @return The operation status. - * @retval MSG_OK if the operation completed successfully. - * @retval MSG_TIMEOUT if the operation timed out. - * - * @api - */ -msg_t uartSendFullTimeout(UARTDriver *uartp, size_t *np, - const void *txbuf, systime_t timeout) { - msg_t msg; - - osalDbgCheck((uartp != NULL) && (*np > 0U) && (txbuf != NULL)); - - osalSysLock(); - osalDbgAssert(uartp->state == UART_READY, "is active"); - osalDbgAssert(uartp->txstate != UART_TX_ACTIVE, "tx active"); - - /* Transmission start.*/ - uartp->early = false; - uart_lld_start_send(uartp, *np, txbuf); - uartp->txstate = UART_TX_ACTIVE; - - /* Waiting for result.*/ - msg = osalThreadSuspendTimeoutS(&uartp->threadtx, timeout); - if (msg != MSG_OK) { - *np = uartStopSendI(uartp); - } - osalSysUnlock(); - - return msg; -} - -/** - * @brief Performs a receive operation on the UART peripheral. - * @note The function returns when the specified number of frames have been - * received or on error/timeout. - * @note The buffers are organized as uint8_t arrays for data sizes below - * or equal to 8 bits else it is organized as uint16_t arrays. - * - * @param[in] uartp pointer to the @p UARTDriver object - * @param[in,out] np number of data frames to receive, on exit the number - * of frames actually received - * @param[in] rxbuf the pointer to the receive buffer - * @param[in] timeout operation timeout - * - * @return The operation status. - * @retval MSG_OK if the operation completed successfully. - * @retval MSG_TIMEOUT if the operation timed out. - * @retval MSG_RESET in case of a receive error. - * - * @api - */ -msg_t uartReceiveTimeout(UARTDriver *uartp, size_t *np, - void *rxbuf, systime_t timeout) { - msg_t msg; - - osalDbgCheck((uartp != NULL) && (*np > 0U) && (rxbuf != NULL)); - - osalSysLock(); - osalDbgAssert(uartp->state == UART_READY, "is active"); - osalDbgAssert(uartp->rxstate != UART_RX_ACTIVE, "rx active"); - - /* Receive start.*/ - uart_lld_start_receive(uartp, *np, rxbuf); - uartp->rxstate = UART_RX_ACTIVE; - - /* Waiting for result.*/ - msg = osalThreadSuspendTimeoutS(&uartp->threadrx, timeout); - if (msg != MSG_OK) { - *np = uartStopReceiveI(uartp); - } - osalSysUnlock(); - - return msg; -} -#endif - -#if (UART_USE_MUTUAL_EXCLUSION == TRUE) || defined(__DOXYGEN__) -/** - * @brief Gains exclusive access to the UART bus. - * @details This function tries to gain ownership to the UART bus, if the bus - * is already being used then the invoking thread is queued. - * @pre In order to use this function the option @p UART_USE_MUTUAL_EXCLUSION - * must be enabled. - * - * @param[in] uartp pointer to the @p UARTDriver object - * - * @api - */ -void uartAcquireBus(UARTDriver *uartp) { - - osalDbgCheck(uartp != NULL); - - osalMutexLock(&uartp->mutex); -} - -/** - * @brief Releases exclusive access to the UART bus. - * @pre In order to use this function the option @p UART_USE_MUTUAL_EXCLUSION - * must be enabled. - * - * @param[in] uartp pointer to the @p UARTDriver object - * - * @api - */ -void uartReleaseBus(UARTDriver *uartp) { - - osalDbgCheck(uartp != NULL); - - osalMutexUnlock(&uartp->mutex); -} -#endif - -#endif /* HAL_USE_UART == TRUE */ - -/** @} */ diff --git a/os/hal/src/usb.c b/os/hal/src/usb.c deleted file mode 100644 index d9fbc091a..000000000 --- a/os/hal/src/usb.c +++ /dev/null @@ -1,950 +0,0 @@ -/* - ChibiOS - Copyright (C) 2006..2016 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 usb.c - * @brief USB Driver code. - * - * @addtogroup USB - * @{ - */ - -#include - -#include "hal.h" - -#if (HAL_USE_USB == TRUE) || defined(__DOXYGEN__) - -/*===========================================================================*/ -/* Driver local definitions. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver exported variables. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver local variables and types. */ -/*===========================================================================*/ - -static const uint8_t zero_status[] = {0x00, 0x00}; -static const uint8_t active_status[] ={0x00, 0x00}; -static const uint8_t halted_status[] = {0x01, 0x00}; - -/*===========================================================================*/ -/* Driver local functions. */ -/*===========================================================================*/ - -static uint16_t get_hword(uint8_t *p) { - uint16_t hw; - - hw = (uint16_t)*p++; - hw |= (uint16_t)*p << 8U; - return hw; -} - -/** - * @brief SET ADDRESS transaction callback. - * - * @param[in] usbp pointer to the @p USBDriver object - */ -static void set_address(USBDriver *usbp) { - - usbp->address = usbp->setup[2]; - usb_lld_set_address(usbp); - _usb_isr_invoke_event_cb(usbp, USB_EVENT_ADDRESS); - usbp->state = USB_SELECTED; -} - -/** - * @brief Standard requests handler. - * @details This is the standard requests default handler, most standard - * requests are handled here, the user can override the standard - * handling using the @p requests_hook_cb hook in the - * @p USBConfig structure. - * - * @param[in] usbp pointer to the @p USBDriver object - * @return The request handling exit code. - * @retval false Request not recognized by the handler or error. - * @retval true Request handled. - */ -static bool default_handler(USBDriver *usbp) { - const USBDescriptor *dp; - - /* Decoding the request.*/ - switch ((((uint32_t)usbp->setup[0] & (USB_RTYPE_RECIPIENT_MASK | - USB_RTYPE_TYPE_MASK)) | - ((uint32_t)usbp->setup[1] << 8U))) { - case (uint32_t)USB_RTYPE_RECIPIENT_DEVICE | ((uint32_t)USB_REQ_GET_STATUS << 8): - /* Just returns the current status word.*/ - usbSetupTransfer(usbp, (uint8_t *)&usbp->status, 2, NULL); - return true; - case (uint32_t)USB_RTYPE_RECIPIENT_DEVICE | ((uint32_t)USB_REQ_CLEAR_FEATURE << 8): - /* Only the DEVICE_REMOTE_WAKEUP is handled here, any other feature - number is handled as an error.*/ - if (usbp->setup[2] == USB_FEATURE_DEVICE_REMOTE_WAKEUP) { - usbp->status &= ~2U; - usbSetupTransfer(usbp, NULL, 0, NULL); - return true; - } - return false; - case (uint32_t)USB_RTYPE_RECIPIENT_DEVICE | ((uint32_t)USB_REQ_SET_FEATURE << 8): - /* Only the DEVICE_REMOTE_WAKEUP is handled here, any other feature - number is handled as an error.*/ - if (usbp->setup[2] == USB_FEATURE_DEVICE_REMOTE_WAKEUP) { - usbp->status |= 2U; - usbSetupTransfer(usbp, NULL, 0, NULL); - return true; - } - return false; - case (uint32_t)USB_RTYPE_RECIPIENT_DEVICE | ((uint32_t)USB_REQ_SET_ADDRESS << 8): - /* The SET_ADDRESS handling can be performed here or postponed after - the status packed depending on the USB_SET_ADDRESS_MODE low - driver setting.*/ -#if USB_SET_ADDRESS_MODE == USB_EARLY_SET_ADDRESS - if ((usbp->setup[0] == USB_RTYPE_RECIPIENT_DEVICE) && - (usbp->setup[1] == USB_REQ_SET_ADDRESS)) { - set_address(usbp); - } - usbSetupTransfer(usbp, NULL, 0, NULL); -#else - usbSetupTransfer(usbp, NULL, 0, set_address); -#endif - return true; - case (uint32_t)USB_RTYPE_RECIPIENT_DEVICE | ((uint32_t)USB_REQ_GET_DESCRIPTOR << 8): - /* Handling descriptor requests from the host.*/ - dp = usbp->config->get_descriptor_cb(usbp, usbp->setup[3], - usbp->setup[2], - get_hword(&usbp->setup[4])); - if (dp == NULL) { - return false; - } - /*lint -save -e9005 [11.8] Removing const is fine.*/ - usbSetupTransfer(usbp, (uint8_t *)dp->ud_string, dp->ud_size, NULL); - /*lint -restore*/ - return true; - case (uint32_t)USB_RTYPE_RECIPIENT_DEVICE | ((uint32_t)USB_REQ_GET_CONFIGURATION << 8): - /* Returning the last selected configuration.*/ - usbSetupTransfer(usbp, &usbp->configuration, 1, NULL); - return true; - case (uint32_t)USB_RTYPE_RECIPIENT_DEVICE | ((uint32_t)USB_REQ_SET_CONFIGURATION << 8): - /* Handling configuration selection from the host.*/ - usbp->configuration = usbp->setup[2]; - if (usbp->configuration == 0U) { - usbp->state = USB_SELECTED; - } - else { - usbp->state = USB_ACTIVE; - } - _usb_isr_invoke_event_cb(usbp, USB_EVENT_CONFIGURED); - usbSetupTransfer(usbp, NULL, 0, NULL); - return true; - case (uint32_t)USB_RTYPE_RECIPIENT_INTERFACE | ((uint32_t)USB_REQ_GET_STATUS << 8): - case (uint32_t)USB_RTYPE_RECIPIENT_ENDPOINT | ((uint32_t)USB_REQ_SYNCH_FRAME << 8): - /* Just sending two zero bytes, the application can change the behavior - using a hook..*/ - /*lint -save -e9005 [11.8] Removing const is fine.*/ - usbSetupTransfer(usbp, (uint8_t *)zero_status, 2, NULL); - /*lint -restore*/ - return true; - case (uint32_t)USB_RTYPE_RECIPIENT_ENDPOINT | ((uint32_t)USB_REQ_GET_STATUS << 8): - /* Sending the EP status.*/ - if ((usbp->setup[4] & 0x80U) != 0U) { - switch (usb_lld_get_status_in(usbp, usbp->setup[4] & 0x0FU)) { - case EP_STATUS_STALLED: - /*lint -save -e9005 [11.8] Removing const is fine.*/ - usbSetupTransfer(usbp, (uint8_t *)halted_status, 2, NULL); - /*lint -restore*/ - return true; - case EP_STATUS_ACTIVE: - /*lint -save -e9005 [11.8] Removing const is fine.*/ - usbSetupTransfer(usbp, (uint8_t *)active_status, 2, NULL); - /*lint -restore*/ - return true; - case EP_STATUS_DISABLED: - default: - return false; - } - } - else { - switch (usb_lld_get_status_out(usbp, usbp->setup[4] & 0x0FU)) { - case EP_STATUS_STALLED: - /*lint -save -e9005 [11.8] Removing const is fine.*/ - usbSetupTransfer(usbp, (uint8_t *)halted_status, 2, NULL); - /*lint -restore*/ - return true; - case EP_STATUS_ACTIVE: - /*lint -save -e9005 [11.8] Removing const is fine.*/ - usbSetupTransfer(usbp, (uint8_t *)active_status, 2, NULL); - /*lint -restore*/ - return true; - case EP_STATUS_DISABLED: - default: - return false; - } - } - case (uint32_t)USB_RTYPE_RECIPIENT_ENDPOINT | ((uint32_t)USB_REQ_CLEAR_FEATURE << 8): - /* Only ENDPOINT_HALT is handled as feature.*/ - if (usbp->setup[2] != USB_FEATURE_ENDPOINT_HALT) { - return false; - } - /* Clearing the EP status, not valid for EP0, it is ignored in that case.*/ - if ((usbp->setup[4] & 0x0FU) != 0U) { - if ((usbp->setup[4] & 0x80U) != 0U) { - usb_lld_clear_in(usbp, usbp->setup[4] & 0x0FU); - } - else { - usb_lld_clear_out(usbp, usbp->setup[4] & 0x0FU); - } - } - usbSetupTransfer(usbp, NULL, 0, NULL); - return true; - case (uint32_t)USB_RTYPE_RECIPIENT_ENDPOINT | ((uint32_t)USB_REQ_SET_FEATURE << 8): - /* Only ENDPOINT_HALT is handled as feature.*/ - if (usbp->setup[2] != USB_FEATURE_ENDPOINT_HALT) { - return false; - } - /* Stalling the EP, not valid for EP0, it is ignored in that case.*/ - if ((usbp->setup[4] & 0x0FU) != 0U) { - if ((usbp->setup[4] & 0x80U) != 0U) { - usb_lld_stall_in(usbp, usbp->setup[4] & 0x0FU); - } - else { - usb_lld_stall_out(usbp, usbp->setup[4] & 0x0FU); - } - } - usbSetupTransfer(usbp, NULL, 0, NULL); - return true; - case (uint32_t)USB_RTYPE_RECIPIENT_DEVICE | ((uint32_t)USB_REQ_SET_DESCRIPTOR << 8): - case (uint32_t)USB_RTYPE_RECIPIENT_INTERFACE | ((uint32_t)USB_REQ_CLEAR_FEATURE << 8): - case (uint32_t)USB_RTYPE_RECIPIENT_INTERFACE | ((uint32_t)USB_REQ_SET_FEATURE << 8): - case (uint32_t)USB_RTYPE_RECIPIENT_INTERFACE | ((uint32_t)USB_REQ_GET_INTERFACE << 8): - case (uint32_t)USB_RTYPE_RECIPIENT_INTERFACE | ((uint32_t)USB_REQ_SET_INTERFACE << 8): - /* All the above requests are not handled here, if you need them then - use the hook mechanism and provide handling.*/ - default: - return false; - } -} - -/*===========================================================================*/ -/* Driver exported functions. */ -/*===========================================================================*/ - -/** - * @brief USB Driver initialization. - * @note This function is implicitly invoked by @p halInit(), there is - * no need to explicitly initialize the driver. - * - * @init - */ -void usbInit(void) { - - usb_lld_init(); -} - -/** - * @brief Initializes the standard part of a @p USBDriver structure. - * - * @param[out] usbp pointer to the @p USBDriver object - * - * @init - */ -void usbObjectInit(USBDriver *usbp) { - unsigned i; - - usbp->state = USB_STOP; - usbp->config = NULL; - for (i = 0; i < (unsigned)USB_MAX_ENDPOINTS; i++) { - usbp->in_params[i] = NULL; - usbp->out_params[i] = NULL; - } - usbp->transmitting = 0; - usbp->receiving = 0; -} - -/** - * @brief Configures and activates the USB peripheral. - * - * @param[in] usbp pointer to the @p USBDriver object - * @param[in] config pointer to the @p USBConfig object - * - * @api - */ -void usbStart(USBDriver *usbp, const USBConfig *config) { - unsigned i; - - osalDbgCheck((usbp != NULL) && (config != NULL)); - - osalSysLock(); - osalDbgAssert((usbp->state == USB_STOP) || (usbp->state == USB_READY), - "invalid state"); - usbp->config = config; - for (i = 0; i <= (unsigned)USB_MAX_ENDPOINTS; i++) { - usbp->epc[i] = NULL; - } - usb_lld_start(usbp); - usbp->state = USB_READY; - osalSysUnlock(); -} - -/** - * @brief Deactivates the USB peripheral. - * - * @param[in] usbp pointer to the @p USBDriver object - * - * @api - */ -void usbStop(USBDriver *usbp) { - unsigned i; - - osalDbgCheck(usbp != NULL); - - osalSysLock(); - osalDbgAssert((usbp->state == USB_STOP) || (usbp->state == USB_READY) || - (usbp->state == USB_SELECTED) || (usbp->state == USB_ACTIVE) || - (usbp->state == USB_SUSPENDED), - "invalid state"); - usb_lld_stop(usbp); - usbp->state = USB_STOP; - - /* Resetting all ongoing synchronous operations.*/ - for (i = 0; i <= (unsigned)USB_MAX_ENDPOINTS; i++) { -#if USB_USE_WAIT == TRUE - if (usbp->epc[i] != NULL) { - if (usbp->epc[i]->in_state != NULL) { - osalThreadResumeI(&usbp->epc[i]->in_state->thread, MSG_RESET); - } - if (usbp->epc[i]->out_state != NULL) { - osalThreadResumeI(&usbp->epc[i]->out_state->thread, MSG_RESET); - } - } -#endif - usbp->epc[i] = NULL; - } - osalOsRescheduleS(); - osalSysUnlock(); -} - -/** - * @brief Enables an endpoint. - * @details This function enables an endpoint, both IN and/or OUT directions - * depending on the configuration structure. - * @note This function must be invoked in response of a SET_CONFIGURATION - * or SET_INTERFACE message. - * - * @param[in] usbp pointer to the @p USBDriver object - * @param[in] ep endpoint number - * @param[in] epcp the endpoint configuration - * - * @iclass - */ -void usbInitEndpointI(USBDriver *usbp, usbep_t ep, - const USBEndpointConfig *epcp) { - - osalDbgCheckClassI(); - osalDbgCheck((usbp != NULL) && (epcp != NULL)); - osalDbgAssert(usbp->state == USB_ACTIVE, - "invalid state"); - osalDbgAssert(usbp->epc[ep] == NULL, "already initialized"); - - /* Logically enabling the endpoint in the USBDriver structure.*/ - usbp->epc[ep] = epcp; - - /* Clearing the state structures, custom fields as well.*/ - if (epcp->in_state != NULL) { - memset(epcp->in_state, 0, sizeof(USBInEndpointState)); - } - if (epcp->out_state != NULL) { - memset(epcp->out_state, 0, sizeof(USBOutEndpointState)); - } - - /* Low level endpoint activation.*/ - usb_lld_init_endpoint(usbp, ep); -} - -/** - * @brief Disables all the active endpoints. - * @details This function disables all the active endpoints except the - * endpoint zero. - * @note This function must be invoked in response of a SET_CONFIGURATION - * message with configuration number zero. - * - * @param[in] usbp pointer to the @p USBDriver object - * - * @iclass - */ -void usbDisableEndpointsI(USBDriver *usbp) { - unsigned i; - - osalDbgCheckClassI(); - osalDbgCheck(usbp != NULL); - osalDbgAssert(usbp->state == USB_SELECTED, "invalid state"); - - usbp->transmitting &= ~1U; - usbp->receiving &= ~1U; - for (i = 1; i <= (unsigned)USB_MAX_ENDPOINTS; i++) { -#if USB_USE_WAIT == TRUE - /* Signaling the event to threads waiting on endpoints.*/ - if (usbp->epc[i] != NULL) { - osalSysLockFromISR(); - if (usbp->epc[i]->in_state != NULL) { - osalThreadResumeI(&usbp->epc[i]->in_state->thread, MSG_RESET); - } - if (usbp->epc[i]->out_state != NULL) { - osalThreadResumeI(&usbp->epc[i]->out_state->thread, MSG_RESET); - } - osalSysUnlockFromISR(); - } -#endif - usbp->epc[i] = NULL; - } - - /* Low level endpoints deactivation.*/ - usb_lld_disable_endpoints(usbp); -} - -/** - * @brief Starts a receive transaction on an OUT endpoint. - * @note This function is meant to be called from ISR context outside - * critical zones because there is a potentially slow operation - * inside. - * - * @param[in] usbp pointer to the @p USBDriver object - * @param[in] ep endpoint number - * @param[out] buf buffer where to copy the received data - * @param[in] n transaction size. It is recommended a multiple of - * the packet size because the excess is discarded. - * - * @iclass - */ -void usbStartReceiveI(USBDriver *usbp, usbep_t ep, - uint8_t *buf, size_t n) { - USBOutEndpointState *osp; - - osalDbgCheckClassI(); - osalDbgCheck((usbp != NULL) && (ep <= (usbep_t)USB_MAX_ENDPOINTS)); - osalDbgAssert(!usbGetReceiveStatusI(usbp, ep), "already receiving"); - - /* Marking the endpoint as active.*/ - usbp->receiving |= (uint16_t)((unsigned)1U << (unsigned)ep); - - /* Setting up the transfer.*/ - /*lint -save -e661 [18.1] pclint is confused by the check on ep.*/ - osp = usbp->epc[ep]->out_state; - /*lint -restore*/ - osp->rxbuf = buf; - osp->rxsize = n; - osp->rxcnt = 0; -#if USB_USE_WAIT == TRUE - osp->thread = NULL; -#endif - - /* Starting transfer.*/ - usb_lld_start_out(usbp, ep); -} - -/** - * @brief Starts a transmit transaction on an IN endpoint. - * @note This function is meant to be called from ISR context outside - * critical zones because there is a potentially slow operation - * inside. - * - * @param[in] usbp pointer to the @p USBDriver object - * @param[in] ep endpoint number - * @param[in] buf buffer where to fetch the data to be transmitted - * @param[in] n transaction size - * - * @iclass - */ -void usbStartTransmitI(USBDriver *usbp, usbep_t ep, - const uint8_t *buf, size_t n) { - USBInEndpointState *isp; - - osalDbgCheckClassI(); - osalDbgCheck((usbp != NULL) && (ep <= (usbep_t)USB_MAX_ENDPOINTS)); - osalDbgAssert(!usbGetTransmitStatusI(usbp, ep), "already transmitting"); - - /* Marking the endpoint as active.*/ - usbp->transmitting |= (uint16_t)((unsigned)1U << (unsigned)ep); - - /* Setting up the transfer.*/ - /*lint -save -e661 [18.1] pclint is confused by the check on ep.*/ - isp = usbp->epc[ep]->in_state; - /*lint -restore*/ - isp->txbuf = buf; - isp->txsize = n; - isp->txcnt = 0; -#if USB_USE_WAIT == TRUE - isp->thread = NULL; -#endif - - /* Starting transfer.*/ - usb_lld_start_in(usbp, ep); -} - -#if (USB_USE_WAIT == TRUE) || defined(__DOXYGEN__) -/** - * @brief Performs a receive transaction on an OUT endpoint. - * - * @param[in] usbp pointer to the @p USBDriver object - * @param[in] ep endpoint number - * @param[out] buf buffer where to copy the received data - * @param[in] n transaction size. It is recommended a multiple of - * the packet size because the excess is discarded. - * - * @return The received effective data size, it can be less than - * the amount specified. - * @retval MSG_RESET driver not in @p USB_ACTIVE state or the operation - * has been aborted by an USB reset or a transition to - * the @p USB_SUSPENDED state. - * - * @api - */ -msg_t usbReceive(USBDriver *usbp, usbep_t ep, uint8_t *buf, size_t n) { - msg_t msg; - - osalSysLock(); - - if (usbGetDriverStateI(usbp) != USB_ACTIVE) { - osalSysUnlock(); - return MSG_RESET; - } - - usbStartReceiveI(usbp, ep, buf, n); - msg = osalThreadSuspendS(&usbp->epc[ep]->out_state->thread); - osalSysUnlock(); - - return msg; -} - -/** - * @brief Performs a transmit transaction on an IN endpoint. - * - * @param[in] usbp pointer to the @p USBDriver object - * @param[in] ep endpoint number - * @param[in] buf buffer where to fetch the data to be transmitted - * @param[in] n transaction size - * - * @return The operation status. - * @retval MSG_OK operation performed successfully. - * @retval MSG_RESET driver not in @p USB_ACTIVE state or the operation - * has been aborted by an USB reset or a transition to - * the @p USB_SUSPENDED state. - * - * @api - */ -msg_t usbTransmit(USBDriver *usbp, usbep_t ep, const uint8_t *buf, size_t n) { - msg_t msg; - - osalSysLock(); - - if (usbGetDriverStateI(usbp) != USB_ACTIVE) { - osalSysUnlock(); - return MSG_RESET; - } - - usbStartTransmitI(usbp, ep, buf, n); - msg = osalThreadSuspendS(&usbp->epc[ep]->in_state->thread); - osalSysUnlock(); - - return msg; -} -#endif /* USB_USE_WAIT == TRUE */ - -/** - * @brief Stalls an OUT endpoint. - * - * @param[in] usbp pointer to the @p USBDriver object - * @param[in] ep endpoint number - * - * @return The operation status. - * @retval false Endpoint stalled. - * @retval true Endpoint busy, not stalled. - * - * @iclass - */ -bool usbStallReceiveI(USBDriver *usbp, usbep_t ep) { - - osalDbgCheckClassI(); - osalDbgCheck(usbp != NULL); - - if (usbGetReceiveStatusI(usbp, ep)) { - return true; - } - - usb_lld_stall_out(usbp, ep); - return false; -} - -/** - * @brief Stalls an IN endpoint. - * - * @param[in] usbp pointer to the @p USBDriver object - * @param[in] ep endpoint number - * - * @return The operation status. - * @retval false Endpoint stalled. - * @retval true Endpoint busy, not stalled. - * - * @iclass - */ -bool usbStallTransmitI(USBDriver *usbp, usbep_t ep) { - - osalDbgCheckClassI(); - osalDbgCheck(usbp != NULL); - - if (usbGetTransmitStatusI(usbp, ep)) { - return true; - } - - usb_lld_stall_in(usbp, ep); - return false; -} - -/** - * @brief USB reset routine. - * @details This function must be invoked when an USB bus reset condition is - * detected. - * - * @param[in] usbp pointer to the @p USBDriver object - * - * @notapi - */ -void _usb_reset(USBDriver *usbp) { - unsigned i; - - /* State transition.*/ - usbp->state = USB_READY; - - /* Resetting internal state.*/ - usbp->status = 0; - usbp->address = 0; - usbp->configuration = 0; - usbp->transmitting = 0; - usbp->receiving = 0; - - /* Invalidates all endpoints into the USBDriver structure.*/ - for (i = 0; i <= (unsigned)USB_MAX_ENDPOINTS; i++) { -#if USB_USE_WAIT == TRUE - /* Signaling the event to threads waiting on endpoints.*/ - if (usbp->epc[i] != NULL) { - osalSysLockFromISR(); - if (usbp->epc[i]->in_state != NULL) { - osalThreadResumeI(&usbp->epc[i]->in_state->thread, MSG_RESET); - } - if (usbp->epc[i]->out_state != NULL) { - osalThreadResumeI(&usbp->epc[i]->out_state->thread, MSG_RESET); - } - osalSysUnlockFromISR(); - } -#endif - usbp->epc[i] = NULL; - } - - /* EP0 state machine initialization.*/ - usbp->ep0state = USB_EP0_WAITING_SETUP; - - /* Low level reset.*/ - usb_lld_reset(usbp); - - /* Notification of reset event.*/ - _usb_isr_invoke_event_cb(usbp, USB_EVENT_RESET); -} - -/** - * @brief USB suspend routine. - * @details This function must be invoked when an USB bus suspend condition is - * detected. - * - * @param[in] usbp pointer to the @p USBDriver object - * - * @notapi - */ -void _usb_suspend(USBDriver *usbp) { - - /* State transition.*/ - usbp->state = USB_SUSPENDED; - - /* Notification of suspend event.*/ - _usb_isr_invoke_event_cb(usbp, USB_EVENT_SUSPEND); - - /* Signaling the event to threads waiting on endpoints.*/ -#if USB_USE_WAIT == TRUE - { - unsigned i; - - for (i = 0; i <= (unsigned)USB_MAX_ENDPOINTS; i++) { - if (usbp->epc[i] != NULL) { - osalSysLockFromISR(); - if (usbp->epc[i]->in_state != NULL) { - osalThreadResumeI(&usbp->epc[i]->in_state->thread, MSG_RESET); - } - if (usbp->epc[i]->out_state != NULL) { - osalThreadResumeI(&usbp->epc[i]->out_state->thread, MSG_RESET); - } - osalSysUnlockFromISR(); - } - } - } -#endif -} - -/** - * @brief USB wake-up routine. - * @details This function must be invoked when an USB bus wake-up condition is - * detected. - * - * @param[in] usbp pointer to the @p USBDriver object - * - * @notapi - */ -void _usb_wakeup(USBDriver *usbp) { - - /* State transition.*/ - usbp->state = USB_ACTIVE; - - /* Notification of suspend event.*/ - _usb_isr_invoke_event_cb(usbp, USB_EVENT_WAKEUP); -} - -/** - * @brief Default EP0 SETUP callback. - * @details This function is used by the low level driver as default handler - * for EP0 SETUP events. - * - * @param[in] usbp pointer to the @p USBDriver object - * @param[in] ep endpoint number, always zero - * - * @notapi - */ -void _usb_ep0setup(USBDriver *usbp, usbep_t ep) { - size_t max; - - usbp->ep0state = USB_EP0_WAITING_SETUP; - usbReadSetup(usbp, ep, usbp->setup); - - /* First verify if the application has an handler installed for this - request.*/ - /*lint -save -e9007 [13.5] No side effects, it is intentional.*/ - if ((usbp->config->requests_hook_cb == NULL) || - !(usbp->config->requests_hook_cb(usbp))) { - /*lint -restore*/ - /* Invoking the default handler, if this fails then stalls the - endpoint zero as error.*/ - /*lint -save -e9007 [13.5] No side effects, it is intentional.*/ - if (((usbp->setup[0] & USB_RTYPE_TYPE_MASK) != USB_RTYPE_TYPE_STD) || - !default_handler(usbp)) { - /*lint -restore*/ - /* Error response, the state machine goes into an error state, the low - level layer will have to reset it to USB_EP0_WAITING_SETUP after - receiving a SETUP packet.*/ - usb_lld_stall_in(usbp, 0); - usb_lld_stall_out(usbp, 0); - _usb_isr_invoke_event_cb(usbp, USB_EVENT_STALLED); - usbp->ep0state = USB_EP0_ERROR; - return; - } - } -#if (USB_SET_ADDRESS_ACK_HANDLING == USB_SET_ADDRESS_ACK_HW) - if (usbp->setup[1] == USB_REQ_SET_ADDRESS) { - /* Zero-length packet sent by hardware */ - return; - } -#endif - /* Transfer preparation. The request handler must have populated - correctly the fields ep0next, ep0n and ep0endcb using the macro - usbSetupTransfer().*/ - max = (size_t)get_hword(&usbp->setup[6]); - /* The transfer size cannot exceed the specified amount.*/ - if (usbp->ep0n > max) { - usbp->ep0n = max; - } - if ((usbp->setup[0] & USB_RTYPE_DIR_MASK) == USB_RTYPE_DIR_DEV2HOST) { - /* IN phase.*/ - if (usbp->ep0n != 0U) { - /* Starts the transmit phase.*/ - usbp->ep0state = USB_EP0_TX; - osalSysLockFromISR(); - usbStartTransmitI(usbp, 0, usbp->ep0next, usbp->ep0n); - osalSysUnlockFromISR(); - } - else { - /* No transmission phase, directly receiving the zero sized status - packet.*/ - usbp->ep0state = USB_EP0_WAITING_STS; -#if (USB_EP0_STATUS_STAGE == USB_EP0_STATUS_STAGE_SW) - osalSysLockFromISR(); - usbStartReceiveI(usbp, 0, NULL, 0); - osalSysUnlockFromISR(); -#else - usb_lld_end_setup(usbp, ep); -#endif - } - } - else { - /* OUT phase.*/ - if (usbp->ep0n != 0U) { - /* Starts the receive phase.*/ - usbp->ep0state = USB_EP0_RX; - osalSysLockFromISR(); - usbStartReceiveI(usbp, 0, usbp->ep0next, usbp->ep0n); - osalSysUnlockFromISR(); - } - else { - /* No receive phase, directly sending the zero sized status - packet.*/ - usbp->ep0state = USB_EP0_SENDING_STS; -#if (USB_EP0_STATUS_STAGE == USB_EP0_STATUS_STAGE_SW) - osalSysLockFromISR(); - usbStartTransmitI(usbp, 0, NULL, 0); - osalSysUnlockFromISR(); -#else - usb_lld_end_setup(usbp, ep); -#endif - } - } -} - -/** - * @brief Default EP0 IN callback. - * @details This function is used by the low level driver as default handler - * for EP0 IN events. - * - * @param[in] usbp pointer to the @p USBDriver object - * @param[in] ep endpoint number, always zero - * - * @notapi - */ -void _usb_ep0in(USBDriver *usbp, usbep_t ep) { - size_t max; - - (void)ep; - switch (usbp->ep0state) { - case USB_EP0_TX: - max = (size_t)get_hword(&usbp->setup[6]); - /* If the transmitted size is less than the requested size and it is a - multiple of the maximum packet size then a zero size packet must be - transmitted.*/ - if ((usbp->ep0n < max) && - ((usbp->ep0n % usbp->epc[0]->in_maxsize) == 0U)) { - osalSysLockFromISR(); - usbStartTransmitI(usbp, 0, NULL, 0); - osalSysUnlockFromISR(); - usbp->ep0state = USB_EP0_WAITING_TX0; - return; - } - /* Falls into, it is intentional.*/ - case USB_EP0_WAITING_TX0: - /* Transmit phase over, receiving the zero sized status packet.*/ - usbp->ep0state = USB_EP0_WAITING_STS; -#if (USB_EP0_STATUS_STAGE == USB_EP0_STATUS_STAGE_SW) - osalSysLockFromISR(); - usbStartReceiveI(usbp, 0, NULL, 0); - osalSysUnlockFromISR(); -#else - usb_lld_end_setup(usbp, ep); -#endif - return; - case USB_EP0_SENDING_STS: - /* Status packet sent, invoking the callback if defined.*/ - if (usbp->ep0endcb != NULL) { - usbp->ep0endcb(usbp); - } - usbp->ep0state = USB_EP0_WAITING_SETUP; - return; - case USB_EP0_WAITING_SETUP: - case USB_EP0_WAITING_STS: - case USB_EP0_RX: - /* All the above are invalid states in the IN phase.*/ - osalDbgAssert(false, "EP0 state machine error"); - /* Falling through is intentional.*/ - case USB_EP0_ERROR: - /* Error response, the state machine goes into an error state, the low - level layer will have to reset it to USB_EP0_WAITING_SETUP after - receiving a SETUP packet.*/ - usb_lld_stall_in(usbp, 0); - usb_lld_stall_out(usbp, 0); - _usb_isr_invoke_event_cb(usbp, USB_EVENT_STALLED); - usbp->ep0state = USB_EP0_ERROR; - return; - default: - osalDbgAssert(false, "EP0 state machine invalid state"); - } -} - -/** - * @brief Default EP0 OUT callback. - * @details This function is used by the low level driver as default handler - * for EP0 OUT events. - * - * @param[in] usbp pointer to the @p USBDriver object - * @param[in] ep endpoint number, always zero - * - * @notapi - */ -void _usb_ep0out(USBDriver *usbp, usbep_t ep) { - - (void)ep; - switch (usbp->ep0state) { - case USB_EP0_RX: - /* Receive phase over, sending the zero sized status packet.*/ - usbp->ep0state = USB_EP0_SENDING_STS; -#if (USB_EP0_STATUS_STAGE == USB_EP0_STATUS_STAGE_SW) - osalSysLockFromISR(); - usbStartTransmitI(usbp, 0, NULL, 0); - osalSysUnlockFromISR(); -#else - usb_lld_end_setup(usbp, ep); -#endif - return; - case USB_EP0_WAITING_STS: - /* Status packet received, it must be zero sized, invoking the callback - if defined.*/ -#if (USB_EP0_STATUS_STAGE == USB_EP0_STATUS_STAGE_SW) - if (usbGetReceiveTransactionSizeX(usbp, 0) != 0U) { - break; - } -#endif - if (usbp->ep0endcb != NULL) { - usbp->ep0endcb(usbp); - } - usbp->ep0state = USB_EP0_WAITING_SETUP; - return; - case USB_EP0_WAITING_SETUP: - case USB_EP0_TX: - case USB_EP0_WAITING_TX0: - case USB_EP0_SENDING_STS: - /* All the above are invalid states in the IN phase.*/ - osalDbgAssert(false, "EP0 state machine error"); - /* Falling through is intentional.*/ - case USB_EP0_ERROR: - /* Error response, the state machine goes into an error state, the low - level layer will have to reset it to USB_EP0_WAITING_SETUP after - receiving a SETUP packet.*/ - usb_lld_stall_in(usbp, 0); - usb_lld_stall_out(usbp, 0); - _usb_isr_invoke_event_cb(usbp, USB_EVENT_STALLED); - usbp->ep0state = USB_EP0_ERROR; - return; - default: - osalDbgAssert(false, "EP0 state machine invalid state"); - } -} - -#endif /* HAL_USE_USB == TRUE */ - -/** @} */ diff --git a/os/hal/src/wdg.c b/os/hal/src/wdg.c deleted file mode 100644 index a764864a4..000000000 --- a/os/hal/src/wdg.c +++ /dev/null @@ -1,120 +0,0 @@ -/* - ChibiOS - Copyright (C) 2006..2016 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 wdg.c - * @brief WDG Driver code. - * - * @addtogroup WDG - * @{ - */ - -#include "hal.h" - -#if (HAL_USE_WDG == TRUE) || defined(__DOXYGEN__) - -/*===========================================================================*/ -/* Driver local definitions. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver exported variables. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver local variables. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver local functions. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver exported functions. */ -/*===========================================================================*/ - -/** - * @brief WDG Driver initialization. - * @note This function is implicitly invoked by @p halInit(), there is - * no need to explicitly initialize the driver. - * - * @init - */ -void wdgInit(void) { - - wdg_lld_init(); -} - -/** - * @brief Configures and activates the WDG peripheral. - * - * @param[in] wdgp pointer to the @p WDGDriver object - * @param[in] config pointer to the @p WDGConfig object - * - * @api - */ -void wdgStart(WDGDriver *wdgp, const WDGConfig *config) { - - osalDbgCheck((wdgp != NULL) && (config != NULL)); - - osalSysLock(); - osalDbgAssert((wdgp->state == WDG_STOP) || (wdgp->state == WDG_READY), - "invalid state"); - wdgp->config = config; - wdg_lld_start(wdgp); - wdgp->state = WDG_READY; - osalSysUnlock(); -} - -/** - * @brief Deactivates the WDG peripheral. - * - * @param[in] wdgp pointer to the @p WDGDriver object - * - * @api - */ -void wdgStop(WDGDriver *wdgp) { - - osalDbgCheck(wdgp != NULL); - - osalSysLock(); - osalDbgAssert((wdgp->state == WDG_STOP) || (wdgp->state == WDG_READY), - "invalid state"); - wdg_lld_stop(wdgp); - wdgp->state = WDG_STOP; - osalSysUnlock(); -} - -/** - * @brief Resets WDG's counter. - * - * @param[in] wdgp pointer to the @p WDGDriver object - * - * @api - */ -void wdgReset(WDGDriver *wdgp) { - - osalDbgCheck(wdgp != NULL); - - osalSysLock(); - osalDbgAssert(wdgp->state == WDG_READY, "not ready"); - wdgResetI(wdgp); - osalSysUnlock(); -} - -#endif /* HAL_USE_WDG == TRUE */ - -/** @} */ -- cgit v1.2.3