/** * @brief Wait end of data transaction and performs finalizations. * * @param[in] sdcp pointer to the @p SDCDriver object * @param[in] n number of blocks in transaction * @param[in] resp pointer to the response buffer * * @return The operation status. * @retval HAL_SUCCESS operation succeeded. * @retval HAL_FAILED operation failed. */ static bool sdc_lld_wait_transaction_end(SDCDriver *sdcp, uint32_t n, uint32_t *resp) { /* Note the mask is checked before going to sleep because the interrupt may have occurred before reaching the critical zone.*/ osalSysLock(); if (sdcp->sdmmc->MASK != 0) osalThreadSuspendS(&sdcp->thread); if ((sdcp->sdmmc->STA & SDMMC_STA_DATAEND) == 0) { osalSysUnlock(); return HAL_FAILED; } /* Wait until DMA channel enabled to be sure that all data transferred.*/ while (sdcp->dma->stream->CR & STM32_DMA_CR_EN) ; /* DMA event flags must be manually cleared.*/ dmaStreamClearInterrupt(sdcp->dma); sdcp->sdmmc->ICR = SDMMC_ICR_ALL_FLAGS; sdcp->sdmmc->DCTRL = 0; osalSysUnlock(); /* Finalize transaction.*/ if (n > 1) return sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_STOP_TRANSMISSION, 0, resp); return HAL_SUCCESS; }
/** * @brief Wait end of data transaction and performs finalizations. * * @param[in] sdcp pointer to the @p SDCDriver object * @param[in] n number of blocks in transaction * @param[in] resp pointer to the response buffer * * @return The operation status. * @retval HAL_SUCCESS operation succeeded. * @retval HAL_FAILED operation failed. */ static bool sdc_lld_wait_transaction_end(SDCDriver *sdcp, uint32_t n, uint32_t *resp) { /* Note the mask is checked before going to sleep because the interrupt may have occurred before reaching the critical zone.*/ osalSysLock(); if (sdcp->sdmmc->MASK != 0) osalThreadSuspendS(&sdcp->thread); if ((sdcp->sdmmc->STA & SDMMC_STA_DATAEND) == 0) { osalSysUnlock(); return HAL_FAILED; } /* Waits for transfer completion at DMA level, then the stream is disabled and cleared.*/ dmaWaitCompletion(sdcp->dma); sdcp->sdmmc->ICR = SDMMC_ICR_ALL_FLAGS; sdcp->sdmmc->DCTRL = 0; osalSysUnlock(); /* Finalize transaction.*/ if (n > 1) return sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_STOP_TRANSMISSION, 0, resp); return HAL_SUCCESS; }
/** * @brief USB data transfer loop. * @details This function must be executed by a system thread in order to * make the USB driver work. * @note The data copy part of the driver is implemented in this thread * in order to not perform heavy tasks withing interrupt handlers. * * @param[in] p pointer to the @p USBDriver object * @return The function never returns. * * @special */ msg_t usb_lld_pump(void *p) { USBDriver *usbp = (USBDriver *)p; stm32_otg_t *otgp = usbp->otg; #if defined(_CHIBIOS_RT_) chRegSetThreadName("usb_lld_pump"); #endif osalSysLock(); while (true) { usbep_t ep; uint32_t epmask; /* Nothing to do, going to sleep.*/ if ((usbp->state == USB_STOP) || ((usbp->txpending == 0) && !(otgp->GINTSTS & GINTSTS_RXFLVL))) { otgp->GINTMSK |= GINTMSK_RXFLVLM; osalThreadSuspendS(&usbp->wait); } osalSysUnlock(); /* Checks if there are TXFIFOs to be filled.*/ for (ep = 0; ep <= usbp->otgparams->num_endpoints; ep++) { /* Empties the RX FIFO.*/ while (otgp->GINTSTS & GINTSTS_RXFLVL) { otg_rxfifo_handler(usbp); } epmask = (1 << ep); if (usbp->txpending & epmask) { bool done; osalSysLock(); /* USB interrupts are globally *suspended* because the peripheral does not allow any interference during the TX FIFO filling operation. Synopsys document: DesignWare Cores USB 2.0 Hi-Speed On-The-Go (OTG) "The application has to finish writing one complete packet before switching to a different channel/endpoint FIFO. Violating this rule results in an error.".*/ otgp->GAHBCFG &= ~GAHBCFG_GINTMSK; usbp->txpending &= ~epmask; osalSysUnlock(); done = otg_txfifo_handler(usbp, ep); osalSysLock(); otgp->GAHBCFG |= GAHBCFG_GINTMSK; if (!done) otgp->DIEPEMPMSK |= epmask; osalSysUnlock(); } } osalSysLock(); } osalSysUnlock(); return 0; }
/** * @brief Read some bites from slave device. * * @param[in] owp pointer to the @p onewireDriver object * @param[in] txbuf pointer to the buffer with data to be written * @param[in] txbytes amount of data to be written * @param[in] pullup_time how long strong pull up must be activated. Set * it to 0 if not needed. */ void onewireWrite(onewireDriver *owp, uint8_t *txbuf, size_t txbytes, systime_t pullup_time) { PWMDriver *pwmd; PWMConfig *pwmcfg; size_t mch, sch; osalDbgCheck((NULL != owp) && (NULL != txbuf)); osalDbgCheck((txbytes > 0) && (txbytes <= ONEWIRE_MAX_TRANSACTION_LEN)); osalDbgAssert(owp->reg.state == ONEWIRE_READY, "Invalid state"); #if !ONEWIRE_USE_STRONG_PULLUP osalDbgAssert(0 == pullup_time, "Non zero time is valid only when strong pull enabled"); #endif pwmd = owp->config->pwmd; pwmcfg = owp->config->pwmcfg; mch = owp->config->master_channel; sch = owp->config->sample_channel; owp->buf = txbuf; owp->reg.bit = 0; owp->reg.final_timeslot = false; owp->reg.bytes = txbytes; pwmcfg->period = ONEWIRE_ZERO_WIDTH + ONEWIRE_RECOVERY_WIDTH; pwmcfg->callback = pwm_write_bit_cb; pwmcfg->channels[mch].callback = NULL; pwmcfg->channels[mch].mode = owp->config->pwmmode; pwmcfg->channels[sch].callback = NULL; pwmcfg->channels[sch].mode = PWM_OUTPUT_DISABLED; #if ONEWIRE_USE_STRONG_PULLUP if (pullup_time > 0) { owp->reg.state = ONEWIRE_PULL_UP; owp->reg.need_pullup = true; } #endif ow_bus_active(owp); osalSysLock(); pwmEnablePeriodicNotificationI(pwmd); osalThreadSuspendS(&owp->thread); osalSysUnlock(); pwmDisablePeriodicNotification(pwmd); ow_bus_idle(owp); #if ONEWIRE_USE_STRONG_PULLUP if (pullup_time > 0) { osalThreadSleep(pullup_time); owp->config->pullup_release(); owp->reg.state = ONEWIRE_READY; } #endif }
/** * @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(); }
/** * @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 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; }
/** * @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)); #if SPI_SUPPORTS_CIRCULAR osalDbgCheck((spip->config->circular == false) || ((n & 1U) == 0U)); #endif osalSysLock(); osalDbgAssert(spip->state == SPI_READY, "not ready"); spiStartReceiveI(spip, n, rxbuf); (void) osalThreadSuspendS(&spip->thread); osalSysUnlock(); }
/** * @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; }
/** * @brief Sends a command without data phase. * @pre In order to use this function the option @p QSPI_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] qspip pointer to the @p QSPIDriver object * @param[in] cmdp pointer to the command descriptor * * @api */ void qspiCommand(QSPIDriver *qspip, const qspi_command_t *cmdp) { osalDbgCheck((qspip != NULL) && (cmdp != NULL)); osalDbgCheck((cmdp->cfg & QSPI_CFG_DATA_MODE_MASK) == QSPI_CFG_DATA_MODE_NONE); osalSysLock(); osalDbgAssert(qspip->state == QSPI_READY, "not ready"); osalDbgAssert(qspip->config->end_cb == NULL, "has callback"); qspiStartCommandI(qspip, cmdp); (void) osalThreadSuspendS(&qspip->thread); osalSysUnlock(); }
/** * @brief Returns calculated CRC from last reset * * @param[in] crcp pointer to the @p CRCDriver object * @param[in] n size of buf in bytes * @param[in] buf @p buffer location * * @notapi */ uint32_t crc_lld_calc(CRCDriver *crcp, size_t n, const void *buf) { #if CRC_USE_DMA == TRUE crc_lld_start_calc(crcp, n, buf); (void) osalThreadSuspendS(&crcp->thread); #else /** * BUG: Only peform byte writes to DR reg if reflect_data is disabled. * The STM32 hardware unit seems to incorrectly calculate CRCs when all * of the following is true: reflect_data(rev_in) is 0, dma is disable, and * you are writing more than a byte into the DR register. */ if (crcp->config->reflect_data != 0) { while(n > 3) { _crc_lld_calc_word(crcp, *(uint32_t*)buf); buf+=4; n-=4; } } #if STM32_CRC_PROGRAMMABLE == TRUE /* Programmable CRC units allow variable register width accesses.*/ /** * BUG: Only peform byte writes to DR reg if reflect_data is disabled. * The STM32 hardware unit seems to incorrectly calculate CRCs when all * of the following is true: reflect_data(rev_in) is 0, dma is disable, and * you are writing more than a byte into the DR register. */ if (crcp->config->reflect_data != 0) { while(n > 1) { _crc_lld_calc_halfword(crcp, *(uint16_t*)buf); buf+=2; n-=2; } } while(n > 0) { _crc_lld_calc_byte(crcp, *(uint8_t*)buf); buf++; n--; } #else osalDbgAssert(n == 0, "STM32 CRC Unit only supports WORD accesses"); #endif #endif return crcp->crc->DR ^ crcp->config->final_val; }
/** * @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; }
/** * @brief Sends a command then receives data over the QSPI bus. * @pre In order to use this function the option @p QSPI_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] qspip pointer to the @p QSPIDriver object * @param[in] cmdp pointer to the command descriptor * @param[in] n number of bytes to send * @param[out] rxbuf the pointer to the receive buffer * * @api */ void qspiReceive(QSPIDriver *qspip, const qspi_command_t *cmdp, size_t n, uint8_t *rxbuf) { osalDbgCheck((qspip != NULL) && (cmdp != NULL)); osalDbgCheck((n > 0U) && (rxbuf != NULL)); osalDbgCheck((cmdp->cfg & QSPI_CFG_DATA_MODE_MASK) != QSPI_CFG_DATA_MODE_NONE); osalSysLock(); osalDbgAssert(qspip->state == QSPI_READY, "not ready"); osalDbgAssert(qspip->config->end_cb == NULL, "has callback"); qspiStartReceiveI(qspip, cmdp, n, rxbuf); (void) osalThreadSuspendS(&qspip->thread); osalSysUnlock(); }
/** * @brief Wait end of data transaction and performs finalizations. * * @param[in] sdcp pointer to the @p SDCDriver object * @param[in] n number of blocks in transaction * @param[in] resp pointer to the response buffer * * @return The operation status. * @retval HAL_SUCCESS operation succeeded. * @retval HAL_FAILED operation failed. */ static bool sdc_lld_wait_transaction_end(SDCDriver *sdcp, uint32_t n, uint32_t *resp) { /* Note the mask is checked before going to sleep because the interrupt may have occurred before reaching the critical zone.*/ osalSysLock(); if (sdcp->sdio->MASK != 0) osalThreadSuspendS(&sdcp->thread); if ((sdcp->sdio->STA & SDIO_STA_DATAEND) == 0) { osalSysUnlock(); return HAL_FAILED; } #if (defined(STM32F4XX) || defined(STM32F2XX)) /* Wait until DMA channel enabled to be sure that all data transferred.*/ while (sdcp->dma->stream->CR & STM32_DMA_CR_EN) ; /* DMA event flags must be manually cleared.*/ dmaStreamClearInterrupt(sdcp->dma); sdcp->sdio->ICR = STM32_SDIO_ICR_ALL_FLAGS; sdcp->sdio->DCTRL = 0; osalSysUnlock(); /* Wait until interrupt flags to be cleared.*/ /*while (((DMA2->LISR) >> (sdcp->dma->ishift)) & STM32_DMA_ISR_TCIF) dmaStreamClearInterrupt(sdcp->dma);*/ #else /* Waits for transfer completion at DMA level, then the stream is disabled and cleared.*/ dmaWaitCompletion(sdcp->dma); sdcp->sdio->ICR = STM32_SDIO_ICR_ALL_FLAGS; sdcp->sdio->DCTRL = 0; osalSysUnlock(); #endif /* Finalize transaction.*/ if (n > 1) return sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_STOP_TRANSMISSION, 0, resp); return HAL_SUCCESS; }
/** * @brief Generate reset pulse on bus. * * @param[in] owp pointer to the @p onewireDriver object * * @return Bool flag denoting device presence. * @retval true There is at least one device on bus. */ bool onewireReset(onewireDriver *owp) { PWMDriver *pwmd; PWMConfig *pwmcfg; size_t mch, sch; osalDbgCheck(NULL != owp); osalDbgAssert(owp->reg.state == ONEWIRE_READY, "Invalid state"); /* short circuit on bus or any other device transmit data */ if (PAL_LOW == ow_read_bit(owp)) return false; pwmd = owp->config->pwmd; pwmcfg = owp->config->pwmcfg; mch = owp->config->master_channel; sch = owp->config->sample_channel; pwmcfg->period = ONEWIRE_RESET_LOW_WIDTH + ONEWIRE_RESET_SAMPLE_WIDTH; pwmcfg->callback = NULL; pwmcfg->channels[mch].callback = NULL; pwmcfg->channels[mch].mode = owp->config->pwmmode; pwmcfg->channels[sch].callback = pwm_reset_cb; pwmcfg->channels[sch].mode = PWM_OUTPUT_ACTIVE_LOW; ow_bus_active(owp); osalSysLock(); pwmEnableChannelI(pwmd, mch, ONEWIRE_RESET_LOW_WIDTH); pwmEnableChannelI(pwmd, sch, ONEWIRE_RESET_SAMPLE_WIDTH); pwmEnableChannelNotificationI(pwmd, sch); osalThreadSuspendS(&owp->thread); osalSysUnlock(); ow_bus_idle(owp); /* wait until slave release bus to discriminate short circuit condition */ osalThreadSleepMicroseconds(500); return (PAL_HIGH == ow_read_bit(owp)) && (true == owp->reg.slave_present); }
/** * @brief Read some bites from slave device. * * @param[in] owp pointer to the @p onewireDriver object * @param[out] rxbuf pointer to the buffer for read data * @param[in] rxbytes amount of data to be received */ void onewireRead(onewireDriver *owp, uint8_t *rxbuf, size_t rxbytes) { PWMDriver *pwmd; PWMConfig *pwmcfg; size_t mch, sch; osalDbgCheck((NULL != owp) && (NULL != rxbuf)); osalDbgCheck((rxbytes > 0) && (rxbytes <= ONEWIRE_MAX_TRANSACTION_LEN)); osalDbgAssert(owp->reg.state == ONEWIRE_READY, "Invalid state"); /* Buffer zeroing. This is important because of driver collects bits using |= operation.*/ memset(rxbuf, 0, rxbytes); pwmd = owp->config->pwmd; pwmcfg = owp->config->pwmcfg; mch = owp->config->master_channel; sch = owp->config->sample_channel; owp->reg.bit = 0; owp->reg.final_timeslot = false; owp->buf = rxbuf; owp->reg.bytes = rxbytes; pwmcfg->period = ONEWIRE_ZERO_WIDTH + ONEWIRE_RECOVERY_WIDTH; pwmcfg->callback = NULL; pwmcfg->channels[mch].callback = NULL; pwmcfg->channels[mch].mode = owp->config->pwmmode; pwmcfg->channels[sch].callback = pwm_read_bit_cb; pwmcfg->channels[sch].mode = PWM_OUTPUT_ACTIVE_LOW; ow_bus_active(owp); osalSysLock(); pwmEnableChannelI(pwmd, mch, ONEWIRE_ONE_WIDTH); pwmEnableChannelI(pwmd, sch, ONEWIRE_SAMPLE_WIDTH); pwmEnableChannelNotificationI(pwmd, sch); osalThreadSuspendS(&owp->thread); osalSysUnlock(); ow_bus_idle(owp); }
/** * @brief Performs tree search on bus. * @note This function does internal 1-wire reset calls every search * iteration. * * @param[in] owp pointer to a @p OWDriver object * @param[out] result pointer to buffer for discovered ROMs * @param[in] max_rom_cnt buffer size in ROMs count for overflow prevention * * @return Count of discovered ROMs. May be more than max_rom_cnt. * @retval 0 no ROMs found or communication error occurred. */ size_t onewireSearchRom(onewireDriver *owp, uint8_t *result, size_t max_rom_cnt) { PWMDriver *pwmd; PWMConfig *pwmcfg; uint8_t cmd; size_t mch, sch; osalDbgCheck(NULL != owp); osalDbgAssert(ONEWIRE_READY == owp->reg.state, "Invalid state"); osalDbgCheck((max_rom_cnt <= 256) && (max_rom_cnt > 0)); pwmd = owp->config->pwmd; pwmcfg = owp->config->pwmcfg; cmd = ONEWIRE_CMD_SEARCH_ROM; mch = owp->config->master_channel; sch = owp->config->sample_channel; search_clean_start(&owp->search_rom); do { /* every search must be started from reset pulse */ if (false == onewireReset(owp)) return 0; /* initialize buffer to store result */ if (owp->search_rom.reg.devices_found >= max_rom_cnt) owp->search_rom.retbuf = result + 8*(max_rom_cnt-1); else owp->search_rom.retbuf = result + 8*owp->search_rom.reg.devices_found; memset(owp->search_rom.retbuf, 0, 8); /* clean iteration state */ search_clean_iteration(&owp->search_rom); /**/ onewireWrite(&OWD1, &cmd, 1, 0); /* Reconfiguration always needed because of previous call onewireWrite.*/ pwmcfg->period = ONEWIRE_ZERO_WIDTH + ONEWIRE_RECOVERY_WIDTH; pwmcfg->callback = NULL; pwmcfg->channels[mch].callback = NULL; pwmcfg->channels[mch].mode = owp->config->pwmmode; pwmcfg->channels[sch].callback = pwm_search_rom_cb; pwmcfg->channels[sch].mode = PWM_OUTPUT_ACTIVE_LOW; ow_bus_active(owp); osalSysLock(); pwmEnableChannelI(pwmd, mch, ONEWIRE_ONE_WIDTH); pwmEnableChannelI(pwmd, sch, ONEWIRE_SAMPLE_WIDTH); pwmEnableChannelNotificationI(pwmd, sch); osalThreadSuspendS(&owp->thread); osalSysUnlock(); ow_bus_idle(owp); if (ONEWIRE_SEARCH_ROM_ERROR != owp->search_rom.reg.result) { /* check CRC and return 0 (0 == error) if mismatch */ if (owp->search_rom.retbuf[7] != onewireCRC(owp->search_rom.retbuf, 7)) return 0; /* store cached result for usage in next iteration */ memcpy(owp->search_rom.prev_path, owp->search_rom.retbuf, 8); } } while (ONEWIRE_SEARCH_ROM_SUCCESS == owp->search_rom.reg.result); /**/ if (ONEWIRE_SEARCH_ROM_ERROR == owp->search_rom.reg.result) return 0; else return owp->search_rom.reg.devices_found; }
/* Idle requests timer code * callback (called from ISR, unlocked state) */ static void keyboard_idle_timer_cb(void *arg) { USBDriver *usbp = (USBDriver *)arg; osalSysLockFromISR(); /* check that the states of things are as they're supposed to */ if(usbGetDriverStateI(usbp) != USB_ACTIVE) { /* do not rearm the timer, should be enabled on IDLE request */ osalSysUnlockFromISR(); return; } #ifdef NKRO_ENABLE if(!keymap_config.nkro && keyboard_idle) { #else /* NKRO_ENABLE */ if(keyboard_idle) { #endif /* NKRO_ENABLE */ /* TODO: are we sure we want the KBD_ENDPOINT? */ if(!usbGetTransmitStatusI(usbp, KEYBOARD_IN_EPNUM)) { usbStartTransmitI(usbp, KEYBOARD_IN_EPNUM, (uint8_t *)&keyboard_report_sent, KEYBOARD_EPSIZE); } /* rearm the timer */ chVTSetI(&keyboard_idle_timer, 4*MS2ST(keyboard_idle), keyboard_idle_timer_cb, (void *)usbp); } /* do not rearm the timer if the condition above fails * it should be enabled again on either IDLE or SET_PROTOCOL requests */ osalSysUnlockFromISR(); } /* LED status */ uint8_t keyboard_leds(void) { return (uint8_t)(keyboard_led_stats & 0xFF); } /* prepare and start sending a report IN * not callable from ISR or locked state */ void send_keyboard(report_keyboard_t *report) { osalSysLock(); if(usbGetDriverStateI(&USB_DRIVER) != USB_ACTIVE) { osalSysUnlock(); return; } osalSysUnlock(); #ifdef NKRO_ENABLE if(keymap_config.nkro) { /* NKRO protocol */ /* need to wait until the previous packet has made it through */ /* can rewrite this using the synchronous API, then would wait * until *after* the packet has been transmitted. I think * this is more efficient */ /* busy wait, should be short and not very common */ osalSysLock(); if(usbGetTransmitStatusI(&USB_DRIVER, NKRO_IN_EPNUM)) { /* Need to either suspend, or loop and call unlock/lock during * every iteration - otherwise the system will remain locked, * no interrupts served, so USB not going through as well. * Note: for suspend, need USB_USE_WAIT == TRUE in halconf.h */ osalThreadSuspendS(&(&USB_DRIVER)->epc[NKRO_IN_EPNUM]->in_state->thread); } usbStartTransmitI(&USB_DRIVER, NKRO_IN_EPNUM, (uint8_t *)report, sizeof(report_keyboard_t)); osalSysUnlock(); } else #endif /* NKRO_ENABLE */ { /* boot protocol */ /* need to wait until the previous packet has made it through */ /* busy wait, should be short and not very common */ osalSysLock(); if(usbGetTransmitStatusI(&USB_DRIVER, KEYBOARD_IN_EPNUM)) { /* Need to either suspend, or loop and call unlock/lock during * every iteration - otherwise the system will remain locked, * no interrupts served, so USB not going through as well. * Note: for suspend, need USB_USE_WAIT == TRUE in halconf.h */ osalThreadSuspendS(&(&USB_DRIVER)->epc[KEYBOARD_IN_EPNUM]->in_state->thread); } usbStartTransmitI(&USB_DRIVER, KEYBOARD_IN_EPNUM, (uint8_t *)report, KEYBOARD_EPSIZE); osalSysUnlock(); } keyboard_report_sent = *report; }
/** * @brief Put calling thread in suspend and switch driver state * * @param[in] nandp pointer to the @p NANDDriver object */ static void nand_lld_suspend_thread(NANDDriver *nandp) { osalThreadSuspendS(&nandp->thread); }