From ab6c7494da3eeb5fe21ef739e9ede36ff16e3ac9 Mon Sep 17 00:00:00 2001 From: JojoS62 Date: Wed, 31 Oct 2018 15:51:30 +0100 Subject: [PATCH 01/13] added component SDIO to DISCO_F469NI --- targets/targets.json | 1 + 1 file changed, 1 insertion(+) diff --git a/targets/targets.json b/targets/targets.json index d9dc09cb612..f4a6cab9958 100644 --- a/targets/targets.json +++ b/targets/targets.json @@ -1952,6 +1952,7 @@ "components": ["QSPIF"], "inherits": ["FAMILY_STM32"], "supported_form_factors": ["ARDUINO"], + "components": ["SDIO"], "core": "Cortex-M4F", "extra_labels_add": ["STM32F4", "STM32F469", "STM32F469NI", "STM32F469xI", "STM32F469xx"], "config": { From 9362c0a9d44ff0ef2d0ff2b0a22def7a03fc1cb5 Mon Sep 17 00:00:00 2001 From: JojoS62 Date: Wed, 31 Oct 2018 15:53:38 +0100 Subject: [PATCH 02/13] add low level driver for SDIO interface intermediate layer between HAL and C++ API. Can be used for other targets to implement SDIO functions --- .../TARGET_STM/TARGET_STM32F4/sdio_device.c | 469 ++++++++++++++++++ .../TARGET_STM/TARGET_STM32F4/sdio_device.h | 111 +++++ 2 files changed, 580 insertions(+) create mode 100644 targets/TARGET_STM/TARGET_STM32F4/sdio_device.c create mode 100644 targets/TARGET_STM/TARGET_STM32F4/sdio_device.h diff --git a/targets/TARGET_STM/TARGET_STM32F4/sdio_device.c b/targets/TARGET_STM/TARGET_STM32F4/sdio_device.c new file mode 100644 index 00000000000..78c19985876 --- /dev/null +++ b/targets/TARGET_STM/TARGET_STM32F4/sdio_device.c @@ -0,0 +1,469 @@ +/** + * + * This sourcecode is derived from STMicroelectronics CubeMX generated code. + * It is modified to work with mbed RTOS. + * + ****************************************************************************** + * @file bsp_driver_sd.c for F4 (based on stm324x9i_eval_sd.c) + * @brief This file includes a generic uSD card driver. + ****************************************************************************** + * This notice applies to any and all portions of this file + * that are not between comment pairs USER CODE BEGIN and + * USER CODE END. Other portions of this file, whether + * inserted by the user or by software development tools + * are owned by their respective copyright owners. + * + * Copyright (c) 2018 STMicroelectronics International N.V. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted, provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of other + * contributors to this software may be used to endorse or promote products + * derived from this software without specific written permission. + * 4. This software, including modifications and/or derivative works of this + * software, must execute solely and exclusively on microcontroller or + * microprocessor devices manufactured by or for STMicroelectronics. + * 5. Redistribution and use of this software other than as permitted under + * this license is void and will automatically terminate your rights under + * this license. + * + * THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY + * RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT + * SHALL STMICROELECTRONICS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +#include "sdio_device.h" +#include "platform/mbed_error.h" + +/* Extern variables ---------------------------------------------------------*/ + +SD_HandleTypeDef hsd; +DMA_HandleTypeDef hdma_sdio_rx; +DMA_HandleTypeDef hdma_sdio_tx; + +// simple flags for DMA pending signaling +volatile uint8_t SD_DMA_ReadPendingState = SD_TRANSFER_OK; +volatile uint8_t SD_DMA_WritePendingState = SD_TRANSFER_OK; + + +/* DMA Handlers are global, there is only one SDIO interface */ + +/** +* @brief This function handles SDIO global interrupt. +*/ +void _SDIO_IRQHandler(void) +{ + HAL_SD_IRQHandler(&hsd); +} + +/** +* @brief This function handles DMAx stream_n global interrupt. DMA Rx +*/ +void _DMA_Stream_Rx_IRQHandler(void) +{ + HAL_DMA_IRQHandler(hsd.hdmarx); +} + +/** +* @brief This function handles DMAx stream_n global interrupt. DMA Tx +*/ +void _DMA_Stream_Tx_IRQHandler(void) +{ + HAL_DMA_IRQHandler(hsd.hdmatx); +} + +/** + * + * @param hsd: Handle for SD handle Structure definition + */ +void HAL_SD_MspInit(SD_HandleTypeDef *hsd) { + IRQn_Type IRQn; + GPIO_InitTypeDef GPIO_InitStruct; + + if (hsd->Instance == SDIO) { + /* Peripheral clock enable */ + __HAL_RCC_SDIO_CLK_ENABLE(); + __HAL_RCC_DMA2_CLK_ENABLE(); + + /* Enable GPIOs clock */ + __HAL_RCC_GPIOC_CLK_ENABLE(); + __HAL_RCC_GPIOD_CLK_ENABLE(); + + /**SDIO GPIO Configuration + PC12 ------> SDIO_CK + PC11 ------> SDIO_D3 + PC10 ------> SDIO_D2 + PD2 ------> SDIO_CMD + PC9 ------> SDIO_D1 + PC8 ------> SDIO_D0 + */ + GPIO_InitStruct.Pin = GPIO_PIN_12 | GPIO_PIN_11 | GPIO_PIN_10 | GPIO_PIN_9 | GPIO_PIN_8; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_PULLUP; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + GPIO_InitStruct.Alternate = GPIO_AF12_SDIO; + HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); + + GPIO_InitStruct.Pin = GPIO_PIN_2; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_PULLUP; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + GPIO_InitStruct.Alternate = GPIO_AF12_SDIO; + HAL_GPIO_Init(GPIOD, &GPIO_InitStruct); + + /* NVIC configuration for SDIO interrupts */ + IRQn = SDIO_IRQn; + HAL_NVIC_SetPriority(IRQn, 0x0E, 0); + NVIC_SetVector(IRQn, (uint32_t) &_SDIO_IRQHandler); + HAL_NVIC_EnableIRQ(IRQn); + + /* SDIO DMA Init */ + /* SDIO_RX Init */ + hdma_sdio_rx.Instance = DMA2_Stream3; + hdma_sdio_rx.Init.Channel = DMA_CHANNEL_4; + hdma_sdio_rx.Init.Direction = DMA_PERIPH_TO_MEMORY; + hdma_sdio_rx.Init.PeriphInc = DMA_PINC_DISABLE; + hdma_sdio_rx.Init.MemInc = DMA_MINC_ENABLE; + hdma_sdio_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD; + hdma_sdio_rx.Init.MemDataAlignment = DMA_MDATAALIGN_WORD; + hdma_sdio_rx.Init.Mode = DMA_PFCTRL; + hdma_sdio_rx.Init.Priority = DMA_PRIORITY_LOW; + hdma_sdio_rx.Init.FIFOMode = DMA_FIFOMODE_ENABLE; + hdma_sdio_rx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; + hdma_sdio_rx.Init.MemBurst = DMA_MBURST_INC4; + hdma_sdio_rx.Init.PeriphBurst = DMA_PBURST_INC4; + if (HAL_DMA_Init(&hdma_sdio_rx) != HAL_OK) { + error("SDIO DMA Init error at %d in %s", __FILE__, __LINE__); + } + + __HAL_LINKDMA(hsd, hdmarx, hdma_sdio_rx); + + /* Deinitialize the stream for new transfer */ + HAL_DMA_DeInit(&hdma_sdio_rx); + + /* Configure the DMA stream */ + HAL_DMA_Init(&hdma_sdio_rx); + + + /* SDIO_TX Init */ + hdma_sdio_tx.Instance = DMA2_Stream6; + hdma_sdio_tx.Init.Channel = DMA_CHANNEL_4; + hdma_sdio_tx.Init.Direction = DMA_MEMORY_TO_PERIPH; + hdma_sdio_tx.Init.PeriphInc = DMA_PINC_DISABLE; + hdma_sdio_tx.Init.MemInc = DMA_MINC_ENABLE; + hdma_sdio_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD; + hdma_sdio_tx.Init.MemDataAlignment = DMA_MDATAALIGN_WORD; + hdma_sdio_tx.Init.Mode = DMA_PFCTRL; + hdma_sdio_tx.Init.Priority = DMA_PRIORITY_LOW; + hdma_sdio_tx.Init.FIFOMode = DMA_FIFOMODE_ENABLE; + hdma_sdio_tx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; + hdma_sdio_tx.Init.MemBurst = DMA_MBURST_INC4; + hdma_sdio_tx.Init.PeriphBurst = DMA_PBURST_INC4; + if (HAL_DMA_Init(&hdma_sdio_tx) != HAL_OK) { + error("SDIO DMA Init error at %d in %s", __FILE__, __LINE__); + } + + __HAL_LINKDMA(hsd, hdmatx, hdma_sdio_tx); + + /* Deinitialize the stream for new transfer */ + HAL_DMA_DeInit(&hdma_sdio_tx); + + /* Configure the DMA stream */ + HAL_DMA_Init(&hdma_sdio_tx); + + /* Enable NVIC for DMA transfer complete interrupts */ + IRQn = DMA2_Stream3_IRQn; + NVIC_SetVector(IRQn, (uint32_t) &_DMA_Stream_Rx_IRQHandler); + HAL_NVIC_SetPriority(IRQn, 0x0F, 0); + HAL_NVIC_EnableIRQ(IRQn); + + IRQn = DMA2_Stream6_IRQn; + NVIC_SetVector(IRQn, (uint32_t) &_DMA_Stream_Tx_IRQHandler); + HAL_NVIC_SetPriority(IRQn, 0x0F, 0); + HAL_NVIC_EnableIRQ(IRQn); + } +} + +/** + * + * @param hsd: Handle for SD handle Structure definition + */ +void HAL_SD_MspDeInit(SD_HandleTypeDef *hsd) { + + if (hsd->Instance == SDIO) { + /* Peripheral clock disable */ + __HAL_RCC_SDIO_CLK_DISABLE(); + + /**SDIO GPIO Configuration + PC12 ------> SDIO_CK + PC11 ------> SDIO_D3 + PC10 ------> SDIO_D2 + PD2 ------> SDIO_CMD + PC9 ------> SDIO_D1 + PC8 ------> SDIO_D0 + */ + HAL_GPIO_DeInit(GPIOC, GPIO_PIN_12 | GPIO_PIN_11 | GPIO_PIN_10 | GPIO_PIN_9 | GPIO_PIN_8); + + HAL_GPIO_DeInit(GPIOD, GPIO_PIN_2); + + /* SDIO DMA DeInit */ + HAL_DMA_DeInit(hsd->hdmarx); + HAL_DMA_DeInit(hsd->hdmatx); + } + +} + +/** + * @brief DeInitializes the SD MSP. + * @param hsd: SD handle + * @param Params : pointer on additional configuration parameters, can be NULL. + */ +__weak void SD_MspDeInit(SD_HandleTypeDef *hsd, void *Params) { + static DMA_HandleTypeDef dma_rx_handle; + static DMA_HandleTypeDef dma_tx_handle; + + /* Disable NVIC for DMA transfer complete interrupts */ + HAL_NVIC_DisableIRQ(DMA2_Stream3_IRQn); + HAL_NVIC_DisableIRQ(DMA2_Stream6_IRQn); + + /* Deinitialize the stream for new transfer */ + dma_rx_handle.Instance = DMA2_Stream3; + HAL_DMA_DeInit(&dma_rx_handle); + + /* Deinitialize the stream for new transfer */ + dma_tx_handle.Instance = DMA2_Stream6; + HAL_DMA_DeInit(&dma_tx_handle); + + /* Disable NVIC for SDIO interrupts */ + HAL_NVIC_DisableIRQ(SDIO_IRQn); + + /* Disable SDIO clock */ + __HAL_RCC_SDIO_CLK_DISABLE(); +} + +/** + * @brief Initializes the SD card device. + * @retval SD status + */ +uint8_t SD_Init(void) { + uint8_t sd_state = MSD_OK; + + hsd.Instance = SDIO; + hsd.Init.ClockEdge = SDIO_CLOCK_EDGE_RISING; + hsd.Init.ClockBypass = SDIO_CLOCK_BYPASS_DISABLE; + hsd.Init.ClockPowerSave = SDIO_CLOCK_POWER_SAVE_DISABLE; + hsd.Init.BusWide = SDIO_BUS_WIDE_1B; + hsd.Init.HardwareFlowControl = SDIO_HARDWARE_FLOW_CONTROL_DISABLE; + hsd.Init.ClockDiv = 0; + // !!! clock must be slower in polling mode if compiled w/o optimization !!! + + /* HAL SD initialization */ + sd_state = HAL_SD_Init(&hsd); + /* Configure SD Bus width (4 bits mode selected) */ + if (sd_state == MSD_OK) { + /* Enable wide operation */ + if (HAL_SD_ConfigWideBusOperation(&hsd, SDIO_BUS_WIDE_4B) != HAL_OK) { + sd_state = MSD_ERROR; + } + } + + return sd_state; +} + +/** + * @brief DeInitializes the SD card device. + * @retval SD status + */ +uint8_t SD_DeInit(void) { + uint8_t sd_state = MSD_OK; + + hsd.Instance = SDIO; + + /* HAL SD deinitialization */ + if (HAL_SD_DeInit(&hsd) != HAL_OK) { + sd_state = MSD_ERROR; + } + + /* Msp SD deinitialization */ + hsd.Instance = SDIO; + SD_MspDeInit(&hsd, NULL); + + return sd_state; +} + +/** + * @brief Reads block(s) from a specified address in an SD card, in polling mode. + * @param pData: Pointer to the buffer that will contain the data to transmit + * @param ReadAddr: Address from where data is to be read + * @param NumOfBlocks: Number of SD blocks to read + * @param Timeout: Timeout for read operation + * @retval SD status + */ +uint8_t SD_ReadBlocks(uint32_t *pData, uint32_t ReadAddr, uint32_t NumOfBlocks, uint32_t Timeout) { + uint8_t sd_state = MSD_OK; + + if (HAL_SD_ReadBlocks(&hsd, (uint8_t *) pData, ReadAddr, NumOfBlocks, Timeout) != HAL_OK) { + sd_state = MSD_ERROR; + } + + return sd_state; +} + +/** + * @brief Writes block(s) to a specified address in an SD card, in polling mode. + * @param pData: Pointer to the buffer that will contain the data to transmit + * @param WriteAddr: Address from where data is to be written + * @param NumOfBlocks: Number of SD blocks to write + * @param Timeout: Timeout for write operation + * @retval SD status + */ +uint8_t SD_WriteBlocks(uint32_t *pData, uint32_t WriteAddr, uint32_t NumOfBlocks, uint32_t Timeout) { + uint8_t sd_state = MSD_OK; + + if (HAL_SD_WriteBlocks(&hsd, (uint8_t *) pData, WriteAddr, NumOfBlocks, Timeout) != HAL_OK) { + sd_state = MSD_ERROR; + } + + return sd_state; +} + +/** + * @brief Reads block(s) from a specified address in an SD card, in DMA mode. + * @param pData: Pointer to the buffer that will contain the data to transmit + * @param ReadAddr: Address from where data is to be read + * @param NumOfBlocks: Number of SD blocks to read + * @retval SD status + */ +uint8_t SD_ReadBlocks_DMA(uint32_t *pData, uint32_t ReadAddr, uint32_t NumOfBlocks) { + uint8_t sd_state = MSD_OK; + SD_DMA_ReadPendingState = SD_TRANSFER_BUSY; + + /* Read block(s) in DMA transfer mode */ + if (HAL_SD_ReadBlocks_DMA(&hsd, (uint8_t *) pData, ReadAddr, NumOfBlocks) != HAL_OK) { + sd_state = MSD_ERROR; + SD_DMA_ReadPendingState = SD_TRANSFER_OK; + } + + return sd_state; +} + +/** + * @brief Writes block(s) to a specified address in an SD card, in DMA mode. + * @param pData: Pointer to the buffer that will contain the data to transmit + * @param WriteAddr: Address from where data is to be written + * @param NumOfBlocks: Number of SD blocks to write + * @retval SD status + */ +uint8_t SD_WriteBlocks_DMA(uint32_t *pData, uint32_t WriteAddr, uint32_t NumOfBlocks) { + uint8_t sd_state = MSD_OK; + SD_DMA_WritePendingState = SD_TRANSFER_BUSY; + + /* Write block(s) in DMA transfer mode */ + if (HAL_SD_WriteBlocks_DMA(&hsd, (uint8_t *) pData, WriteAddr, NumOfBlocks) != HAL_OK) { + sd_state = MSD_ERROR; + SD_DMA_WritePendingState = SD_TRANSFER_OK; + } + + return sd_state; +} + +/** + * @brief Erases the specified memory area of the given SD card. + * @param StartAddr: Start byte address + * @param EndAddr: End byte address + * @retval SD status + */ +uint8_t SD_Erase(uint32_t StartAddr, uint32_t EndAddr) { + uint8_t sd_state = MSD_OK; + + if (HAL_SD_Erase(&hsd, StartAddr, EndAddr) != HAL_OK) { + sd_state = MSD_ERROR; + } + + return sd_state; +} + +/** + * @brief Gets the current SD card data status. + * @param None + * @retval Data transfer state. + * This value can be one of the following values: + * @arg SD_TRANSFER_OK: No data transfer is acting + * @arg SD_TRANSFER_BUSY: Data transfer is acting + */ +uint8_t SD_GetCardState(void) { + return ((HAL_SD_GetCardState(&hsd) == HAL_SD_CARD_TRANSFER) ? SD_TRANSFER_OK : SD_TRANSFER_BUSY); +} + +/** + * @brief Get SD information about specific SD card. + * @param CardInfo: Pointer to HAL_SD_CardInfoTypedef structure + * @retval None + */ +void SD_GetCardInfo(HAL_SD_CardInfoTypeDef *CardInfo) { + /* Get SD card Information */ + HAL_SD_GetCardInfo(&hsd, CardInfo); +} + +/** + * @brief Check if a DMA operation is pending + * @retval DMA operation is pending + * This value can be one of the following values: + * @arg SD_TRANSFER_OK: No data transfer is acting + * @arg SD_TRANSFER_BUSY: Data transfer is acting + */ +uint8_t SD_DMA_ReadPending(void) { + return SD_DMA_ReadPendingState; +} + +/** + * @brief Check if a DMA operation is pending + * @retval DMA operation is pending + * This value can be one of the following values: + * @arg SD_TRANSFER_OK: No data transfer is acting + * @arg SD_TRANSFER_BUSY: Data transfer is acting + */ +uint8_t SD_DMA_WritePending(void) { + return SD_DMA_WritePendingState; +} + +/** + * @brief Rx Transfer completed callbacks + * @param hsd Pointer SD handle + * @retval None + */ +void HAL_SD_RxCpltCallback(SD_HandleTypeDef *hsd) +{ + SD_DMA_ReadPendingState = SD_TRANSFER_OK; +} + +/** + * @brief Tx Transfer completed callbacks + * @param hsd Pointer to SD handle + * @retval None + */ +void HAL_SD_TxCpltCallback(SD_HandleTypeDef *hsd) +{ + SD_DMA_WritePendingState = SD_TRANSFER_OK; +} + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/targets/TARGET_STM/TARGET_STM32F4/sdio_device.h b/targets/TARGET_STM/TARGET_STM32F4/sdio_device.h new file mode 100644 index 00000000000..93b34baa57e --- /dev/null +++ b/targets/TARGET_STM/TARGET_STM32F4/sdio_device.h @@ -0,0 +1,111 @@ +/** + * + * This sourcecode is derived from STMicroelectronics CubeMX generated code. + * It is modified to work with mbed RTOS. + * + ****************************************************************************** + * @file bsp_driver_sd.h for F4 (based on stm324x9i_eval_sd.h) + * @brief This file contains the common defines and functions prototypes for + * the bsp_driver_sd.c driver. + ****************************************************************************** + * This notice applies to any and all portions of this file + * that are not between comment pairs USER CODE BEGIN and + * USER CODE END. Other portions of this file, whether + * inserted by the user or by software development tools + * are owned by their respective copyright owners. + * + * Copyright (c) 2018 STMicroelectronics International N.V. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted, provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of other + * contributors to this software may be used to endorse or promote products + * derived from this software without specific written permission. + * 4. This software, including modifications and/or derivative works of this + * software, must execute solely and exclusively on microcontroller or + * microprocessor devices manufactured by or for STMicroelectronics. + * 5. Redistribution and use of this software other than as permitted under + * this license is void and will automatically terminate your rights under + * this license. + * + * THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY + * RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT + * SHALL STMICROELECTRONICS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F4_SD_H +#define __STM32F4_SD_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f4xx_hal.h" + +extern SD_HandleTypeDef hsd; + +/* Exported types --------------------------------------------------------*/ +/** + * @brief SD Card information structure + */ +#define BSP_SD_CardInfo HAL_SD_CardInfoTypeDef + +/* Exported constants --------------------------------------------------------*/ +/** + * @brief SD status structure definition + */ +#define MSD_OK ((uint8_t)0x00) +#define MSD_ERROR ((uint8_t)0x01) + +/** + * @brief SD transfer state definition + */ +#define SD_TRANSFER_OK ((uint8_t)0x00) +#define SD_TRANSFER_BUSY ((uint8_t)0x01) + +/* Exported functions --------------------------------------------------------*/ +uint8_t SD_Init(void); +uint8_t SD_DeInit(void); +uint8_t SD_ReadBlocks(uint32_t *pData, uint32_t ReadAddr, uint32_t NumOfBlocks, uint32_t Timeout); +uint8_t SD_WriteBlocks(uint32_t *pData, uint32_t WriteAddr, uint32_t NumOfBlocks, uint32_t Timeout); +uint8_t SD_ReadBlocks_DMA(uint32_t *pData, uint32_t ReadAddr, uint32_t NumOfBlocks); +uint8_t SD_WriteBlocks_DMA(uint32_t *pData, uint32_t WriteAddr, uint32_t NumOfBlocks); +uint8_t SD_DMA_ReadPending(void); +uint8_t SD_DMA_WritePending(void); +uint8_t SD_Erase(uint32_t StartAddr, uint32_t EndAddr); + +uint8_t SD_GetCardState(void); +void SD_GetCardInfo(HAL_SD_CardInfoTypeDef *CardInfo); + +/* callback function for DMA Rx/Tx completete, called by HAL SDIO interrupt handler */ +void HAL_SD_TxCpltCallback(SD_HandleTypeDef *hsd); +void HAL_SD_RxCpltCallback(SD_HandleTypeDef *hsd); + + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F4_SD_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ From fe248ae1d825ca0d48924317cd2d701550d81602 Mon Sep 17 00:00:00 2001 From: JojoS62 Date: Wed, 31 Oct 2018 15:54:23 +0100 Subject: [PATCH 03/13] add SDIOBlockdevice API based on BlockDevice class --- .../COMPONENT_SDIO/SDIOBlockDevice.cpp | 307 ++++++++++++++++++ .../COMPONENT_SDIO/SDIOBlockDevice.h | 148 +++++++++ 2 files changed, 455 insertions(+) create mode 100644 components/storage/blockdevice/COMPONENT_SDIO/SDIOBlockDevice.cpp create mode 100644 components/storage/blockdevice/COMPONENT_SDIO/SDIOBlockDevice.h diff --git a/components/storage/blockdevice/COMPONENT_SDIO/SDIOBlockDevice.cpp b/components/storage/blockdevice/COMPONENT_SDIO/SDIOBlockDevice.cpp new file mode 100644 index 00000000000..7dfb0b0e686 --- /dev/null +++ b/components/storage/blockdevice/COMPONENT_SDIO/SDIOBlockDevice.cpp @@ -0,0 +1,307 @@ +/* mbed Microcontroller Library + * Copyright (c) 2017 ARM Limited + * + * 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. + */ + + +#include +#include "platform/mbed_debug.h" +#include "platform/mbed_wait_api.h" +#include "SDIOBlockDevice.h" + +namespace mbed { + +/* + * defines + */ + +/* + * TRANSFER_MODE : must be either DMA or POLLING + * ATTENTION: in POLLING mode, HAL code is slow and SDIO_CLOCK must be reduced! + */ +#define TRANSFER_MODE_DMA (0) +#define TRANSFER_MODE_POLLING (1) +#define TRANSFER_MODE TRANSFER_MODE_DMA + +#define SD_DBG 0 /*!< 1 - Enable debugging */ +#define SD_CMD_TRACE 0 /*!< 1 - Enable SD command tracing */ + +#define SD_BLOCK_DEVICE_ERROR_WOULD_BLOCK -5001 /*!< operation would block */ +#define SD_BLOCK_DEVICE_ERROR_UNSUPPORTED -5002 /*!< unsupported operation */ +#define SD_BLOCK_DEVICE_ERROR_PARAMETER -5003 /*!< invalid parameter */ +#define SD_BLOCK_DEVICE_ERROR_NO_INIT -5004 /*!< uninitialized */ +#define SD_BLOCK_DEVICE_ERROR_NO_DEVICE -5005 /*!< device is missing or not connected */ +#define SD_BLOCK_DEVICE_ERROR_WRITE_PROTECTED -5006 /*!< write protected */ +#define SD_BLOCK_DEVICE_ERROR_UNUSABLE -5007 /*!< unusable card */ +#define SD_BLOCK_DEVICE_ERROR_NO_RESPONSE -5008 /*!< No response from device */ +#define SD_BLOCK_DEVICE_ERROR_CRC -5009 /*!< CRC error */ +#define SD_BLOCK_DEVICE_ERROR_ERASE -5010 /*!< Erase error: reset/sequence */ +#define SD_BLOCK_DEVICE_ERROR_WRITE -5011 /*!< SPI Write error: !SPI_DATA_ACCEPTED */ +#define SD_BLOCK_DEVICE_ERROR_UNSUPPORTED_BLOCKSIZE -5012 /*!< unsupported blocksize, only 512 byte supported */ +#define SD_BLOCK_DEVICE_ERROR_READBLOCKS -5013 /*!< read data blocks from SD failed */ +#define SD_BLOCK_DEVICE_ERROR_WRITEBLOCKS -5014 /*!< write data blocks to SD failed */ +#define SD_BLOCK_DEVICE_ERROR_ERASEBLOCKS -5015 /*!< erase data blocks to SD failed */ + +#define BLOCK_SIZE_HC 512 /*!< Block size supported for SD card is 512 bytes */ + +// Types +#define SDCARD_NONE 0 /**< No card is present */ +#define SDCARD_V1 1 /**< v1.x Standard Capacity */ +#define SDCARD_V2 2 /**< v2.x Standard capacity SD card */ +#define SDCARD_V2HC 3 /**< v2.x High capacity SD card */ +#define CARD_UNKNOWN 4 /**< Unknown or unsupported card */ + +#ifndef MBED_CONF_SD_TIMEOUT +# define MBED_CONF_SD_TIMEOUT (30 * 1000) /* ms */ +#endif + +SDIOBlockDevice::SDIOBlockDevice(PinName cardDetect) : + _cardDetect(cardDetect), + _is_initialized(0), + _sectors(0), + _sd_state(0), + _init_ref_count(0) +{ + _card_type = SDCARD_NONE; + + // Only HC block size is supported. + _block_size = BLOCK_SIZE_HC; + _erase_size = BLOCK_SIZE_HC; +} + +SDIOBlockDevice::~SDIOBlockDevice() { + if (_is_initialized) { + deinit(); + } +} + +int SDIOBlockDevice::init() { + debug_if(SD_DBG, "init Card...\r\n"); + if (isPresent() == false) { + return SD_BLOCK_DEVICE_ERROR_NO_DEVICE; + } + + if (!_is_initialized) { + _sd_state = SD_Init(); + if (BD_ERROR_OK != _sd_state) + return BD_ERROR_DEVICE_ERROR; + + SD_GetCardInfo(&_cardInfo); + _is_initialized = true; + debug_if(SD_DBG, "SD initialized: type: %d version: %d class: %d\n", + _cardInfo.CardType, _cardInfo.CardVersion, _cardInfo.Class); + debug_if(SD_DBG, "SD size: %d MB\n", + _cardInfo.LogBlockNbr / 2 / 1024); + } + + // get sectors count from cardinfo + _sectors = _cardInfo.LogBlockNbr; + if (BLOCK_SIZE_HC != _cardInfo.BlockSize) { + return SD_BLOCK_DEVICE_ERROR_UNSUPPORTED_BLOCKSIZE; + } + + return BD_ERROR_OK; +} + + +int SDIOBlockDevice::deinit() { + debug_if(SD_DBG, "deinit Card...\r\n"); + _sd_state = SD_DeInit(); + _is_initialized = false; + + return BD_ERROR_OK; +} + +int SDIOBlockDevice::read(void* b, bd_addr_t addr, bd_size_t size) { + //debug_if(SD_DBG, "read Card...\r\n"); + if (isPresent() == false) { + return SD_BLOCK_DEVICE_ERROR_NO_DEVICE; + } + if (!is_valid_read(addr, size)) { + return SD_BLOCK_DEVICE_ERROR_PARAMETER; + } + + lock(); + if (!_is_initialized) { + unlock(); + return SD_BLOCK_DEVICE_ERROR_NO_INIT; + } + + uint32_t *buffer = static_cast(b); + int status = BD_ERROR_OK; + + // ReadBlocks uses byte unit address + // SDHC and SDXC Cards different addressing is handled in ReadBlocks() + bd_addr_t blockCnt = size / _block_size; + addr = addr / _block_size; + + // receive the data : one block/ multiple blocks is handled in ReadBlocks() +#if (TRANSFER_MODE == TRANSFER_MODE_POLLING) + _sd_state = SD_ReadBlocks(buffer, addr, blockCnt, MBED_CONF_SD_TIMEOUT); +#elif (TRANSFER_MODE == TRANSFER_MODE_DMA) + _sd_state = SD_ReadBlocks_DMA(buffer, addr, blockCnt); +#else +# error "TRANSFER_MODE must be either TRANSFER_MODE_POLLING or TRANSFER_MODE_DMA" +#endif + debug_if(SD_DBG, "ReadBlocks dbgtest addr: %lld blockCnt: %lld \n", addr, blockCnt); + if (_sd_state != 0) { + debug_if(SD_DBG, "ReadBlocks failed! addr: %lld blockCnt: %lld \n", addr, blockCnt); + debug_if(SD_DBG, " hsd.errorcode: %lu 0x%lx\n", hsd.ErrorCode, hsd.ErrorCode); + printf("ReadBlocks failed! addr: %lld blockCnt: %lld \n", addr, blockCnt); + printf(" hsd.errorcode: %lu 0x%lx\n", hsd.ErrorCode, hsd.ErrorCode); + status = SD_BLOCK_DEVICE_ERROR_READBLOCKS; + } + else { + while (SD_GetCardState() != SD_TRANSFER_OK) { + // wait until SD ready + wait_ms(10); + } + } + +#if (TRANSFER_MODE == TRANSFER_MODE_DMA) + while (SD_DMA_ReadPending() != SD_TRANSFER_OK) { + // wait until DMA transfer done + wait_ms(10); + } +#endif + + unlock(); + return status; +} + +int SDIOBlockDevice::program(const void* b, bd_addr_t addr, bd_size_t size) { + //debug_if(SD_DBG, "program Card...\r\n"); + if (isPresent() == false) { + return SD_BLOCK_DEVICE_ERROR_NO_DEVICE; + } + if (!is_valid_program(addr, size)) { + return SD_BLOCK_DEVICE_ERROR_PARAMETER; + } + + lock(); + if (!_is_initialized) { + unlock(); + return SD_BLOCK_DEVICE_ERROR_NO_INIT; + } + + //uint32_t *buffer = static_cast< uint32_t *>(b); + // HAL layer uses uint32_t for addr/size + uint32_t *buffer = (uint32_t *)(b); + int status = BD_ERROR_OK; + + // Get block count + bd_size_t blockCnt = size / _block_size; + addr = addr / _block_size; + +#if (TRANSFER_MODE == TRANSFER_MODE_POLLING) + _sd_state = SD_WriteBlocks(buffer, addr, blockCnt, MBED_CONF_SD_TIMEOUT); +#elif (TRANSFER_MODE == TRANSFER_MODE_DMA) + _sd_state = SD_WriteBlocks_DMA(buffer, addr, blockCnt); +#else +# error "TRANSFER_MODE must be either TRANSFER_MODE_POLLING or TRANSFER_MODE_DMA" +#endif + debug_if(SD_DBG, "WriteBlocks dbgtest addr: %lld blockCnt: %lld \n", addr, blockCnt); + if (_sd_state != 0) { + debug_if(SD_DBG, "WriteBlocks failed! addr: %lld blockCnt: %lld \n", addr, blockCnt); + debug_if(SD_DBG, " hsd.errorcode: %lu 0x%lx\n", hsd.ErrorCode, hsd.ErrorCode); + printf("ReadBlocks failed! addr: %lld blockCnt: %lld \n", addr, blockCnt); + printf(" hsd.errorcode: %lu 0x%lx\n", hsd.ErrorCode, hsd.ErrorCode); + status = SD_BLOCK_DEVICE_ERROR_WRITEBLOCKS; + } + else { + while (SD_GetCardState() != SD_TRANSFER_OK) { + // wait until SD ready + wait_ms(10); + } + } + + #if (TRANSFER_MODE == TRANSFER_MODE_DMA) + while (SD_DMA_WritePending() != SD_TRANSFER_OK) { + // wait until DMA transfer done + wait_ms(20); + } +#endif + + unlock(); + return status; +} + +int SDIOBlockDevice::trim(bd_addr_t addr, bd_size_t size) { + //debug_if(SD_DBG, "trim Card...\r\n"); + if (isPresent() == false) { + return SD_BLOCK_DEVICE_ERROR_NO_DEVICE; + } + if (!_is_valid_trim(addr, size)) { + return SD_BLOCK_DEVICE_ERROR_PARAMETER; + } + + lock(); + if (!_is_initialized) { + unlock(); + return SD_BLOCK_DEVICE_ERROR_NO_INIT; + } + + int status = BD_ERROR_OK; + + bd_size_t blockCnt = size / _block_size; + addr = addr / _block_size; + + _sd_state = SD_Erase(addr, blockCnt); + if (_sd_state != 0) { + debug_if(SD_DBG, "Erase blocks failed! addr: %lld blockCnt: %lld \n", addr, blockCnt); + status = SD_BLOCK_DEVICE_ERROR_ERASEBLOCKS; + } + else { + while (SD_GetCardState() != SD_TRANSFER_OK) { + // wait until SD ready + } + } + + unlock(); + return status; +} + +bd_size_t SDIOBlockDevice::get_read_size() const { + return _block_size; +} + +bd_size_t SDIOBlockDevice::get_program_size() const { + return _block_size; +} + +bd_size_t SDIOBlockDevice::size() const { + return _block_size * _sectors; +} + +void SDIOBlockDevice::debug(bool dbg) { +} + +bool SDIOBlockDevice::_is_valid_trim(bd_addr_t addr, bd_size_t size) +{ + return ( + addr % _erase_size == 0 && + size % _erase_size == 0 && + addr + size <= this->size()); +} + +bool SDIOBlockDevice::isPresent(void) { + if (_cardDetect.is_connected()) + return (_cardDetect.read() == 0); + else + return true; +} + + +} // namespace mbed + diff --git a/components/storage/blockdevice/COMPONENT_SDIO/SDIOBlockDevice.h b/components/storage/blockdevice/COMPONENT_SDIO/SDIOBlockDevice.h new file mode 100644 index 00000000000..60e43283432 --- /dev/null +++ b/components/storage/blockdevice/COMPONENT_SDIO/SDIOBlockDevice.h @@ -0,0 +1,148 @@ +/* mbed Microcontroller Library + * Copyright (c) 2017 ARM Limited + * + * 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. + */ + + +#ifndef MBED_OS_FEATURES_STORAGE_BLOCKDEVICE_SDIOBLOCKDEVICE_H_ + +#define MBED_OS_FEATURES_STORAGE_BLOCKDEVICE_SDIOBLOCKDEVICE_H_ + +#include "BlockDevice.h" +#include "drivers/DigitalIn.h" +#include "platform/PlatformMutex.h" +#include "targets/TARGET_STM/TARGET_STM32F4/sdio_device.h" + +namespace mbed { + +class SDIOBlockDevice: public BlockDevice { +public: + SDIOBlockDevice(PinName cardDetect=NC); + virtual ~SDIOBlockDevice(); + /** Initialize a block device + * + * @return 0 on success or a negative error code on failure + */ + virtual int init(); + + /** Deinitialize a block device + * + * @return 0 on success or a negative error code on failure + */ + virtual int deinit(); + + /** Read blocks from a block device + * + * @param buffer Buffer to write blocks to + * @param addr Address of block to begin reading from + * @param size Size to read in bytes, must be a multiple of read block size + * @return 0 on success, negative error code on failure + */ + virtual int read(void *buffer, bd_addr_t addr, bd_size_t size); + + /** Program blocks to a block device + * + * The blocks must have been erased prior to being programmed + * + * @param buffer Buffer of data to write to blocks + * @param addr Address of block to begin writing to + * @param size Size to write in bytes, must be a multiple of program block size + * @return 0 on success, negative error code on failure + */ + virtual int program(const void *buffer, bd_addr_t addr, bd_size_t size); + + /** Mark blocks as no longer in use + * + * This function provides a hint to the underlying block device that a region of blocks + * is no longer in use and may be erased without side effects. Erase must still be called + * before programming, but trimming allows flash-translation-layers to schedule erases when + * the device is not busy. + * + * @param addr Address of block to mark as unused + * @param size Size to mark as unused in bytes, must be a multiple of erase block size + * @return 0 on success, negative error code on failure + */ + virtual int trim(bd_addr_t addr, bd_size_t size); + + /** Get the size of a readable block + * + * @return Size of a readable block in bytes + */ + virtual bd_size_t get_read_size() const; + + /** Get the size of a programable block + * + * @return Size of a programable block in bytes + * @note Must be a multiple of the read size + */ + virtual bd_size_t get_program_size() const; + + /** Get the total size of the underlying device + * + * @return Size of the underlying device in bytes + */ + virtual bd_size_t size() const; + + /** Enable or disable debugging + * + * @param dbg State of debugging + */ + virtual void debug(bool dbg); + + /** Set the transfer frequency + * + * @param freq Transfer frequency + * @note Max frequency supported is 25MHZ + */ + virtual int frequency(uint64_t freq) {return BD_ERROR_OK;}; + + /** check if SD is present + * + * @note check physical present switch. Maybe not support by hardware, then function will always return true. + */ + virtual bool isPresent(void); + +private: + //SD_HandleTypeDef _hsd; + DigitalIn _cardDetect; + bool _is_initialized; + bd_size_t _block_size; + bd_size_t _erase_size; + bd_size_t _sectors; + uint32_t _sd_state; + uint32_t _init_ref_count; + HAL_SD_CardInfoTypeDef _cardInfo; + uint32_t _card_type; + + PlatformMutex _mutex; + virtual void lock() + { + _mutex.lock(); + } + + virtual void unlock() + { + _mutex.unlock(); + } + + bool _is_valid_trim(bd_addr_t addr, bd_size_t size); + + +}; + + +} // namespace mbed + + +#endif /* MBED_OS_FEATURES_STORAGE_BLOCKDEVICE_SDIOBLOCKDEVICE_H_ */ From 37801f2506de489f63b588aefde3848053e3b861 Mon Sep 17 00:00:00 2001 From: JojoS62 Date: Wed, 31 Oct 2018 15:54:52 +0100 Subject: [PATCH 04/13] configuration file for SDIO settings --- .../blockdevice/COMPONENT_SDIO/config/mbed_lib.json | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 components/storage/blockdevice/COMPONENT_SDIO/config/mbed_lib.json diff --git a/components/storage/blockdevice/COMPONENT_SDIO/config/mbed_lib.json b/components/storage/blockdevice/COMPONENT_SDIO/config/mbed_lib.json new file mode 100644 index 00000000000..30d5324fa41 --- /dev/null +++ b/components/storage/blockdevice/COMPONENT_SDIO/config/mbed_lib.json @@ -0,0 +1,12 @@ +{ + "name": "sdio", + "config": { + "FSFAT_SDCARD_INSTALLED": 1, + "CMD_TIMEOUT": 30000 + }, + "target_overrides": { + "DISCO_F469NI": { + "CMD_TIMEOUT": 30000 + } + } +} From 22bd3f6266c4b17fc2f8bb4867a463b6676c8e95 Mon Sep 17 00:00:00 2001 From: JojoS62 Date: Wed, 31 Oct 2018 15:55:10 +0100 Subject: [PATCH 05/13] adding tests for SDIOBlockdevice --- .../TESTS/filesystem/dirs/main.cpp | 500 +++++ .../TESTS/filesystem/files/main.cpp | 337 ++++ .../TESTS/filesystem/fopen/fopen.cpp | 1621 +++++++++++++++++ .../TESTS/filesystem/parallel/main.cpp | 209 +++ .../TESTS/filesystem/seek/main.cpp | 656 +++++++ 5 files changed, 3323 insertions(+) create mode 100644 components/storage/blockdevice/COMPONENT_SDIO/TESTS/filesystem/dirs/main.cpp create mode 100644 components/storage/blockdevice/COMPONENT_SDIO/TESTS/filesystem/files/main.cpp create mode 100644 components/storage/blockdevice/COMPONENT_SDIO/TESTS/filesystem/fopen/fopen.cpp create mode 100644 components/storage/blockdevice/COMPONENT_SDIO/TESTS/filesystem/parallel/main.cpp create mode 100644 components/storage/blockdevice/COMPONENT_SDIO/TESTS/filesystem/seek/main.cpp diff --git a/components/storage/blockdevice/COMPONENT_SDIO/TESTS/filesystem/dirs/main.cpp b/components/storage/blockdevice/COMPONENT_SDIO/TESTS/filesystem/dirs/main.cpp new file mode 100644 index 00000000000..fcb055a8117 --- /dev/null +++ b/components/storage/blockdevice/COMPONENT_SDIO/TESTS/filesystem/dirs/main.cpp @@ -0,0 +1,500 @@ +/* mbed Microcontroller Library + * Copyright (c) 2016 ARM Limited + * + * 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. + */ + +#include "mbed.h" +#include "greentea-client/test_env.h" +#include "unity.h" +#include "utest.h" +#include +#include + +using namespace utest::v1; + +// test configuration +#ifndef MBED_TEST_FILESYSTEM +#define MBED_TEST_FILESYSTEM FATFileSystem +#endif + +#ifndef MBED_TEST_FILESYSTEM_DECL +#define MBED_TEST_FILESYSTEM_DECL MBED_TEST_FILESYSTEM fs("fs") +#endif + +#ifndef MBED_TEST_BLOCKDEVICE +#define MBED_TEST_BLOCKDEVICE SDIOBlockDevice +#define MBED_TEST_BLOCKDEVICE_DECL SDIOBlockDevice bd; +#endif + +#ifndef MBED_TEST_BLOCKDEVICE_DECL +#define MBED_TEST_BLOCKDEVICE_DECL MBED_TEST_BLOCKDEVICE bd +#endif + +#ifndef MBED_TEST_FILES +#define MBED_TEST_FILES 4 +#endif + +#ifndef MBED_TEST_DIRS +#define MBED_TEST_DIRS 4 +#endif + +#ifndef MBED_TEST_BUFFER +#define MBED_TEST_BUFFER 8192 +#endif + +#ifndef MBED_TEST_TIMEOUT +#define MBED_TEST_TIMEOUT 120 +#endif + + +// declarations +#define STRINGIZE(x) STRINGIZE2(x) +#define STRINGIZE2(x) #x +#define INCLUDE(x) STRINGIZE(x.h) + +#include INCLUDE(MBED_TEST_FILESYSTEM) +#include INCLUDE(MBED_TEST_BLOCKDEVICE) + +MBED_TEST_FILESYSTEM_DECL; +MBED_TEST_BLOCKDEVICE_DECL; + +Dir dir[MBED_TEST_DIRS]; +File file[MBED_TEST_FILES]; +DIR *dd[MBED_TEST_DIRS]; +FILE *fd[MBED_TEST_FILES]; +struct dirent ent; +struct dirent *ed; +size_t size; +uint8_t buffer[MBED_TEST_BUFFER]; +uint8_t rbuffer[MBED_TEST_BUFFER]; +uint8_t wbuffer[MBED_TEST_BUFFER]; + + +// tests + +void test_directory_tests() +{ + int res = bd.init(); + TEST_ASSERT_EQUAL(0, res); + + { + res = MBED_TEST_FILESYSTEM::format(&bd); + TEST_ASSERT_EQUAL(0, res); + } + + res = bd.deinit(); + TEST_ASSERT_EQUAL(0, res); +} + +void test_root_directory() +{ + int res = bd.init(); + TEST_ASSERT_EQUAL(0, res); + + { + res = fs.mount(&bd); + TEST_ASSERT_EQUAL(0, res); + res = dir[0].open(&fs, "/"); + TEST_ASSERT_EQUAL(0, res); + res = dir[0].close(); + TEST_ASSERT_EQUAL(0, res); + res = fs.unmount(); + TEST_ASSERT_EQUAL(0, res); + } + + res = bd.deinit(); + TEST_ASSERT_EQUAL(0, res); +} + +void test_directory_creation() +{ + int res = bd.init(); + TEST_ASSERT_EQUAL(0, res); + + { + res = fs.mount(&bd); + TEST_ASSERT_EQUAL(0, res); + res = fs.mkdir("potato", 0777); + TEST_ASSERT_EQUAL(0, res); + res = fs.unmount(); + TEST_ASSERT_EQUAL(0, res); + } + + res = bd.deinit(); + TEST_ASSERT_EQUAL(0, res); +} + +void test_file_creation() +{ + int res = bd.init(); + TEST_ASSERT_EQUAL(0, res); + + { + res = fs.mount(&bd); + TEST_ASSERT_EQUAL(0, res); + res = file[0].open(&fs, "burito", O_CREAT | O_WRONLY); + TEST_ASSERT_EQUAL(0, res); + res = file[0].close(); + TEST_ASSERT_EQUAL(0, res); + res = fs.unmount(); + TEST_ASSERT_EQUAL(0, res); + } + + res = bd.deinit(); + TEST_ASSERT_EQUAL(0, res); +} + +void dir_file_check(char *list[], uint32_t elements) +{ + int res; + while (1) { + res = dir[0].read(&ent); + if (0 == res) { + break; + } + for (int i = 0; i < elements ; i++) { + res = strcmp(ent.d_name, list[i]); + if (0 == res) { + res = ent.d_type; + if ((DT_DIR != res) && (DT_REG != res)) { + TEST_ASSERT(1); + } + break; + } else if ( i == elements) { + TEST_ASSERT_EQUAL(0, res); + } + } + } +} + +void test_directory_iteration() +{ + int res = bd.init(); + TEST_ASSERT_EQUAL(0, res); + + res = fs.mount(&bd); + TEST_ASSERT_EQUAL(0, res); + res = dir[0].open(&fs, "/"); + TEST_ASSERT_EQUAL(0, res); + char *dir_list[] = {"potato", "burito", ".", ".."}; + + dir_file_check(dir_list, (sizeof(dir_list) / sizeof(dir_list[0]))); + + res = dir[0].close(); + TEST_ASSERT_EQUAL(0, res); + res = fs.unmount(); + TEST_ASSERT_EQUAL(0, res); + res = bd.deinit(); + TEST_ASSERT_EQUAL(0, res); +} + +void test_directory_failures() +{ + int res = bd.init(); + TEST_ASSERT_EQUAL(0, res); + + { + res = fs.mount(&bd); + TEST_ASSERT_EQUAL(0, res); + res = fs.mkdir("potato", 0777); + TEST_ASSERT_EQUAL(-EEXIST, res); + res = dir[0].open(&fs, "tomato"); + TEST_ASSERT_EQUAL(-ENOTDIR, res); + res = dir[0].open(&fs, "burito"); + TEST_ASSERT_NOT_EQUAL(0, res); + res = file[0].open(&fs, "tomato", O_RDONLY); + TEST_ASSERT_EQUAL(-ENOENT, res); + res = file[0].open(&fs, "potato", O_RDONLY); + TEST_ASSERT_NOT_EQUAL(0, res); + res = fs.unmount(); + TEST_ASSERT_EQUAL(0, res); + } + + res = bd.deinit(); + TEST_ASSERT_EQUAL(0, res); +} + +void test_nested_directories() +{ + int res = bd.init(); + TEST_ASSERT_EQUAL(0, res); + + { + res = fs.mount(&bd); + TEST_ASSERT_EQUAL(0, res); + res = fs.mkdir("potato/baked", 0777); + TEST_ASSERT_EQUAL(0, res); + res = fs.mkdir("potato/sweet", 0777); + TEST_ASSERT_EQUAL(0, res); + res = fs.mkdir("potato/fried", 0777); + TEST_ASSERT_EQUAL(0, res); + res = fs.unmount(); + TEST_ASSERT_EQUAL(0, res); + } + + { + res = fs.mount(&bd); + TEST_ASSERT_EQUAL(0, res); + res = dir[0].open(&fs, "/"); + TEST_ASSERT_EQUAL(0, res); + char *dir_list[] = {"potato", "baked", "sweet", "fried", ".", ".."}; + dir_file_check(dir_list, (sizeof(dir_list) / sizeof(dir_list[0]))); + res = dir[0].close(); + TEST_ASSERT_EQUAL(0, res); + res = fs.unmount(); + TEST_ASSERT_EQUAL(0, res); + } + + res = bd.deinit(); + TEST_ASSERT_EQUAL(0, res); +} + +void test_multi_block_directory() +{ + int res = bd.init(); + TEST_ASSERT_EQUAL(0, res); + + { + res = fs.mount(&bd); + TEST_ASSERT_EQUAL(0, res); + res = fs.mkdir("cactus", 0777); + TEST_ASSERT_EQUAL(0, res); + for (int i = 0; i < 128; i++) { + sprintf((char *)buffer, "cactus/test%d", i); + res = fs.mkdir((char *)buffer, 0777); + TEST_ASSERT_EQUAL(0, res); + } + res = fs.unmount(); + TEST_ASSERT_EQUAL(0, res); + } + + { + res = fs.mount(&bd); + TEST_ASSERT_EQUAL(0, res); + res = dir[0].open(&fs, "cactus"); + TEST_ASSERT_EQUAL(0, res); + +#if (MBED_TEST_FILESYSTEM != FATFileSystem) + char *dir_list[] = {".", ".."}; + dir_file_check(dir_list, (sizeof(dir_list) / sizeof(dir_list[0]))); +#endif + + for (int i = 0; i < 128; i++) { + sprintf((char *)buffer, "test%d", i); + res = dir[0].read(&ent); + TEST_ASSERT_EQUAL(1, res); + res = strcmp(ent.d_name, (char *)buffer); + TEST_ASSERT_EQUAL(0, res); + } + res = dir[0].read(&ent); + TEST_ASSERT_EQUAL(0, res); + res = dir[0].close(); + TEST_ASSERT_EQUAL(0, res); + res = fs.unmount(); + TEST_ASSERT_EQUAL(0, res); + } + + res = bd.deinit(); + TEST_ASSERT_EQUAL(0, res); +} + +void test_directory_remove() +{ + int res = bd.init(); + TEST_ASSERT_EQUAL(0, res); + + { + res = fs.mount(&bd); + TEST_ASSERT_EQUAL(0, res); + res = fs.remove("potato"); + TEST_ASSERT_NOT_EQUAL(0, res); + res = fs.remove("potato/sweet"); + TEST_ASSERT_EQUAL(0, res); + res = fs.remove("potato/baked"); + TEST_ASSERT_EQUAL(0, res); + res = fs.remove("potato/fried"); + TEST_ASSERT_EQUAL(0, res); + res = dir[0].open(&fs, "potato"); + TEST_ASSERT_EQUAL(0, res); + +#if (MBED_TEST_FILESYSTEM != FATFileSystem) + char *dir_list[] = {".", ".."}; + dir_file_check(dir_list, (sizeof(dir_list) / sizeof(dir_list[0]))); +#endif + + res = dir[0].read(&ent); + TEST_ASSERT_EQUAL(0, res); + res = dir[0].close(); + TEST_ASSERT_EQUAL(0, res); + res = fs.remove("potato"); + TEST_ASSERT_EQUAL(0, res); + res = fs.unmount(); + TEST_ASSERT_EQUAL(0, res); + } + + { + res = fs.mount(&bd); + TEST_ASSERT_EQUAL(0, res); + res = dir[0].open(&fs, "/"); + TEST_ASSERT_EQUAL(0, res); + char *dir_list[] = {"burito", "cactus", ".", ".."}; + dir_file_check(dir_list, (sizeof(dir_list) / sizeof(dir_list[0]))); + res = dir[0].close(); + TEST_ASSERT_EQUAL(0, res); + res = fs.unmount(); + TEST_ASSERT_EQUAL(0, res); + } + + res = bd.deinit(); + TEST_ASSERT_EQUAL(0, res); +} + +void test_directory_rename() +{ + int res = bd.init(); + TEST_ASSERT_EQUAL(0, res); + + { + res = fs.mount(&bd); + TEST_ASSERT_EQUAL(0, res); + res = fs.mkdir("coldpotato", 0777); + TEST_ASSERT_EQUAL(0, res); + res = fs.mkdir("coldpotato/baked", 0777); + TEST_ASSERT_EQUAL(0, res); + res = fs.mkdir("coldpotato/sweet", 0777); + TEST_ASSERT_EQUAL(0, res); + res = fs.mkdir("coldpotato/fried", 0777); + TEST_ASSERT_EQUAL(0, res); + res = fs.unmount(); + TEST_ASSERT_EQUAL(0, res); + } + + { + res = fs.mount(&bd); + TEST_ASSERT_EQUAL(0, res); + res = fs.rename("coldpotato", "hotpotato"); + TEST_ASSERT_EQUAL(0, res); + res = fs.unmount(); + TEST_ASSERT_EQUAL(0, res); + } + + { + res = fs.mount(&bd); + TEST_ASSERT_EQUAL(0, res); + res = dir[0].open(&fs, "hotpotato"); + TEST_ASSERT_EQUAL(0, res); + char *dir_list[] = {"baked", "sweet", "fried", ".", ".."}; + dir_file_check(dir_list, (sizeof(dir_list) / sizeof(dir_list[0]))); + res = dir[0].close(); + TEST_ASSERT_EQUAL(0, res); + res = fs.unmount(); + TEST_ASSERT_EQUAL(0, res); + } + + { + res = fs.mount(&bd); + TEST_ASSERT_EQUAL(0, res); + res = fs.mkdir("warmpotato", 0777); + TEST_ASSERT_EQUAL(0, res); + res = fs.mkdir("warmpotato/mushy", 0777); + TEST_ASSERT_EQUAL(0, res); + res = fs.rename("hotpotato", "warmpotato"); + TEST_ASSERT_NOT_EQUAL(0, res); + res = fs.remove("warmpotato/mushy"); + TEST_ASSERT_EQUAL(0, res); + res = fs.remove("warmpotato"); + TEST_ASSERT_EQUAL(0, res); + res = fs.rename("hotpotato", "warmpotato"); + TEST_ASSERT_EQUAL(0, res); + res = fs.unmount(); + TEST_ASSERT_EQUAL(0, res); + } + + { + res = fs.mount(&bd); + TEST_ASSERT_EQUAL(0, res); + res = dir[0].open(&fs, "warmpotato"); + TEST_ASSERT_EQUAL(0, res); + char *dir_list[] = {"baked", "sweet", "fried", ".", ".."}; + dir_file_check(dir_list, (sizeof(dir_list) / sizeof(dir_list[0]))); + res = dir[0].close(); + TEST_ASSERT_EQUAL(0, res); + res = fs.unmount(); + TEST_ASSERT_EQUAL(0, res); + } + + { + res = fs.mount(&bd); + TEST_ASSERT_EQUAL(0, res); + res = fs.mkdir("coldpotato", 0777); + TEST_ASSERT_EQUAL(0, res); + res = fs.rename("warmpotato/baked", "coldpotato/baked"); + TEST_ASSERT_EQUAL(0, res); + res = fs.rename("warmpotato/sweet", "coldpotato/sweet"); + TEST_ASSERT_EQUAL(0, res); + res = fs.rename("warmpotato/fried", "coldpotato/fried"); + TEST_ASSERT_EQUAL(0, res); + res = fs.remove("coldpotato"); + TEST_ASSERT_NOT_EQUAL(0, res); + res = fs.remove("warmpotato"); + TEST_ASSERT_EQUAL(0, res); + res = fs.unmount(); + TEST_ASSERT_EQUAL(0, res); + } + + { + res = fs.mount(&bd); + TEST_ASSERT_EQUAL(0, res); + res = dir[0].open(&fs, "coldpotato"); + TEST_ASSERT_EQUAL(0, res); + char *dir_list[] = {"baked", "sweet", "fried", ".", ".."}; + dir_file_check(dir_list, (sizeof(dir_list) / sizeof(dir_list[0]))); + res = dir[0].close(); + TEST_ASSERT_EQUAL(0, res); + res = fs.unmount(); + TEST_ASSERT_EQUAL(0, res); + } + + res = bd.deinit(); + TEST_ASSERT_EQUAL(0, res); +} + + + +// test setup +utest::v1::status_t test_setup(const size_t number_of_cases) +{ + GREENTEA_SETUP(MBED_TEST_TIMEOUT, "default_auto"); + return verbose_test_setup_handler(number_of_cases); +} + +Case cases[] = { + Case("Directory tests", test_directory_tests), + Case("Root directory", test_root_directory), + Case("Directory creation", test_directory_creation), + Case("File creation", test_file_creation), + Case("Directory iteration", test_directory_iteration), + Case("Directory failures", test_directory_failures), + Case("Nested directories", test_nested_directories), + Case("Multi-block directory", test_multi_block_directory), + Case("Directory remove", test_directory_remove), + Case("Directory rename", test_directory_rename), +}; + +Specification specification(test_setup, cases); + +int main() +{ + return !Harness::run(specification); +} diff --git a/components/storage/blockdevice/COMPONENT_SDIO/TESTS/filesystem/files/main.cpp b/components/storage/blockdevice/COMPONENT_SDIO/TESTS/filesystem/files/main.cpp new file mode 100644 index 00000000000..ed4d242ac90 --- /dev/null +++ b/components/storage/blockdevice/COMPONENT_SDIO/TESTS/filesystem/files/main.cpp @@ -0,0 +1,337 @@ +/* mbed Microcontroller Library + * Copyright (c) 2016 ARM Limited + * + * 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. + */ + +#include "mbed.h" +#include "greentea-client/test_env.h" +#include "unity.h" +#include "utest.h" +#include +#include + +using namespace utest::v1; + +// test configuration +#ifndef MBED_TEST_FILESYSTEM +#define MBED_TEST_FILESYSTEM FATFileSystem +#endif + +#ifndef MBED_TEST_FILESYSTEM_DECL +#define MBED_TEST_FILESYSTEM_DECL MBED_TEST_FILESYSTEM fs("fs") +#endif + +#ifndef MBED_TEST_BLOCKDEVICE +#define MBED_TEST_BLOCKDEVICE SDIOBlockDevice +#define MBED_TEST_BLOCKDEVICE_DECL SDIOBlockDevice bd; +#endif + +#ifndef MBED_TEST_BLOCKDEVICE_DECL +#define MBED_TEST_BLOCKDEVICE_DECL MBED_TEST_BLOCKDEVICE bd +#endif + +#ifndef MBED_TEST_FILES +#define MBED_TEST_FILES 4 +#endif + +#ifndef MBED_TEST_DIRS +#define MBED_TEST_DIRS 4 +#endif + +#ifndef MBED_TEST_BUFFER +#define MBED_TEST_BUFFER 8192 +#endif + +#ifndef MBED_TEST_TIMEOUT +#define MBED_TEST_TIMEOUT 120 +#endif + + +// declarations +#define STRINGIZE(x) STRINGIZE2(x) +#define STRINGIZE2(x) #x +#define INCLUDE(x) STRINGIZE(x.h) + +#include INCLUDE(MBED_TEST_FILESYSTEM) +#include INCLUDE(MBED_TEST_BLOCKDEVICE) + +MBED_TEST_FILESYSTEM_DECL; +MBED_TEST_BLOCKDEVICE_DECL; + +Dir dir[MBED_TEST_DIRS]; +File file[MBED_TEST_FILES]; +DIR *dd[MBED_TEST_DIRS]; +FILE *fd[MBED_TEST_FILES]; +struct dirent ent; +struct dirent *ed; +size_t size; +uint8_t buffer[MBED_TEST_BUFFER]; +uint8_t rbuffer[MBED_TEST_BUFFER]; +uint8_t wbuffer[MBED_TEST_BUFFER]; + +static char file_counter = 0; +const char *filenames[] = {"smallavacado", "mediumavacado", "largeavacado", + "blockfile", "bigblockfile", "hello", ".", ".." + }; + +// tests + +void test_file_tests() +{ + int res = bd.init(); + TEST_ASSERT_EQUAL(0, res); + + { + res = MBED_TEST_FILESYSTEM::format(&bd); + TEST_ASSERT_EQUAL(0, res); + } + + res = bd.deinit(); + TEST_ASSERT_EQUAL(0, res); +} + +void test_simple_file_test() +{ + int res = bd.init(); + TEST_ASSERT_EQUAL(0, res); + + { + res = fs.mount(&bd); + TEST_ASSERT_EQUAL(0, res); + res = file[0].open(&fs, "hello", O_WRONLY | O_CREAT); + TEST_ASSERT_EQUAL(0, res); + size = strlen("Hello World!\n"); + memcpy(wbuffer, "Hello World!\n", size); + res = file[0].write(wbuffer, size); + TEST_ASSERT_EQUAL(size, res); + res = file[0].close(); + TEST_ASSERT_EQUAL(0, res); + res = file[0].open(&fs, "hello", O_RDONLY); + TEST_ASSERT_EQUAL(0, res); + size = strlen("Hello World!\n"); + res = file[0].read(rbuffer, size); + TEST_ASSERT_EQUAL(size, res); + res = memcmp(rbuffer, wbuffer, size); + TEST_ASSERT_EQUAL(0, res); + res = file[0].close(); + TEST_ASSERT_EQUAL(0, res); + res = fs.unmount(); + TEST_ASSERT_EQUAL(0, res); + } + + res = bd.deinit(); + TEST_ASSERT_EQUAL(0, res); +} + +template +void test_write_file_test() +{ + int res = bd.init(); + TEST_ASSERT_EQUAL(0, res); + + { + size_t size = file_size; + size_t chunk = write_size; + srand(0); + res = fs.mount(&bd); + TEST_ASSERT_EQUAL(0, res); + res = file[0].open(&fs, filenames[file_counter], O_WRONLY | O_CREAT); + TEST_ASSERT_EQUAL(0, res); + for (size_t i = 0; i < size; i += chunk) { + chunk = (chunk < size - i) ? chunk : size - i; + for (size_t b = 0; b < chunk; b++) { + buffer[b] = rand() & 0xff; + } + res = file[0].write(buffer, chunk); + TEST_ASSERT_EQUAL(chunk, res); + } + res = file[0].close(); + TEST_ASSERT_EQUAL(0, res); + res = fs.unmount(); + TEST_ASSERT_EQUAL(0, res); + } + + { + size_t size = file_size; + size_t chunk = read_size; + srand(0); + res = fs.mount(&bd); + TEST_ASSERT_EQUAL(0, res); + res = file[0].open(&fs, filenames[file_counter], O_RDONLY); + TEST_ASSERT_EQUAL(0, res); + for (size_t i = 0; i < size; i += chunk) { + chunk = (chunk < size - i) ? chunk : size - i; + res = file[0].read(buffer, chunk); + TEST_ASSERT_EQUAL(chunk, res); + for (size_t b = 0; b < chunk && i + b < size; b++) { + res = buffer[b]; + TEST_ASSERT_EQUAL(rand() & 0xff, res); + } + } + res = file[0].close(); + TEST_ASSERT_EQUAL(0, res); + res = fs.unmount(); + TEST_ASSERT_EQUAL(0, res); + } + + file_counter++; + res = bd.deinit(); + TEST_ASSERT_EQUAL(0, res); +} + +void test_non_overlap_check() +{ + int res = bd.init(); + TEST_ASSERT_EQUAL(0, res); + + { + size_t size = 32; + size_t chunk = 29; + srand(0); + res = fs.mount(&bd); + TEST_ASSERT_EQUAL(0, res); + res = file[0].open(&fs, "smallavacado", O_RDONLY); + TEST_ASSERT_EQUAL(0, res); + for (size_t i = 0; i < size; i += chunk) { + chunk = (chunk < size - i) ? chunk : size - i; + res = file[0].read(buffer, chunk); + TEST_ASSERT_EQUAL(chunk, res); + for (size_t b = 0; b < chunk && i + b < size; b++) { + res = buffer[b]; + TEST_ASSERT_EQUAL(rand() & 0xff, res); + } + } + res = file[0].close(); + TEST_ASSERT_EQUAL(0, res); + res = fs.unmount(); + TEST_ASSERT_EQUAL(0, res); + } + + { + size_t size = 8192; + size_t chunk = 29; + srand(0); + res = fs.mount(&bd); + TEST_ASSERT_EQUAL(0, res); + res = file[0].open(&fs, "mediumavacado", O_RDONLY); + TEST_ASSERT_EQUAL(0, res); + for (size_t i = 0; i < size; i += chunk) { + chunk = (chunk < size - i) ? chunk : size - i; + res = file[0].read(buffer, chunk); + TEST_ASSERT_EQUAL(chunk, res); + for (size_t b = 0; b < chunk && i + b < size; b++) { + res = buffer[b]; + TEST_ASSERT_EQUAL(rand() & 0xff, res); + } + } + res = file[0].close(); + TEST_ASSERT_EQUAL(0, res); + res = fs.unmount(); + TEST_ASSERT_EQUAL(0, res); + } + + { + size_t size = 262144; + size_t chunk = 29; + srand(0); + res = fs.mount(&bd); + TEST_ASSERT_EQUAL(0, res); + res = file[0].open(&fs, "largeavacado", O_RDONLY); + TEST_ASSERT_EQUAL(0, res); + for (size_t i = 0; i < size; i += chunk) { + chunk = (chunk < size - i) ? chunk : size - i; + res = file[0].read(buffer, chunk); + TEST_ASSERT_EQUAL(chunk, res); + for (size_t b = 0; b < chunk && i + b < size; b++) { + res = buffer[b]; + TEST_ASSERT_EQUAL(rand() & 0xff, res); + } + } + res = file[0].close(); + TEST_ASSERT_EQUAL(0, res); + res = fs.unmount(); + TEST_ASSERT_EQUAL(0, res); + } + + res = bd.deinit(); + TEST_ASSERT_EQUAL(0, res); +} + +void test_dir_check() +{ + + int res = bd.init(); + TEST_ASSERT_EQUAL(0, res); + + { + res = fs.mount(&bd); + TEST_ASSERT_EQUAL(0, res); + res = dir[0].open(&fs, "/"); + TEST_ASSERT_EQUAL(0, res); + int numFiles = sizeof(filenames) / sizeof(filenames[0]); + // Check the filenames in directory + while (1) { + res = dir[0].read(&ent); + if (0 == res) { + break; + } + for (int i = 0; i < numFiles ; i++) { + res = strcmp(ent.d_name, filenames[i]); + if (0 == res) { + res = ent.d_type; + if ((DT_REG != res) && (DT_DIR != res)) { + TEST_ASSERT(1); + } + break; + } else if ( i == numFiles) { + TEST_ASSERT_EQUAL(0, res); + } + } + } + res = dir[0].close(); + TEST_ASSERT_EQUAL(0, res); + res = fs.unmount(); + TEST_ASSERT_EQUAL(0, res); + } + + res = bd.deinit(); + TEST_ASSERT_EQUAL(0, res); +} + + +// test setup +utest::v1::status_t test_setup(const size_t number_of_cases) +{ + GREENTEA_SETUP(MBED_TEST_TIMEOUT, "default_auto"); + return verbose_test_setup_handler(number_of_cases); +} + +Case cases[] = { + Case("File tests", test_file_tests), + Case("Simple file test", test_simple_file_test), + Case("Small file test", test_write_file_test<32, 31, 29>), + Case("Medium file test", test_write_file_test<8192, 31, 29>), + Case("Large file test", test_write_file_test<262144, 31, 29>), + Case("Block Size file test", test_write_file_test<9000, 512, 512>), + Case("Multiple block size file test", test_write_file_test<26215, MBED_TEST_BUFFER, MBED_TEST_BUFFER>), + Case("Non-overlap check", test_non_overlap_check), + Case("Dir check", test_dir_check), +}; + +Specification specification(test_setup, cases); + +int main() +{ + return !Harness::run(specification); +} diff --git a/components/storage/blockdevice/COMPONENT_SDIO/TESTS/filesystem/fopen/fopen.cpp b/components/storage/blockdevice/COMPONENT_SDIO/TESTS/filesystem/fopen/fopen.cpp new file mode 100644 index 00000000000..03c6fda4501 --- /dev/null +++ b/components/storage/blockdevice/COMPONENT_SDIO/TESTS/filesystem/fopen/fopen.cpp @@ -0,0 +1,1621 @@ +/* + * mbed Microcontroller Library + * Copyright (c) 2006-2016 ARM Limited + * + * 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 fopen.cpp Test cases to POSIX file fopen() interface. + * + * Please consult the documentation under the test-case functions for + * a description of the individual test case. + */ + +#include "mbed.h" +#include "mbed_config.h" +#include "SDIOBlockDevice.h" +#include "FATFileSystem.h" +#include "fsfat_debug.h" +#include "fsfat_test.h" +#include "utest/utest.h" +#include "unity/unity.h" +#include "greentea-client/test_env.h" + +#include +#include +#include /*rand()*/ +#include +#include +/* mbed_retarget.h is included after errno.h so symbols are mapped to + * consistent values for all toolchains */ +#include "platform/mbed_retarget.h" + +using namespace utest::v1; + +/// @cond FSFAT_DOXYGEN_DISABLE +#ifdef FSFAT_DEBUG +#define FSFAT_FOPEN_GREENTEA_TIMEOUT_S 3000 +#else +#define FSFAT_FOPEN_GREENTEA_TIMEOUT_S 1000 +#endif +/// @endcond + + +/* DEVICE_SPI + * This symbol is defined in targets.json if the target has a SPI interface, which is required for SDCard support. + * + * MBED_CONF_APP_FSFAT_SDCARD_INSTALLED + * For testing purposes, an SDCard must be installed on the target for the test cases in this file to succeed. + * If the target has an SD card installed then the MBED_CONF_APP_FSFAT_SDCARD_INSTALLED will be generated + * from the mbed_app.json, which includes the line + * { + * "config": { + * "UART_RX": "D0", + * <<< lines removed >>> + * "DEVICE_SPI": 1, + * "FSFAT_SDCARD_INSTALLED": 1 + * }, + * <<< lines removed >>> + */ + +#if defined(DEVICE_SPI) && ( defined(MBED_CONF_APP_FSFAT_SDCARD_INSTALLED) || (MBED_CONF_SD_FSFAT_SDCARD_INSTALLED)) +static char fsfat_fopen_utest_msg_g[FSFAT_UTEST_MSG_BUF_SIZE]; +#define FSFAT_FOPEN_TEST_MOUNT_PT_NAME "sd" +#define FSFAT_FOPEN_TEST_MOUNT_PT_PATH "/" FSFAT_FOPEN_TEST_MOUNT_PT_NAME +#define FSFAT_FOPEN_TEST_WORK_BUF_SIZE_1 64 +#define FSFAT_FOPEN_TEST_FILEPATH_MAX_DEPTH 20 +static const char *sd_badfile_path = "/sd/badfile.txt"; +static const char *sd_testfile_path = "/sd/test.txt"; + +SDIOBlockDevice sd(); +FATFileSystem fs("sd", &sd); + +#define FSFAT_FOPEN_TEST_01 fsfat_fopen_test_01 +#define FSFAT_FOPEN_TEST_02 fsfat_fopen_test_02 +#define FSFAT_FOPEN_TEST_03 fsfat_fopen_test_03 +#define FSFAT_FOPEN_TEST_04 fsfat_fopen_test_04 +#define FSFAT_FOPEN_TEST_05 fsfat_fopen_test_05 +#define FSFAT_FOPEN_TEST_06 fsfat_fopen_test_06 +#define FSFAT_FOPEN_TEST_07 fsfat_fopen_test_07 +#define FSFAT_FOPEN_TEST_08 fsfat_fopen_test_08 +#define FSFAT_FOPEN_TEST_09 fsfat_fopen_test_09 +#define FSFAT_FOPEN_TEST_10 fsfat_fopen_test_10 +#define FSFAT_FOPEN_TEST_11 fsfat_fopen_test_11 +#define FSFAT_FOPEN_TEST_12 fsfat_fopen_test_12 +#define FSFAT_FOPEN_TEST_13 fsfat_fopen_test_13 +#define FSFAT_FOPEN_TEST_14 fsfat_fopen_test_14 +#define FSFAT_FOPEN_TEST_15 fsfat_fopen_test_15 +#define FSFAT_FOPEN_TEST_16 fsfat_fopen_test_16 +#define FSFAT_FOPEN_TEST_17 fsfat_fopen_test_17 +#define FSFAT_FOPEN_TEST_18 fsfat_fopen_test_18 +#define FSFAT_FOPEN_TEST_19 fsfat_fopen_test_19 +#define FSFAT_FOPEN_TEST_20 fsfat_fopen_test_20 +#define FSFAT_FOPEN_TEST_21 fsfat_fopen_test_21 +#define FSFAT_FOPEN_TEST_22 fsfat_fopen_test_22 +#define FSFAT_FOPEN_TEST_23 fsfat_fopen_test_23 +#define FSFAT_FOPEN_TEST_24 fsfat_fopen_test_24 +#define FSFAT_FOPEN_TEST_25 fsfat_fopen_test_25 +#define FSFAT_FOPEN_TEST_26 fsfat_fopen_test_26 +#define FSFAT_FOPEN_TEST_27 fsfat_fopen_test_27 +#define FSFAT_FOPEN_TEST_28 fsfat_fopen_test_28 +#define FSFAT_FOPEN_TEST_29 fsfat_fopen_test_29 +#define FSFAT_FOPEN_TEST_30 fsfat_fopen_test_30 + + +/* support functions */ + +/* + * open tests that focus on testing fopen() + * fsfat_handle_t fopen(const char* filename, char* data, size_t* len, fsfat_key_desc_t* kdesc) + */ + +/* file data for test_01 */ +static fsfat_kv_data_t fsfat_fopen_test_01_kv_data[] = { + { "/sd/fopentst/hello/world/animal/wobbly/dog/foot/frontlft.txt", "missing"}, + { NULL, NULL}, +}; + + +/** @brief + * Split a file path into its component parts, setting '/' characters to '\0', and returning + * pointers to the file path components in the parts array. For example, if + * filepath = "/sd/fopentst/hello/world/animal/wobbly/dog/foot/frontlft.txt" then + * *parts[0] = "sd" + * *parts[1] = "fopentst" + * *parts[2] = "hello" + * *parts[3] = "world" + * *parts[4] = "animal" + * *parts[5] = "wobbly" + * *parts[6] = "dog" + * *parts[7] = "foot" + * *parts[8] = "frontlft.txt" + * parts[9] = NULL + * + * ARGUMENTS + * @param filepath IN file path string to split into component parts. Expected to start with '/' + * @param parts IN OUT array to hold pointers to parts + * @param num IN number of components available in parts + * + * @return On success, this returns the number of components in the filepath Returns number of compoee + */ +static int32_t fsfat_filepath_split(char *filepath, char *parts[], uint32_t num) +{ + uint32_t i = 0; + int32_t ret = -1; + char *z = filepath; + + while (i < num && *z != '\0') { + if (*z == '/' ) { + *z = '\0'; + parts[i] = ++z; + i++; + } else { + z++; + } + } + if (*z == '\0' && i > 0) { + ret = (int32_t) i; + } + return ret; +} + + +/** @brief + * remove all directories and file in the given filepath + * + * ARGUMENTS + * @param filepath IN file path string to split into component parts. Expected to start with '/' + * + * @return On success, this returns 0, otherwise < 0 is returned; + */ +int32_t fsfat_filepath_remove_all(char *filepath) +{ + int32_t ret = -1; + int32_t len = 0; + char *fpathbuf = NULL; + char *pos = NULL; + + FSFAT_FENTRYLOG("%s:entered\n", __func__); + len = strlen(filepath); + fpathbuf = (char *) malloc(len + 1); + if (fpathbuf == NULL) { + FSFAT_DBGLOG("%s: failed to duplicate string (out of memory)\n", __func__); + return ret; + } + memset(fpathbuf, 0, len + 1); + memcpy(fpathbuf, filepath, len); + + /* delete the leaf node first, and then successively parent directories. */ + pos = fpathbuf + strlen(fpathbuf); + while (pos != fpathbuf) { + /* If the remaining file path is the mount point path then finish as the mount point cannot be removed */ + if (strlen(fpathbuf) == strlen(FSFAT_FOPEN_TEST_MOUNT_PT_PATH)) { + if ( strncmp(fpathbuf, FSFAT_FOPEN_TEST_MOUNT_PT_PATH, strlen(fpathbuf)) == 0) { + break; + } + } + ret = remove(fpathbuf); + pos = strrchr(fpathbuf, '/'); + *pos = '\0'; + } + if (fpathbuf) { + free(fpathbuf); + } + return ret; +} + + +/** @brief + * make all directories in the given filepath. Do not create the file if present at end of filepath + * + * ARGUMENTS + * @param filepath IN file path containing directories and file + * @param do_asserts IN set to true if function should assert on errors + * + * @return On success, this returns 0, otherwise < 0 is returned; + */ +static int32_t fsfat_filepath_make_dirs(char *filepath, bool do_asserts) +{ + int32_t i = 0; + int32_t num_parts = 0; + int32_t len = 0; + int32_t ret = -1; + char *fpathbuf = NULL; + char *buf = NULL; + int pos = 0; + char *parts[FSFAT_FOPEN_TEST_FILEPATH_MAX_DEPTH]; + + FSFAT_DBGLOG("%s:entered\n", __func__); + /* find the dirs to create*/ + memset(parts, 0, sizeof(parts)); + len = strlen(filepath); + fpathbuf = (char *) malloc(len + 1); + if (fpathbuf == NULL) { + FSFAT_DBGLOG("%s: failed to duplicate string (out of memory)\n", __func__); + return ret; + } + memset(fpathbuf, 0, len + 1); + memcpy(fpathbuf, filepath, len); + num_parts = fsfat_filepath_split(fpathbuf, parts, FSFAT_FOPEN_TEST_FILEPATH_MAX_DEPTH); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, + "%s:Error: failed to split filepath (filename=\"%s\", num_parts=%d)\n", __func__, filepath, (int) num_parts); + TEST_ASSERT_MESSAGE(num_parts > 0, fsfat_fopen_utest_msg_g); + + /* Now create the directories on the directory path. + * Skip creating dir for "/sd" which must be present */ + buf = (char *) malloc(strlen(filepath) + 1); + memset(buf, 0, strlen(filepath) + 1); + pos = sprintf(buf, "/%s", parts[0]); + for (i = 1; i < num_parts - 1; i++) { + pos += sprintf(buf + pos, "/%s", parts[i]); + FSFAT_DBGLOG("mkdir(%s)\n", buf); + ret = mkdir(buf, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); + if (do_asserts == true) { + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, + "%s:Error: failed to create directory (filepath2=\"%s\", ret=%d, errno=%d)\n", __func__, buf, (int) ret, errno); + TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g); + } + } + + if (buf) { + free(buf); + } + if (fpathbuf) { + free(fpathbuf); + } + return ret; +} + + +/* FIX ME: errno not set correctly when error occurs. This indicates a problem with the implementation. */ + +/** @brief + * Basic fopen test which does the following: + * - creates file and writes some data to the value blob. + * - closes the newly created file. + * - opens the file (r-only) + * - reads the file data and checks its the same as the previously created data. + * - closes the opened file + * + * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors. + */ +static control_t fsfat_fopen_test_01(const size_t call_count) +{ + char *read_buf; + int32_t ret = 0; + size_t len = 0; + fsfat_kv_data_t *node; + FILE *fp = NULL; + + FSFAT_DBGLOG("%s:entered\n", __func__); + (void) call_count; + node = fsfat_fopen_test_01_kv_data; + + /* remove file and directory from a previous failed test run, if present */ + fsfat_filepath_remove_all((char *) node->filename); + + /* create dirs */ + ret = fsfat_filepath_make_dirs((char *) node->filename, true); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, + "%s:Error: failed to create dirs for filename (filename=\"%s\")(ret=%d)\n", __func__, node->filename, (int) ret); + TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g); + + FSFAT_DBGLOG("%s:About to create new file (filename=\"%s\", data=\"%s\")\n", __func__, node->filename, node->value); + fp = fopen(node->filename, "w+"); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, + "%s:Error: failed to create file (filename=\"%s\", data=\"%s\")(ret=%d, errno=%d)\n", __func__, node->filename, + node->value, (int) ret, errno); + TEST_ASSERT_MESSAGE(fp != NULL, fsfat_fopen_utest_msg_g); + + FSFAT_DBGLOG("%s:length of file=%d (filename=\"%s\", data=\"%s\")\n", __func__, (int) len, node->filename, node->value); + len = strlen(node->value); + ret = fwrite((const void *) node->value, len, 1, fp); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, + "%s:Error: failed to write file (filename=\"%s\", data=\"%s\")(ret=%d)\n", __func__, node->filename, node->value, + (int) ret); + TEST_ASSERT_MESSAGE(ret == 1, fsfat_fopen_utest_msg_g); + + FSFAT_DBGLOG("Created file successfully (filename=\"%s\", data=\"%s\")\n", node->filename, node->value); + ret = fclose(fp); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, + "%s:Error: failed to close file (ret=%d, errno=%d)\n", __func__, (int) ret, errno); + TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g); + + /* now open the newly created key */ + fp = NULL; + fp = fopen(node->filename, "r"); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, + "%s:Error: failed to open file for reading (filename=\"%s\", data=\"%s\")(ret=%d)\n", __func__, node->filename, + node->value, (int) ret); + TEST_ASSERT_MESSAGE(fp != NULL, fsfat_fopen_utest_msg_g); + + len = strlen(node->value) + 1; + read_buf = (char *) malloc(len); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, + "%s:Error: failed to allocated read buffer \n", __func__); + TEST_ASSERT_MESSAGE(read_buf != NULL, fsfat_fopen_utest_msg_g); + + FSFAT_DBGLOG("Opened file successfully (filename=\"%s\", data=\"%s\")\n", node->filename, node->value); + memset(read_buf, 0, len); + ret = fread((void *) read_buf, len, 1, fp); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, + "%s:Error: failed to read file (filename=\"%s\", data=\"%s\", read_buf=\"%s\", ret=%d)\n", __func__, node->filename, + node->value, read_buf, (int) ret); + /* FIX ME: fread should return the number of items read, not 0 when an item is read successfully. + * This indicates a problem with the implementation, as the correct data is read. The correct assert should be: + * TEST_ASSERT_MESSAGE(ret == 1, fsfat_fopen_utest_msg_g); + * The following assert is curerntly used until the implementation is fixed + */ + TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g); + + /* check read data is as expected */ + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, + "%s:Error: read value data (%s) != expected value data (filename=\"%s\", data=\"%s\", read_buf=\"%s\", ret=%d)\n", + __func__, read_buf, node->filename, node->value, read_buf, (int) ret); + TEST_ASSERT_MESSAGE(strncmp(read_buf, node->value, strlen(node->value)) == 0, fsfat_fopen_utest_msg_g); + + if (read_buf) { + free(read_buf); + } + ret = fclose(fp); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, + "%s:Error: fclose() call failed (ret=%d, errno=%d).\n", __func__, (int) ret, errno); + TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g); + return CaseNext; +} + +static fsfat_kv_data_t fsfat_fopen_test_02_data[] = { + FSFAT_INIT_1_TABLE_MID_NODE, + { NULL, NULL}, +}; + +/** + * @brief test to fopen() a pre-existing key and try to write it, which should fail + * as by default pre-existing keys are opened read-only + * + * Basic open test which does the following: + * - creates file with default rw perms and writes some data to the value blob. + * - closes the newly created file. + * - opens the file with the default permissions (read-only) + * - tries to write the file data which should fail because file was not opened with write flag set. + * - closes the opened key + * + * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors. + */ +control_t fsfat_fopen_test_02(const size_t call_count) +{ + int32_t ret = -1; + size_t len = 0; + FILE *fp = NULL; + + FSFAT_FENTRYLOG("%s:entered\n", __func__); + (void) call_count; + len = strlen(fsfat_fopen_test_02_data[0].value); + ret = fsfat_test_create(fsfat_fopen_test_02_data[0].filename, (char *) fsfat_fopen_test_02_data[0].value, len); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, + "%s:Error: failed to create file (ret=%d).\n", __func__, (int) ret); + TEST_ASSERT_MESSAGE(ret >= 0, fsfat_fopen_utest_msg_g); + + /* by default, owner of key opens with read-only permissions*/ + fp = fopen(fsfat_fopen_test_02_data[0].filename, "r"); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, + "%s:Error: failed to open file (filename=\"%s\", ret=%d)\n", __func__, fsfat_fopen_test_02_data[0].filename, (int) ret); + TEST_ASSERT_MESSAGE(fp != NULL, fsfat_fopen_utest_msg_g); + + len = strlen(fsfat_fopen_test_02_data[0].value); + ret = fwrite((const void *) fsfat_fopen_test_02_data[0].value, len, 1, fp); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, + "%s:Error: call to fwrite() succeeded when should have failed for read-only file (filename=\"%s\")(ret=%d).\n", + __func__, fsfat_fopen_test_02_data[0].filename, (int) ret); + TEST_ASSERT_MESSAGE(ret <= 0, fsfat_fopen_utest_msg_g); + + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, "%s:Error: fclose() call failed.\n", + __func__); + TEST_ASSERT_MESSAGE(fclose(fp) == 0, fsfat_fopen_utest_msg_g); + + return CaseNext; +} + + +/** + * @brief test to fopen() a pre-existing file and try to write it, which should succeed + * because the key was opened read-write permissions explicitly + * + * Basic open test which does the following: + * - creates file with default rw perms and writes some data to the value blob. + * - closes the newly created file. + * - opens the file with the rw permissions (non default) + * - tries to write the file data which should succeeds because file was opened with write flag set. + * - closes the opened key + * + * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors. + */ +control_t fsfat_fopen_test_03(const size_t call_count) +{ + int32_t ret = -1; + size_t len = 0; + FILE *fp = NULL; + + FSFAT_FENTRYLOG("%s:entered\n", __func__); + (void) call_count; + len = strlen(fsfat_fopen_test_02_data[0].value); + ret = fsfat_test_create(fsfat_fopen_test_02_data[0].filename, (char *) fsfat_fopen_test_02_data[0].value, len); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, + "%s:Error: failed to create file in store (ret=%d).\n", __func__, (int) ret); + TEST_ASSERT_MESSAGE(ret >= 0, fsfat_fopen_utest_msg_g); + + /* opens with read-write permissions*/ + fp = fopen(fsfat_fopen_test_02_data[0].filename, "w+"); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, + "%s:Error: failed to open file (filename=\"%s\")(ret=%d)\n", __func__, fsfat_fopen_test_02_data[0].filename, (int) ret); + TEST_ASSERT_MESSAGE(ret >= 0, fsfat_fopen_utest_msg_g); + + len = strlen(fsfat_fopen_test_02_data[0].value); + ret = fwrite((const void *) fsfat_fopen_test_02_data[0].value, len, 1, fp); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, + "%s:Error: call to fwrite() failed when should have succeeded (filename=\"%s\", ret=%d).\n", __func__, + fsfat_fopen_test_02_data[0].filename, (int) ret); + TEST_ASSERT_MESSAGE(ret >= 0, fsfat_fopen_utest_msg_g); + + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, "%s:Error: fclose() call failed.\n", + __func__); + TEST_ASSERT_MESSAGE(fclose(fp) >= 0, fsfat_fopen_utest_msg_g); + + /* clean-up */ + ret = remove(fsfat_fopen_test_02_data[0].filename); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, + "%s:Error: unable to delete file (filename=%s, ret=%d) .\n", __func__, fsfat_fopen_test_02_data[0].filename, (int) ret); + TEST_ASSERT_MESSAGE(ret >= 0, fsfat_fopen_utest_msg_g); + + return CaseNext; +} + + +/** @brief test to call fopen() with a filename string that exceeds the maximum length + * - chanFS supports the exFAT format which should support 255 char filenames + * - check that filenames of this length can be created + * + * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors. + */ +control_t fsfat_fopen_test_04(const size_t call_count) +{ + char filename_good[FSFAT_FILENAME_MAX_LENGTH + 1]; + char filename_bad[FSFAT_FILENAME_MAX_LENGTH + 2]; + int32_t ret = -1; + size_t len = 0; + + FSFAT_FENTRYLOG("%s:entered\n", __func__); + (void) call_count; + + memset(filename_good, 0, FSFAT_FILENAME_MAX_LENGTH + 1); + memset(filename_bad, 0, FSFAT_FILENAME_MAX_LENGTH + 2); + ret = fsfat_test_filename_gen(filename_good, FSFAT_FILENAME_MAX_LENGTH); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, + "%s:Error: unable to generate filename_good.\n", __func__); + TEST_ASSERT_MESSAGE(ret >= 0, fsfat_fopen_utest_msg_g); + + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, + "%s:Error: filename_good is not the correct length (filename_good=%s, len=%d, expected=%d).\n", __func__, filename_good, + (int) strlen(filename_good), (int) FSFAT_FILENAME_MAX_LENGTH); + TEST_ASSERT_MESSAGE(strlen(filename_good) == FSFAT_FILENAME_MAX_LENGTH, fsfat_fopen_utest_msg_g); + + ret = fsfat_test_filename_gen(filename_bad, FSFAT_FILENAME_MAX_LENGTH + 1); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, + "%s:Error: unable to generate filename_bad.\n", __func__); + TEST_ASSERT_MESSAGE(ret >= 0, fsfat_fopen_utest_msg_g); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, + "%s:Error: filename_bad is not the correct length (len=%d, expected=%d).\n", __func__, (int) strlen(filename_bad), + (int) FSFAT_FILENAME_MAX_LENGTH + 1); + TEST_ASSERT_MESSAGE(strlen(filename_bad) == FSFAT_FILENAME_MAX_LENGTH + 1, fsfat_fopen_utest_msg_g); + + len = strlen(filename_good); + ret = fsfat_test_create(filename_good, filename_good, len); + /* FIXME: + * The current implementation can create file with a filename with 9 chars (more than the 8 restriction of FAT32 Short File Names). + * However, the exFAT 255 char filesnames is not supported and hence the following is commented out. Find out what is + * the supported max filename length and change this testcase according. + * + * FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, "%s:Error: failed to create file (filename=%s, ret=%d).\n", __func__, filename_good, (int) ret); + * TEST_ASSERT_MESSAGE(ret >= 0, fsfat_fopen_utest_msg_g); + */ + + len = strlen(filename_bad); + ret = fsfat_test_create(filename_bad, filename_bad, len); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, + "%s:Error: created file in store for filename_bad when should have failed (filename=%s, ret=%d).\n", __func__, + filename_bad, (int) ret); + TEST_ASSERT_MESSAGE(ret < 0, fsfat_fopen_utest_msg_g); + return CaseNext; +} + + +/// @cond FSFAT_DOXYGEN_DISABLE +typedef struct fsfat_fopen_kv_name_ascii_node { + uint32_t code; + uint32_t f_allowed : 1; +} fsfat_fopen_kv_name_ascii_node; +/// @endcond + +static const uint32_t fsfat_fopen_kv_name_ascii_table_code_sentinel_g = 256; + +/*@brief table recording ascii character codes permitted in kv names */ +static fsfat_fopen_kv_name_ascii_node fsfat_fopen_kv_name_ascii_table[] = { + {0, true}, /* code 0-33 allowed*/ + {34, false}, /* '"' not allowed */ + {35, true}, /* allowed */ + {42, false}, /* '*' not allowed */ + {43, true}, /* allowed */ + {47, false}, /* '/' not allowed */ + {48, true}, /* allowed */ + {58, false}, /* ':' not allowed */ + {59, true}, /* allowed */ + {60, false}, /* '<' not allowed */ + {61, true}, /* allowed */ + {62, false}, /* '?', '>' not allowed */ + {64, true}, /* allowed */ + {92, false}, /* '\' not allowed */ + {93, true}, /* allowed */ + {124, false}, /* '!' not allowed */ + {125, true}, /* allowed */ + {127, false}, /* DEL not allowed */ + {128, true}, /* allowed */ + {fsfat_fopen_kv_name_ascii_table_code_sentinel_g, false}, /* sentinel */ +}; + + +/// @cond FSFAT_DOXYGEN_DISABLE +enum fsfat_fopen_kv_name_pos { + fsfat_fopen_kv_name_pos_start = 0x0, + fsfat_fopen_kv_name_pos_mid, + fsfat_fopen_kv_name_pos_end, + fsfat_fopen_kv_name_pos_max +}; +/// @endcond + +/** @brief test to call fopen() with filename that in includes illegal characters + * - the character(s) can be at the beginning of the filename + * - the character(s) can be at the end of the filename + * - the character(s) can be somewhere within the filename string + * - a max-length string of random characters (legal and illegal) + * - a max-length string of random illegal characters only + * + * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors. + */ +control_t fsfat_fopen_test_05(const size_t call_count) +{ + bool f_allowed = false; + const char *mnt_pt = FSFAT_FOPEN_TEST_MOUNT_PT_PATH; + const char *basename = "goodfile"; + const char *extname = "txt"; + const size_t basename_len = strlen(basename); + const size_t filename_len = strlen(mnt_pt) + strlen(basename) + strlen(extname) + + 2; /* extra 2 chars for '/' and '.' in "/sd/goodfile.txt" */ + char filename[FSFAT_BUF_MAX_LENGTH]; + size_t len = 0; + uint32_t j = 0; + int32_t ret = 0; + fsfat_fopen_kv_name_ascii_node *node = NULL; + uint32_t pos; + + FSFAT_FENTRYLOG("%s:entered\n", __func__); + (void) call_count; + +#ifdef FSFAT_DEBUG + /* symbol only used why debug is enabled */ + const char *pos_str = NULL; +#endif + + /* create bad keyname strings with invalid character code at start of keyname */ + node = fsfat_fopen_kv_name_ascii_table; + memset(filename, 0, FSFAT_BUF_MAX_LENGTH); + while (node->code != fsfat_fopen_kv_name_ascii_table_code_sentinel_g) { + /* loop over range */ + for (j = node->code; j < (node + 1)->code; j++) { + if ( (j >= 48 && j <= 57) || (j >= 65 && j <= 90) || (j >= 97 && j <= 122)) { + FSFAT_DBGLOG("%s: skipping alpha-numeric ascii character code %d (%c).\n", __func__, (int) j, (char) j); + continue; + } + + /* set the start, mid, last character of the name to the test char code */ + for (pos = (uint32_t) fsfat_fopen_kv_name_pos_start; pos < (uint32_t) fsfat_fopen_kv_name_pos_max; pos++) { + len = snprintf(filename, filename_len + 1, "%s/%s.%s", mnt_pt, basename, extname); + /* overwrite a char at the pos start, mid, end of the filename with an ascii char code (both illegal and legal)*/ + switch (pos) { + case fsfat_fopen_kv_name_pos_start: + filename[5] = (char) j; /* 5 so at to write the second basename char (bad chars as first char not accepted)*/ + break; + case fsfat_fopen_kv_name_pos_mid: + /* create bad keyname strings with invalid character code in the middle of keyname */ + filename[5 + basename_len / 2] = (char) j; + break; + case fsfat_fopen_kv_name_pos_end: + /* create bad keyname strings with invalid character code at end of keyname */ + filename[5 + basename_len - 1] = (char) j; + break; + default: + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, + "%s:Error: unexpected value of pos (pos=%d).\n", __func__, (int) pos); + TEST_ASSERT_MESSAGE(ret >= 0, fsfat_fopen_utest_msg_g); + break; + } + +#ifdef FSFAT_DEBUG + /* processing only required when debug trace enabled */ + switch (pos) { + case fsfat_fopen_kv_name_pos_start: + pos_str = "start"; + break; + case fsfat_fopen_kv_name_pos_mid: + pos_str = "middle"; + break; + case fsfat_fopen_kv_name_pos_end: + pos_str = "end"; + break; + default: + break; + } +#endif + ret = fsfat_test_create(filename, (const char *) filename, len); + + /* special cases */ + switch (j) { + //case 0 : + //case 46 : + // switch(pos) + // { + // /* for code = 0 (null terminator). permitted at mid and end of string */ + // /* for code = 46 ('.'). permitted at mid and end of string but not at start */ + // case fsfat_fopen_kv_name_pos_start: + // f_allowed = false; + // break; + // case fsfat_fopen_kv_name_pos_mid: + // case fsfat_fopen_kv_name_pos_end: + // default: + // f_allowed = true; + // break; + // } + // break; + default: + f_allowed = node->f_allowed; + break; + } + if (f_allowed == true) { + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, + "%s:Error: failed to create file in store when filename contains valid characters (code=%d, ret=%d).\n", __func__, + (int) j, (int) ret); + TEST_ASSERT_MESSAGE(ret >= 0, fsfat_fopen_utest_msg_g); + /* revert FSFAT_LOG for more trace */ + FSFAT_DBGLOG("Successfully created a file with valid keyname containing ascii character code %d (%c) at the %s of the keyname.\n", + (int) j, (int) j, pos_str); + FSFAT_LOG("%c", '.'); + + ret = fsfat_test_delete(filename); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, + "%s:Error: failed to delete file previously created (code=%d, ret=%d).\n", __func__, (int) j, (int) ret); + TEST_ASSERT_MESSAGE(ret >= 0, fsfat_fopen_utest_msg_g); + } else { + /*node->f_allowed == false => not allowed to create kv name with ascii code */ + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, + "%s:Error: created file in store when filename contains an invalid character (code=%d, ret=%d).\n", __func__, (int) j, + (int) ret); + TEST_ASSERT_MESSAGE(ret < 0, fsfat_fopen_utest_msg_g); + /* revert FSFAT_LOG for more trace */ + FSFAT_DBGLOG("Successfully failed to create a file with an invalid keyname containing ascii character code %d at the %s of the keyname.\n", + (int) j, pos_str); + FSFAT_LOG("%c", '.'); + } + } + } + node++; + } + + FSFAT_LOG("%c", '\n'); + return CaseNext; +} + + +static const char fsfat_fopen_ascii_illegal_buf_g[] = "\"�'*+,./:;<=>?[\\]|"; + +/** @brief test to call fopen() with filename that in includes + * illegal characters + * - a max-length string of random illegal characters only + * + * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors. + */ +control_t fsfat_fopen_test_06(const size_t call_count) +{ + const char *mnt_pt = FSFAT_FOPEN_TEST_MOUNT_PT_PATH; + const char *extname = "txt"; + const size_t filename_len = strlen(mnt_pt) + FSFAT_MAX_FILE_BASENAME + strlen(extname) + + 2; /* extra 2 chars for '/' and '.' in "/sd/goodfile.txt" */ + char filename[FSFAT_BUF_MAX_LENGTH]; + int32_t i = 0; + int32_t j = 0; + uint32_t pos = 0; + uint32_t len = 0; + int32_t ret = -1; + size_t buf_data_max = 0; + + FSFAT_FENTRYLOG("%s:entered\n", __func__); + (void) call_count; + + memset(filename, 0, FSFAT_BUF_MAX_LENGTH); + /* create bad keyname strings with invalid character code at start of keyname */ + buf_data_max = strlen(fsfat_fopen_ascii_illegal_buf_g); + + /* generate a number of illegal filenames */ + for (j = 0; i < FSFAT_MAX_FILE_BASENAME; j++) { + /* generate a kv name of illegal chars*/ + len = snprintf(filename, filename_len + 1, "%s/", mnt_pt); + for (i = 0; i < FSFAT_MAX_FILE_BASENAME; i++) { + pos = rand() % (buf_data_max + 1); + len += snprintf(filename + len, filename_len + 1, "%c", fsfat_fopen_ascii_illegal_buf_g[pos]); + + } + len += snprintf(filename + len, filename_len + 1, ".%s", extname); + ret = fsfat_test_create(filename, filename, len); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, + "%s:Error: created file when filename contains invalid characters (filename=%s, ret=%d).\n", __func__, filename, + (int) ret); + TEST_ASSERT_MESSAGE(ret < 0, fsfat_fopen_utest_msg_g); + } + return CaseNext; +} + + +/** @brief test for errno reporting on a failed fopen()call + * + * This test does the following: + * - tries to open a file that does not exist for reading, and checks that a NULL pointer is returned. + * - checks that errno is not 0 as there is an error. + * - checks that ferror() returns 1 indicating an error exists. + * + * Note: see NOTE_1 below. + * + * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors. + */ +control_t fsfat_fopen_test_07(const size_t call_count) +{ + FILE *f = NULL; + int ret = -1; + int errno_val = 0; + const char *filename = sd_badfile_path; + + FSFAT_FENTRYLOG("%s:entered\n", __func__); + (void) call_count; + + errno = 0; + /* this is expect to fail as the file doesnt exist */ + f = fopen(filename, "r"); + + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, + "%s:Error: opened non-existent file for reading (filename=%s, f=%p).\n", __func__, filename, f); + TEST_ASSERT_MESSAGE(f == NULL, fsfat_fopen_utest_msg_g); + + /* check errno is set correctly */ +#if ! defined(__ARMCC_VERSION) && defined(__GNUC__) + /* Store errno so the current value set is not changed by new function call */ + errno_val = errno; + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, + "%s:Error: errno has unexpected value (errno != 0 expected) (filename=%s, errno=%d).\n", __func__, filename, errno); + TEST_ASSERT_MESSAGE(errno_val != 0, fsfat_fopen_utest_msg_g); +#endif /* ! defined(__ARMCC_VERSION) && defined(__GNUC__) */ + return CaseNext; +} + + +/** @brief test for operation of clearerr() and ferror() + * + * The test does the following: + * - opens and then closes a file, but keeps a copy of the FILE pointer fp. + * - set errno to 0. + * - write to the close file with fwrite(fp) which should return 0 (no writes) and set the errno. + * - check the error condition is set with ferror(). + * - clear the error with clearerr(). + * - check the error condition is reset with ferror(). + * + * NOTE_1: GCC/ARMCC support for setting errno + * - Documentation (e.g. fwrite() man page) does not explicity say fwrite() sets errno + * (e.g. for an fwrite() on a read-only file). + * - GCC libc fwrite() appears to set errno as expected. + * - ARMCC & IAR libc fwrite() appears not to set errno. + * + * The following ARMCC documents are silent on whether fwrite() sets errno: + * - "ARM C and C++ Libraries and Floating-Point Support". + * - "RL-ARM User Guide fwrite() section". + * + * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors. + */ +control_t fsfat_fopen_test_08(const size_t call_count) +{ + FILE *fp = NULL; + int ret = -1; + int ret_ferror = -1; + const char *filename = sd_testfile_path; + + FSFAT_FENTRYLOG("%s:entered\n", __func__); + (void) call_count; + + errno = 0; + fp = fopen(filename, "w+"); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, + "%s:Error: failed to open file (filename=%s, f=%p).\n", __func__, filename, fp); + TEST_ASSERT_MESSAGE(fp != NULL, fsfat_fopen_utest_msg_g); + + /* close the fp but then try to read or write it */ + ret = fclose(fp); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, + "%s:Error: failed to close file (ret=%d, errno=%d)\n", __func__, (int) ret, errno); + TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g); + + /* open file */ + errno = 0; + fp = fopen(filename, "r"); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, + "%s:Error: failed to open file for reading (filename=\"%s\", ret=%d)\n", __func__, filename, (int) ret); + TEST_ASSERT_MESSAGE(fp != NULL, fsfat_fopen_utest_msg_g); + + /* Perform fwrite() operation that will fail. */ + errno = 0; + ret = fwrite("42!", 4, 1, fp); + + ret_ferror = ferror(fp); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, + "%s:Error: ferror() failed to report error (filename=%s, ret_ferror=%d).\n", __func__, filename, (int) ret_ferror); + TEST_ASSERT_MESSAGE(ret_ferror != 0, fsfat_fopen_utest_msg_g); + + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, + "%s:Error: fwrite successfully wrote to read-only file (filename=%s, ret=%d).\n", __func__, filename, (int) ret); + /* the fwrite() should fail and return 0. */ + TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g); + +#if ! defined(__ARMCC_VERSION) && defined(__GNUC__) + /* check that errno is set. ARMCC appears not to set errno for fwrite() failure. */ + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, + "%s:Error: unexpected zero value for errno (filename=%s, ret=%d, errno=%d).\n", __func__, filename, (int) ret, errno); + TEST_ASSERT_MESSAGE(errno != 0, fsfat_fopen_utest_msg_g); + + /* check that errno is set to the expected value (this may change differ for different libc's) */ + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, + "%s:Error: errno != EBADF (filename=%s, ret=%d, errno=%d).\n", __func__, filename, (int) ret, errno); + TEST_ASSERT_MESSAGE(errno == EBADF, fsfat_fopen_utest_msg_g); +#endif /* ! defined(__ARMCC_VERSION) && defined(__GNUC__) */ + + /* check clearerr() return clears the error */ + clearerr(fp); + ret = ferror(fp); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, + "%s:Error: ferror() did not return zero value when error has been cleared (filename=%s, ret=%d).\n", __func__, filename, + (int) ret); + TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g); + + fclose(fp); + return CaseNext; +} + + +/** @brief test for operation of ftell() + * + * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors. + */ +control_t fsfat_fopen_test_09(const size_t call_count) +{ + FILE *fp = NULL; + int ret = -1; + int32_t len = 0; + + FSFAT_FENTRYLOG("%s:entered\n", __func__); + (void) call_count; + + /* create a file of a certain length */ + len = strlen(fsfat_fopen_test_02_data[0].value); + ret = fsfat_test_create(fsfat_fopen_test_02_data[0].filename, (char *) fsfat_fopen_test_02_data[0].value, len); + + errno = 0; + /* Open the file for reading so the file is not truncated to 0 length. */ + fp = fopen(fsfat_fopen_test_02_data[0].filename, "r"); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, + "%s:Error: failed to open file (filename=%s, fp=%p, errno=%d).\n", __func__, fsfat_fopen_test_02_data[0].filename, fp, + errno); + TEST_ASSERT_MESSAGE(fp != NULL, fsfat_fopen_utest_msg_g); + + errno = 0; + ret = fseek(fp, 0, SEEK_END); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, + "%s:Error: fseek() failed to SEEK_END (filename=%s, ret=%d, errno=%d).\n", __func__, + fsfat_fopen_test_02_data[0].filename, (int) ret, errno); + TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g); + + errno = 0; + ret = ftell(fp); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, + "%s:Error: ftell() failed to report correct offset value (filename=%s, ret=%d, errno=%d).\n", __func__, + fsfat_fopen_test_02_data[0].filename, (int) ret, errno); + TEST_ASSERT_MESSAGE(ret == len, fsfat_fopen_utest_msg_g); + + errno = 0; + ret = fclose(fp); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, + "%s:Error: failed to close file (ret=%d, errno=%d)\n", __func__, (int) ret, errno); + TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g); + + return CaseNext; +} + + +/* file data for test_10 */ +static fsfat_kv_data_t fsfat_fopen_test_10_kv_data[] = { + { "/sd/test_10/testfile.txt", "test_data"}, + { NULL, NULL}, +}; + +/** @brief test for operation of remove() + * + * Performs the following tests: + * 1. test remove() on a file that exists. This should succeed. + * 2. test remove() on a dir that exists. This should succeed. + * 3. test remove() on a file that doesnt exist. This should fail. check errno set. + * 4. test remove() on a dir that doesnt exist. This should fail. check errno set. + * + * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors. + */ +control_t fsfat_fopen_test_10(const size_t call_count) +{ + char buf[FSFAT_FOPEN_TEST_WORK_BUF_SIZE_1]; + char *pos = NULL; + int32_t ret = -1; + size_t len = 0; + fsfat_kv_data_t *node = fsfat_fopen_test_10_kv_data; + + FSFAT_FENTRYLOG("%s:entered\n", __func__); + (void) call_count; + + TEST_ASSERT(strlen(node->filename) < FSFAT_FOPEN_TEST_WORK_BUF_SIZE_1); + + /* start from a known state i.e. directory to be created in not present */ + fsfat_filepath_remove_all((char *) node->filename); + + /* (1) */ + errno = 0; + ret = fsfat_filepath_make_dirs((char *) node->filename, false); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, + "%s:Error: failed to create dir (dirname=%s, ret=%d, errno=%d)\n", __func__, node->filename, (int) ret, errno); + TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g); + + len = strlen(node->value); + ret = fsfat_test_create(node->filename, (char *) node->value, len); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, + "%s:Error: failed to create file (ret=%d).\n", __func__, (int) ret); + TEST_ASSERT_MESSAGE(ret >= 0, fsfat_fopen_utest_msg_g); + + ret = remove(node->filename); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, + "%s:Error: delete file operation failed (filename=%s, ret=%d) .\n", __func__, node->filename, (int) ret); + TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g); + + /* (3) */ + ret = remove(node->filename); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, + "%s:Error: deleted a file that doesn't exist (filename=%s, ret=%d, errno=%d) .\n", __func__, node->filename, (int) ret, + errno); + TEST_ASSERT_MESSAGE(ret != 0, fsfat_fopen_utest_msg_g); + + /* (2) */ + memset(buf, 0, FSFAT_FOPEN_TEST_WORK_BUF_SIZE_1); + memcpy(buf, node->filename, strlen(node->filename)); + pos = strrchr(buf, '/'); + *pos = '\0'; + ret = remove(buf); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, + "%s:Error: delete directory operation failed (directory name=%s, ret=%d, errno=%d).\n", __func__, buf, (int) ret, + errno); + TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g); + + /* (4) */ + ret = remove(buf); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, + "%s:Error: deleted a directory that doesn't exist (directory name=%s, ret=%d, errno=%d).\n", __func__, buf, (int) ret, + errno); + TEST_ASSERT_MESSAGE(ret != 0, fsfat_fopen_utest_msg_g); + + return CaseNext; +} + + +/* file data for test_11 */ +static fsfat_kv_data_t fsfat_fopen_test_11_kv_data[] = { + { "/sd/test_11/step0.txt", "test_data"}, + { "/sd/test_11/step1.txt", "test_data"}, + { "/sd/test_11/subdir/step3.txt", "test_data"}, + { NULL, NULL}, +}; + +/** @brief test for operation of rename() + * + * This test does the following: + * 1) test rename() on a file that exists to a new filename within the same directory. + * 2) test rename() on a file that exists to a new filename within a different directory. + * + * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors. + */ +control_t fsfat_fopen_test_11(const size_t call_count) +{ + int32_t ret = -1; + size_t len = 0; + fsfat_kv_data_t *node = fsfat_fopen_test_11_kv_data; + + FSFAT_FENTRYLOG("%s:entered\n", __func__); + (void) call_count; + + TEST_ASSERT(strlen(node->filename) < FSFAT_FOPEN_TEST_WORK_BUF_SIZE_1); + + /* start from a known state i.e. directory to be created in not present, files not present */ + while (node->filename != NULL) { + fsfat_filepath_remove_all((char *) node->filename); + node++; + } + + /* create file and directories ready for rename() tests */ + errno = 0; + node = fsfat_fopen_test_11_kv_data; + ret = fsfat_filepath_make_dirs((char *) node->filename, false); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, + "%s:Error: failed to create dir (dirname=%s, ret=%d, errno=%d)\n", __func__, node->filename, (int) ret, errno); + TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g); + + len = strlen(node->value); + ret = fsfat_test_create(node->filename, (char *) node->value, len); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, + "%s:Error: failed to create file (ret=%d).\n", __func__, (int) ret); + TEST_ASSERT_MESSAGE(ret >= 0, fsfat_fopen_utest_msg_g); + + errno = 0; + node = &fsfat_fopen_test_11_kv_data[2]; + ret = fsfat_filepath_make_dirs((char *) node->filename, false); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, + "%s:Error: failed to create dir (dirname=%s, ret=%d, errno=%d)\n", __func__, node->filename, (int) ret, errno); + TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g); + + /* (1) */ + ret = rename(fsfat_fopen_test_11_kv_data[0].filename, fsfat_fopen_test_11_kv_data[1].filename); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, + "%s:Error: unable to rename file from (%s) to (%s) (ret=%d, errno=%d).\n", __func__, + fsfat_fopen_test_11_kv_data[0].filename, fsfat_fopen_test_11_kv_data[1].filename, (int) ret, errno); + TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g); + + /* (2) */ + ret = rename(fsfat_fopen_test_11_kv_data[1].filename, fsfat_fopen_test_11_kv_data[2].filename); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, + "%s:Error: unable to rename file from (%s) to (%s) (ret=%d, errno=%d).\n", __func__, + fsfat_fopen_test_11_kv_data[1].filename, fsfat_fopen_test_11_kv_data[2].filename, (int) ret, errno); + TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g); + + return CaseNext; +} + + +/* file data for test_12 */ +static fsfat_kv_data_t fsfat_fopen_test_12_kv_data[] = { + { "/sd/test_12/subdir/testfil1.txt", "testfil1.txt"}, + { "/sd/test_12/testfil2.txt", "testfil2.txt"}, + { "/sd/test_12/testfil3.txt", "testfil3.txt"}, + { "/sd/test_12/testfil4.txt", "testfil4.txt"}, + { "/sd/test_12/testfil5.txt", "testfil5.txt"}, + { NULL, NULL}, +}; + +/** @brief test for operation of readdir(). + * + * Note, rewinddir(), telldir() and seekdir() dont appear to work reliably. + * opendir() not available on ARM/IAR toolchains. + * + * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors. + */ +control_t fsfat_fopen_test_12(const size_t call_count) +{ + char buf[FSFAT_FOPEN_TEST_WORK_BUF_SIZE_1]; + char *pos = NULL; + int32_t count = 0; + int32_t ret = -1; + size_t len = 0; + DIR *dir; + struct dirent *dp; + fsfat_kv_data_t *node = fsfat_fopen_test_12_kv_data; + + FSFAT_FENTRYLOG("%s:entered\n", __func__); + (void) call_count; + +#if ! defined(__ARMCC_VERSION) && defined(__GNUC__) + + /* start from a known state i.e. directory to be created in not present */ + while (node->filename != NULL) { + fsfat_filepath_remove_all((char *) node->filename); + node++; + } + + /* create a file */ + node = fsfat_fopen_test_12_kv_data; + errno = 0; + ret = fsfat_filepath_make_dirs((char *) node->filename, false); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, + "%s:Error: failed to create dir (dirname=%s, ret=%d, errno=%d)\n", __func__, node->filename, (int) ret, errno); + TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g); + + node = fsfat_fopen_test_12_kv_data; + while (node->filename != NULL) { + len = strlen(node->value); + ret = fsfat_test_create(node->filename, (char *) node->value, len); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, + "%s:Error: failed to create file (ret=%d).\n", __func__, (int) ret); + TEST_ASSERT_MESSAGE(ret >= 0, fsfat_fopen_utest_msg_g); + node++; + } + + node = fsfat_fopen_test_12_kv_data; + memset(buf, 0, FSFAT_FOPEN_TEST_WORK_BUF_SIZE_1); + memcpy(buf, node->filename, strlen(node->filename)); + pos = strrchr(buf, '/'); + *pos = '\0'; + dir = opendir(buf); + + while ((dp = readdir(dir)) != NULL) { + FSFAT_DBGLOG("%s: filename: \"%s\"\n", __func__, dp->d_name); + TEST_ASSERT_MESSAGE(dp != 0, "Error: readdir() failed\n"); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, + "%s:Error: unexpected object name (name=%s, expected=%s).\n", __func__, dp->d_name, + fsfat_fopen_test_12_kv_data[count].value); + TEST_ASSERT_MESSAGE(strncmp(dp->d_name, fsfat_fopen_test_12_kv_data[count].value, + strlen(fsfat_fopen_test_12_kv_data[count].value)) == 0, fsfat_fopen_utest_msg_g); + count++; + } + closedir(dir); + + /* cleanup */ + node = fsfat_fopen_test_12_kv_data; + while (node->filename != NULL) { + fsfat_filepath_remove_all((char *) node->filename); + node++; + } +#endif /* ! defined(__ARMCC_VERSION) && defined(__GNUC__) */ + return CaseNext; +} + + +/* file data for test_13 */ +static fsfat_kv_data_t fsfat_fopen_test_13_kv_data[] = { + /* a file is included in the filepath even though its not created by the test, + * as the fsfat_filepath_make_dirs() works with it present. */ + { "/sd/test_13/dummy.txt", "testdir"}, + { NULL, NULL}, +}; +/** @brief test for operation of mkdir()/remove() + * + * This test checks that: + * - The mkdir() function successfully creates a directory that is not already present. + * - The mkdir() function returns EEXIST when trying to create a directory thats already present. + * - The remove() function successfully removes a directory that is present. + * + * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors. + */ +control_t fsfat_fopen_test_13(const size_t call_count) +{ + int32_t ret = 0; + + FSFAT_DBGLOG("%s:entered\n", __func__); + (void) call_count; + + /* start from a known state i.e. directory to be created in not present */ + fsfat_filepath_remove_all((char *) fsfat_fopen_test_13_kv_data[0].filename); + + errno = 0; + ret = fsfat_filepath_make_dirs((char *) fsfat_fopen_test_13_kv_data[0].filename, false); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, + "%s:Error: failed to create dir (dirname=%s, ret=%d, errno=%d)\n", __func__, fsfat_fopen_test_13_kv_data[0].filename, + (int) ret, errno); + TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g); + + /* check that get a suitable error when try to create it again.*/ + errno = 0; + ret = fsfat_filepath_make_dirs((char *) fsfat_fopen_test_13_kv_data[0].filename, false); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, + "%s:Error: permitted to create directory when already exists (dirname=%s, ret=%d, errno=%d)\n", __func__, + fsfat_fopen_test_13_kv_data[0].filename, (int) ret, errno); + TEST_ASSERT_MESSAGE(ret != 0, fsfat_fopen_utest_msg_g); + + /* check errno is as expected */ + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, + "%s:Error: errno != EEXIST (dirname=%s, ret=%d, errno=%d)\n", __func__, fsfat_fopen_test_13_kv_data[0].filename, + (int) ret, errno); + TEST_ASSERT_MESSAGE(errno == EEXIST, fsfat_fopen_utest_msg_g); + + ret = fsfat_filepath_remove_all((char *) fsfat_fopen_test_13_kv_data[0].filename); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, + "%s:Error: failed to remove directory (dirname=%s, ret=%d, errno=%d)\n", __func__, + fsfat_fopen_test_13_kv_data[0].filename, (int) ret, errno); + TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g); + + return CaseNext; +} + +/* file data for test_14 */ +static fsfat_kv_data_t fsfat_fopen_test_14_kv_data[] = { + /* a file is included in the filepath even though its not created by the test, + * as the fsfat_filepath_make_dirs() works with it present. */ + { "/sd/test_14/testfile.txt", "testdata"}, + { NULL, NULL}, +}; + +/** @brief test for operation of stat() + * + * stat() is currently no supported by ARMCC and IAR toolchains libc. + * + * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors. + */ +control_t fsfat_fopen_test_14(const size_t call_count) +{ +#if ! defined(__ARMCC_VERSION) && defined(__GNUC__) + + char buf[FSFAT_FOPEN_TEST_WORK_BUF_SIZE_1]; + char *pos = NULL; + int32_t ret = -1; + size_t len = 0; + struct stat file_stat; + fsfat_kv_data_t *node = fsfat_fopen_test_14_kv_data; + + FSFAT_FENTRYLOG("%s:entered\n", __func__); + (void) call_count; + + TEST_ASSERT(strlen(node->filename) < FSFAT_FOPEN_TEST_WORK_BUF_SIZE_1); + + /* start from a known state i.e. directory to be created in not present */ + fsfat_filepath_remove_all((char *) node->filename); + + /* Create file in a directory. */ + errno = 0; + ret = fsfat_filepath_make_dirs((char *) node->filename, false); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, + "%s:Error: failed to create dir (dirname=%s, ret=%d, errno=%d)\n", __func__, node->filename, (int) ret, errno); + TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g); + + len = strlen(node->value); + ret = fsfat_test_create(node->filename, (char *) node->value, len); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, + "%s:Error: failed to create file (ret=%d).\n", __func__, (int) ret); + TEST_ASSERT_MESSAGE(ret >= 0, fsfat_fopen_utest_msg_g); + + /* Test stat() on the file returns the correct attribute set */ + memset(&file_stat, 0, sizeof(file_stat)); + ret = stat(node->filename, &file_stat); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, + "%s:Error: stat() operation on file failed (filename=%s, ret=%d, errno=%d).\n", __func__, node->filename, (int) ret, + errno); + TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g); + + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, + "%s:Error: expected st_mode S_IFREG flag not set (filename=%s).\n", __func__, node->filename); + TEST_ASSERT_MESSAGE((file_stat.st_mode & S_IFREG) == S_IFREG, fsfat_fopen_utest_msg_g); + + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, + "%s:Error: unexpected st_mode S_IFDIR flag set (filename=%s).\n", __func__, node->filename); + TEST_ASSERT_MESSAGE((file_stat.st_mode & S_IFDIR) != S_IFDIR, fsfat_fopen_utest_msg_g); + + /* Test stat() on the directory returns the correct attribute set */ + memset(&file_stat, 0, sizeof(file_stat)); + memset(buf, 0, FSFAT_FOPEN_TEST_WORK_BUF_SIZE_1); + memcpy(buf, node->filename, strlen(node->filename)); + pos = strrchr(buf, '/'); + *pos = '\0'; + ret = stat(buf, &file_stat); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, + "%s:Error: stat() operation on directory failed (directory name=%s, ret=%d, errno=%d).\n", __func__, buf, (int) ret, + errno); + TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g); + + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, + "%s:Error: unexpected st_mode S_IFREG flag set (directory name=%s).\n", __func__, buf); + TEST_ASSERT_MESSAGE((file_stat.st_mode & S_IFREG) != S_IFREG, fsfat_fopen_utest_msg_g); + + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, + "%s:Error: expected st_mode S_IFDIR flag not set (directory name=%s).\n", __func__, buf); + TEST_ASSERT_MESSAGE((file_stat.st_mode & S_IFDIR) == S_IFDIR, fsfat_fopen_utest_msg_g); + + /* clean up after successful test */ + fsfat_filepath_remove_all((char *) node->filename); + +#endif /* ! defined(__ARMCC_VERSION) && defined(__GNUC__) */ + return CaseNext; +} + +/** @brief test for operation of SDFileSystem::format() + * + * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors. + */ +control_t fsfat_fopen_test_15(const size_t call_count) +{ + + FSFAT_FENTRYLOG("%s:entered\n", __func__); + (void) call_count; + int32_t ret = -1; + + /* the allocation_unit of 0 means chanFS will use the default for the card (varies according to capacity). */ + fs.unmount(); + ret = fs.format(&sd); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, + "%s:Error: failed to format sdcard (ret=%d)\n", __func__, (int) ret); + TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g); + fs.mount(&sd); + return CaseNext; +} + + +/* @brief test utility function to create a file of a given size. + * + * A reference data table is used of so that the data file can be later be + * checked with fsfat_test_check_data_file(). + * + * @param filename name of the file including path + * @param data data to store in file + * @param len number of bytes of data present in the data buffer. + */ +int32_t fsfat_test_create_data_file(const char *filename, size_t len) +{ + int32_t ret = -1; + FILE *fp = NULL; + size_t write_len = 0; + size_t written_len = 0; + int32_t exp = 0; + const int32_t exp_max = 8; /* so as not to exceed FSFAT_TEST_BYTE_DATA_TABLE_SIZE/2 */ + + FSFAT_FENTRYLOG("%s:entered (filename=%s, len=%d).\n", __func__, filename, (int) len); + TEST_ASSERT(len % FSFAT_TEST_BYTE_DATA_TABLE_SIZE == 0); + fp = fopen(filename, "a"); + if (fp == NULL) { + return ret; + } + + while (written_len < len) { + /* write fsfat_test_byte_data_table or part thereof, in 9 writes of sizes + * 1, 2, 4, 8, 16, 32, 64, 128, 1, totalling 256 bytes len permitting. */ + for (exp = 0; (exp <= exp_max) && (written_len < len); exp++) { + write_len = 0x1 << (exp % exp_max); + write_len = len - written_len > write_len ? write_len : len - written_len; + ret = fwrite((const void *) &fsfat_test_byte_data_table[written_len % FSFAT_TEST_BYTE_DATA_TABLE_SIZE], write_len, 1, + fp); + written_len += write_len; + if (ret != 1) { + FSFAT_DBGLOG("%s:Error: fwrite() failed (ret=%d)\n", __func__, (int) ret); + ret = -1; + goto out0; + } + } + } + if (written_len == len) { + ret = 0; + } else { + ret = -1; + } +out0: + fclose(fp); + return ret; +} + + +/* @brief test utility function to check the data in the specified file is correct. + * + * The data read from the file is check that it agrees with the data written by + * fsfat_test_create_data_file(). + * + * @param filename name of the file including path + * @param data data to store in file + * @param len number of bytes of data present in the data buffer. + */ +int32_t fsfat_test_check_data_file(const char *filename, size_t len) +{ + int32_t ret = -1; + FILE *fp = NULL; + size_t read_len = 0; + uint8_t buf[FSFAT_TEST_BYTE_DATA_TABLE_SIZE]; + + FSFAT_FENTRYLOG("%s:entered (filename=%s, len=%d).\n", __func__, filename, (int) len); + TEST_ASSERT(len % FSFAT_TEST_BYTE_DATA_TABLE_SIZE == 0); + fp = fopen(filename, "r"); + if (fp == NULL) { + return ret; + } + + while (read_len < len) { + ret = fread((void *) buf, FSFAT_TEST_BYTE_DATA_TABLE_SIZE, 1, fp); + read_len += FSFAT_TEST_BYTE_DATA_TABLE_SIZE; + if (ret == 0) { + /* end of read*/ + FSFAT_DBGLOG("%s:unable to read data\n", __func__); + break; + } + if (memcmp(buf, fsfat_test_byte_data_table, FSFAT_TEST_BYTE_DATA_TABLE_SIZE) != 0) { + FSFAT_DBGLOG("%s:Error: read data not as expected (0x%2x, 0x%2x, 0x%2x, 0x%2x, 0x%2x, 0x%2x, 0x%2x, 0x%2x, 0x%2x, 0x%2x, 0x%2x, 0x%2x, 0x%2x, 0x%2x, 0x%2x, 0x%2x\n", + __func__, + buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7], buf[8], buf[9], buf[10], buf[11], buf[12], buf[13], + buf[14], buf[15]); + ret = -1; + goto out0; + } + } + if (read_len == len) { + ret = 0; + } +out0: + fclose(fp); + return ret; +} + +/* file data for test_16 */ +static fsfat_kv_data_t fsfat_fopen_test_16_kv_data[] = { + { "/sd/tst16_0/testfil0.txt", "dummy_data"}, + { "/sd/tst16_1/subdir0/testfil0.txt", "dummy_data"}, + { "/sd/tst16_2/subdir0/subdir1/testfil0.txt", "dummy_data"}, + { "/sd/tst16_3/subdir0/subdir1/subdir2/subdir3/testfil0.txt", "dummy_data"}, + { "/sd/tst16_4/subdir0/subdir1/subdir2/subdir3/subdir4/testfil0.txt", "dummy_data"}, + { "/sd/tst16_5/subdir0/subdir1/subdir2/subdir3/subdir4/subdir5/testfil0.txt", "dummy_data"}, + { "/sd/tst16_6/subdir0/subdir1/subdir2/subdir3/subdir4/subdir5/subdir6/testfil0.txt", "dummy_data"}, + { "/sd/tst16_7/subdir0/subdir1/subdir2/subdir3/subdir4/subdir5/subdir6/subdir7/testfil0.txt", "dummy_data"}, + { "/sd/tst16_8/subdir0/subdir1/subdir2/subdir3/subdir4/subdir5/subdir6/subdir7/subdir8/testfil0.txt", "dummy_data"}, + { "/sd/tst16_9/subdir0/subdir1/subdir2/subdir3/subdir4/subdir5/subdir6/subdir7/subdir8/subdir9/testfil0.txt", "dummy_data"}, + { NULL, NULL}, +}; + + +/** @brief stress test to write data to fs + * + * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors. + */ +control_t fsfat_fopen_test_16(const size_t call_count) +{ + int32_t ret = 0; + fsfat_kv_data_t *node = fsfat_fopen_test_16_kv_data; + const int32_t num_blocks = 100; /* each file ~25kB */ + + FSFAT_DBGLOG("%s:entered\n", __func__); + (void) call_count; + + /* remove file and directory from a previous failed test run, if present */ + while (node->filename != NULL) { + fsfat_filepath_remove_all((char *) node->filename); + node++; + } + + /* create dirs */ + node = fsfat_fopen_test_16_kv_data; + while (node->filename != NULL) { + ret = fsfat_filepath_make_dirs((char *) node->filename, true); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, + "%s:Error: failed to create dirs for filename (filename=\"%s\")(ret=%d)\n", __func__, node->filename, (int) ret); + TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g); + node++; + } + + /* create the data files */ + node = fsfat_fopen_test_16_kv_data; + while (node->filename != NULL) { + ret = fsfat_test_create_data_file(node->filename, num_blocks * FSFAT_TEST_BYTE_DATA_TABLE_SIZE); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, + "%s:Error: failed to create data file (filename=\"%s\")(ret=%d)\n", __func__, node->filename, (int) ret); + TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g); + node++; + } + + /* read the data back and check its as expected */ + node = fsfat_fopen_test_16_kv_data; + while (node->filename != NULL) { + ret = fsfat_test_check_data_file(node->filename, num_blocks * FSFAT_TEST_BYTE_DATA_TABLE_SIZE); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, + "%s:Error: failed to check data file (filename=\"%s\")(ret=%d)\n", __func__, node->filename, (int) ret); + TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g); + node++; + } + + /* clean up */ + node = fsfat_fopen_test_16_kv_data; + while (node->filename != NULL) { + fsfat_filepath_remove_all((char *) node->filename); + node++; + } + return CaseNext; +} + + +#else + + +#define FSFAT_FOPEN_TEST_01 fsfat_fopen_test_dummy +#define FSFAT_FOPEN_TEST_02 fsfat_fopen_test_dummy +#define FSFAT_FOPEN_TEST_03 fsfat_fopen_test_dummy +#define FSFAT_FOPEN_TEST_04 fsfat_fopen_test_dummy +#define FSFAT_FOPEN_TEST_05 fsfat_fopen_test_dummy +#define FSFAT_FOPEN_TEST_06 fsfat_fopen_test_dummy +#define FSFAT_FOPEN_TEST_07 fsfat_fopen_test_dummy +#define FSFAT_FOPEN_TEST_08 fsfat_fopen_test_dummy +#define FSFAT_FOPEN_TEST_09 fsfat_fopen_test_dummy +#define FSFAT_FOPEN_TEST_10 fsfat_fopen_test_dummy +#define FSFAT_FOPEN_TEST_11 fsfat_fopen_test_dummy +#define FSFAT_FOPEN_TEST_12 fsfat_fopen_test_dummy +#define FSFAT_FOPEN_TEST_13 fsfat_fopen_test_dummy +#define FSFAT_FOPEN_TEST_14 fsfat_fopen_test_dummy +#define FSFAT_FOPEN_TEST_15 fsfat_fopen_test_dummy +#define FSFAT_FOPEN_TEST_16 fsfat_fopen_test_dummy +#define FSFAT_FOPEN_TEST_17 fsfat_fopen_test_dummy +#define FSFAT_FOPEN_TEST_18 fsfat_fopen_test_dummy +#define FSFAT_FOPEN_TEST_19 fsfat_fopen_test_dummy +#define FSFAT_FOPEN_TEST_20 fsfat_fopen_test_dummy +#define FSFAT_FOPEN_TEST_21 fsfat_fopen_test_dummy +#define FSFAT_FOPEN_TEST_22 fsfat_fopen_test_dummy +#define FSFAT_FOPEN_TEST_23 fsfat_fopen_test_dummy +#define FSFAT_FOPEN_TEST_24 fsfat_fopen_test_dummy +#define FSFAT_FOPEN_TEST_25 fsfat_fopen_test_dummy +#define FSFAT_FOPEN_TEST_26 fsfat_fopen_test_dummy +#define FSFAT_FOPEN_TEST_27 fsfat_fopen_test_dummy +#define FSFAT_FOPEN_TEST_28 fsfat_fopen_test_dummy +#define FSFAT_FOPEN_TEST_29 fsfat_fopen_test_dummy +#define FSFAT_FOPEN_TEST_30 fsfat_fopen_test_dummy + +/** @brief fsfat_fopen_test_dummy Dummy test case for testing when platform doesnt have an SDCard installed. + * + * @return success always + */ +static control_t fsfat_fopen_test_dummy() +{ + printf("Null test\n"); + return CaseNext; +} + +#endif + + +/// @cond FSFAT_DOXYGEN_DISABLE +utest::v1::status_t greentea_setup(const size_t number_of_cases) +{ + GREENTEA_SETUP(FSFAT_FOPEN_GREENTEA_TIMEOUT_S, "default_auto"); + return greentea_test_setup_handler(number_of_cases); +} + +Case cases[] = { + /* 1 2 3 4 5 6 7 */ + /* 1234567890123456789012345678901234567890123456789012345678901234567890 */ + Case("FSFAT_FOPEN_TEST_01: fopen()/fwrite()/fclose() directories/file in multi-dir filepath.", FSFAT_FOPEN_TEST_01), + Case("FSFAT_FOPEN_TEST_02: fopen(r) pre-existing file try to write it.", FSFAT_FOPEN_TEST_02), + Case("FSFAT_FOPEN_TEST_03: fopen(w+) pre-existing file try to write it.", FSFAT_FOPEN_TEST_03), + Case("FSFAT_FOPEN_TEST_04: fopen() with a filename exceeding the maximum length.", FSFAT_FOPEN_TEST_04), +#ifdef FOPEN_EXTENDED_TESTING + Case("FSFAT_FOPEN_TEST_05: fopen() with bad filenames (extended).", FSFAT_FOPEN_TEST_05), +#endif + Case("FSFAT_FOPEN_TEST_06: fopen() with bad filenames (minimal).", FSFAT_FOPEN_TEST_06), + Case("FSFAT_FOPEN_TEST_07: fopen()/errno handling.", FSFAT_FOPEN_TEST_07), + Case("FSFAT_FOPEN_TEST_08: ferror()/clearerr()/errno handling.", FSFAT_FOPEN_TEST_08), + Case("FSFAT_FOPEN_TEST_09: ftell() handling.", FSFAT_FOPEN_TEST_09), + Case("FSFAT_FOPEN_TEST_10: remove() test.", FSFAT_FOPEN_TEST_10), + Case("FSFAT_FOPEN_TEST_11: rename().", FSFAT_FOPEN_TEST_11), + Case("FSFAT_FOPEN_TEST_12: opendir(), readdir(), closedir() test.", FSFAT_FOPEN_TEST_12), + Case("FSFAT_FOPEN_TEST_13: mkdir() test.", FSFAT_FOPEN_TEST_13), + Case("FSFAT_FOPEN_TEST_14: stat() test.", FSFAT_FOPEN_TEST_14), + Case("FSFAT_FOPEN_TEST_15: format() test.", FSFAT_FOPEN_TEST_15), + Case("FSFAT_FOPEN_TEST_16: write/check n x 25kB data files.", FSFAT_FOPEN_TEST_16), +}; + + +/* Declare your test specification with a custom setup handler */ +Specification specification(greentea_setup, cases); + +int main() +{ + return !Harness::run(specification); +} +/// @endcond diff --git a/components/storage/blockdevice/COMPONENT_SDIO/TESTS/filesystem/parallel/main.cpp b/components/storage/blockdevice/COMPONENT_SDIO/TESTS/filesystem/parallel/main.cpp new file mode 100644 index 00000000000..2ae26ee1a44 --- /dev/null +++ b/components/storage/blockdevice/COMPONENT_SDIO/TESTS/filesystem/parallel/main.cpp @@ -0,0 +1,209 @@ +/* mbed Microcontroller Library + * Copyright (c) 2016 ARM Limited + * + * 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. + */ + +#include "mbed.h" +#include "greentea-client/test_env.h" +#include "unity.h" +#include "utest.h" +#include +#include + +using namespace utest::v1; + +// test configuration +#ifndef MBED_TEST_FILESYSTEM +#define MBED_TEST_FILESYSTEM FATFileSystem +#endif + +#ifndef MBED_TEST_FILESYSTEM_DECL +#define MBED_TEST_FILESYSTEM_DECL MBED_TEST_FILESYSTEM fs("fs") +#endif + +#ifndef MBED_TEST_BLOCKDEVICE +#define MBED_TEST_BLOCKDEVICE SDIOBlockDevice +#define MBED_TEST_BLOCKDEVICE_DECL SDIOBlockDevice bd; +#endif + +#ifndef MBED_TEST_BLOCKDEVICE_DECL +#define MBED_TEST_BLOCKDEVICE_DECL MBED_TEST_BLOCKDEVICE bd +#endif + +#ifndef MBED_TEST_FILES +#define MBED_TEST_FILES 4 +#endif + +#ifndef MBED_TEST_DIRS +#define MBED_TEST_DIRS 4 +#endif + +#ifndef MBED_TEST_BUFFER +#define MBED_TEST_BUFFER 512 +#endif + +#ifndef MBED_TEST_TIMEOUT +#define MBED_TEST_TIMEOUT 120 +#endif + +#ifndef MBED_THREAD_COUNT +#define MBED_THREAD_COUNT MBED_TEST_FILES +#endif + +// declarations +#define STRINGIZE(x) STRINGIZE2(x) +#define STRINGIZE2(x) #x +#define INCLUDE(x) STRINGIZE(x.h) + +#include INCLUDE(MBED_TEST_FILESYSTEM) +#include INCLUDE(MBED_TEST_BLOCKDEVICE) + +MBED_TEST_FILESYSTEM_DECL; +MBED_TEST_BLOCKDEVICE_DECL; + +Dir dir[MBED_TEST_DIRS]; +File file[MBED_TEST_FILES]; +DIR *dd[MBED_TEST_DIRS]; +FILE *fd[MBED_TEST_FILES]; +struct dirent ent; +struct dirent *ed; + +volatile bool count_done = 0; + +// tests + +void test_file_tests() +{ + int res = bd.init(); + TEST_ASSERT_EQUAL(0, res); + + { + res = MBED_TEST_FILESYSTEM::format(&bd); + TEST_ASSERT_EQUAL(0, res); + } + + res = bd.deinit(); + TEST_ASSERT_EQUAL(0, res); +} + +void write_file_data (char count) +{ + + char filename[10]; + uint8_t wbuffer[MBED_TEST_BUFFER]; + int res; + + sprintf(filename, "%s%d", "data", count); + res = file[count].open(&fs, filename, O_WRONLY | O_CREAT); + TEST_ASSERT_EQUAL(0, res); + + char letter = 'A' + count; + for (uint32_t i = 0; i < MBED_TEST_BUFFER; i++) { + wbuffer[i] = letter++; + if ('z' == letter) { + letter = 'A' + count; + } + } + + for (uint32_t i = 0; i < 5; i++) { + res = file[count].write(wbuffer, MBED_TEST_BUFFER); + TEST_ASSERT_EQUAL(MBED_TEST_BUFFER, res); + } + + res = file[count].close(); + TEST_ASSERT_EQUAL(0, res); +} + +void read_file_data (char count) +{ + char filename[10]; + uint8_t rbuffer[MBED_TEST_BUFFER]; + int res; + + sprintf(filename, "%s%d", "data", count); + res = file[count].open(&fs, filename, O_RDONLY); + TEST_ASSERT_EQUAL(0, res); + + for (uint32_t i = 0; i < 5; i++) { + res = file[count].read(rbuffer, MBED_TEST_BUFFER); + TEST_ASSERT_EQUAL(MBED_TEST_BUFFER, res); + char letter = 'A' + count; + for (uint32_t i = 0; i < MBED_TEST_BUFFER; i++) { + res = rbuffer[i]; + TEST_ASSERT_EQUAL(letter++, res); + if ('z' == letter) { + letter = 'A' + count; + } + } + } + + res = file[count].close(); + TEST_ASSERT_EQUAL(0, res); +} + +void test_thread_access_test() +{ + char *dummy = new (std::nothrow) char[OS_STACK_SIZE * MBED_THREAD_COUNT]; + delete[] dummy; + TEST_SKIP_UNLESS_MESSAGE(dummy, "Not enough memory to run test"); + + Thread *data[MBED_THREAD_COUNT]; + int res = bd.init(); + TEST_ASSERT_EQUAL(0, res); + res = fs.mount(&bd); + TEST_ASSERT_EQUAL(0, res); + + // Write threads in parallel + for (char thread_count = 0; thread_count < MBED_THREAD_COUNT; thread_count++) { + data[thread_count] = new Thread(osPriorityNormal); + data[thread_count]->start(callback((void(*)(void *))write_file_data, (void *)thread_count)); + } + + // Wait for write thread to join before creating read thread + for (char thread_count = 0; thread_count < MBED_THREAD_COUNT; thread_count++) { + data[thread_count]->join(); + delete data[thread_count]; + data[thread_count] = new Thread(osPriorityNormal); + data[thread_count]->start(callback((void(*)(void *))read_file_data, (void *)thread_count)); + } + + // Wait for read threads to join + for (char thread_count = 0; thread_count < MBED_THREAD_COUNT; thread_count++) { + data[thread_count]->join(); + delete data[thread_count]; + } + res = fs.unmount(); + TEST_ASSERT_EQUAL(0, res); + res = bd.deinit(); + TEST_ASSERT_EQUAL(0, res); +} + +// test setup +utest::v1::status_t test_setup(const size_t number_of_cases) +{ + GREENTEA_SETUP(MBED_TEST_TIMEOUT, "default_auto"); + return verbose_test_setup_handler(number_of_cases); +} + +Case cases[] = { + Case("File tests", test_file_tests), + Case("Filesystem access from multiple threads", test_thread_access_test), +}; + +Specification specification(test_setup, cases); + +int main() +{ + return !Harness::run(specification); +} diff --git a/components/storage/blockdevice/COMPONENT_SDIO/TESTS/filesystem/seek/main.cpp b/components/storage/blockdevice/COMPONENT_SDIO/TESTS/filesystem/seek/main.cpp new file mode 100644 index 00000000000..e2fd2bd647b --- /dev/null +++ b/components/storage/blockdevice/COMPONENT_SDIO/TESTS/filesystem/seek/main.cpp @@ -0,0 +1,656 @@ +/* mbed Microcontroller Library + * Copyright (c) 2016 ARM Limited + * + * 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. + */ + +#include "mbed.h" +#include "greentea-client/test_env.h" +#include "unity.h" +#include "utest.h" +#include +#include + +using namespace utest::v1; + +// test configuration +#ifndef MBED_TEST_FILESYSTEM +#define MBED_TEST_FILESYSTEM FATFileSystem +#endif + +#ifndef MBED_TEST_FILESYSTEM_DECL +#define MBED_TEST_FILESYSTEM_DECL MBED_TEST_FILESYSTEM fs("fs") +#endif + +#ifndef MBED_TEST_BLOCKDEVICE +#define MBED_TEST_BLOCKDEVICE SDIOBlockDevice +#define MBED_TEST_BLOCKDEVICE_DECL SDIOBlockDevice bd; +#endif + +#ifndef MBED_TEST_BLOCKDEVICE_DECL +#define MBED_TEST_BLOCKDEVICE_DECL MBED_TEST_BLOCKDEVICE bd +#endif + +#ifndef MBED_TEST_FILES +#define MBED_TEST_FILES 4 +#endif + +#ifndef MBED_TEST_DIRS +#define MBED_TEST_DIRS 4 +#endif + +#ifndef MBED_TEST_BUFFER +#define MBED_TEST_BUFFER 8192 +#endif + +#ifndef MBED_TEST_TIMEOUT +#define MBED_TEST_TIMEOUT 120 +#endif + + +// declarations +#define STRINGIZE(x) STRINGIZE2(x) +#define STRINGIZE2(x) #x +#define INCLUDE(x) STRINGIZE(x.h) + +#include INCLUDE(MBED_TEST_FILESYSTEM) +#include INCLUDE(MBED_TEST_BLOCKDEVICE) + +MBED_TEST_FILESYSTEM_DECL; +MBED_TEST_BLOCKDEVICE_DECL; + +Dir dir[MBED_TEST_DIRS]; +File file[MBED_TEST_FILES]; +DIR *dd[MBED_TEST_DIRS]; +FILE *fd[MBED_TEST_FILES]; +struct dirent ent; +struct dirent *ed; +size_t size; +uint8_t buffer[MBED_TEST_BUFFER]; +uint8_t rbuffer[MBED_TEST_BUFFER]; +uint8_t wbuffer[MBED_TEST_BUFFER]; + + +// tests + +void test_seek_tests() +{ + int res = bd.init(); + TEST_ASSERT_EQUAL(0, res); + + { + res = MBED_TEST_FILESYSTEM::format(&bd); + TEST_ASSERT_EQUAL(0, res); + res = fs.mount(&bd); + TEST_ASSERT_EQUAL(0, res); + res = fs.mkdir("hello", 0777); + TEST_ASSERT_EQUAL(0, res); + for (int i = 0; i < 132; i++) { + sprintf((char *)buffer, "hello/kitty%d", i); + res = file[0].open(&fs, (char *)buffer, + O_WRONLY | O_CREAT | O_APPEND); + TEST_ASSERT_EQUAL(0, res); + + size = strlen("kittycatcat"); + memcpy(buffer, "kittycatcat", size); + for (int j = 0; j < 132; j++) { + file[0].write(buffer, size); + } + res = file[0].close(); + TEST_ASSERT_EQUAL(0, res); + } + res = fs.unmount(); + TEST_ASSERT_EQUAL(0, res); + } + + res = bd.deinit(); + TEST_ASSERT_EQUAL(0, res); +} + +void test_simple_dir_seek() +{ + int res = bd.init(); + TEST_ASSERT_EQUAL(0, res); + + { + res = fs.mount(&bd); + TEST_ASSERT_EQUAL(0, res); + res = dir[0].open(&fs, "hello"); + TEST_ASSERT_EQUAL(0, res); +#if (MBED_TEST_FILESYSTEM != FATFileSystem) + res = dir[0].read(&ent); + TEST_ASSERT_EQUAL(1, res); + res = strcmp(ent.d_name, "."); + TEST_ASSERT_EQUAL(0, res); + res = dir[0].read(&ent); + TEST_ASSERT_EQUAL(1, res); + res = strcmp(ent.d_name, ".."); + TEST_ASSERT_EQUAL(0, res); +#endif + + off_t pos; + int i; + for (i = 0; i < 4; i++) { + sprintf((char *)buffer, "kitty%d", i); + res = dir[0].read(&ent); + TEST_ASSERT_EQUAL(1, res); + res = strcmp(ent.d_name, (char *)buffer); + TEST_ASSERT_EQUAL(0, res); + pos = dir[0].tell(); + } + res = pos >= 0; + TEST_ASSERT_EQUAL(1, res); + + dir[0].seek(pos); + sprintf((char *)buffer, "kitty%d", i); + res = dir[0].read(&ent); + TEST_ASSERT_EQUAL(1, res); + res = strcmp(ent.d_name, (char *)buffer); + TEST_ASSERT_EQUAL(0, res); + + dir[0].rewind(); + sprintf((char *)buffer, "kitty%d", 0); +#if (MBED_TEST_FILESYSTEM != FATFileSystem) + res = dir[0].read(&ent); + TEST_ASSERT_EQUAL(1, res); + res = strcmp(ent.d_name, "."); + TEST_ASSERT_EQUAL(0, res); + res = dir[0].read(&ent); + TEST_ASSERT_EQUAL(1, res); + res = strcmp(ent.d_name, ".."); + TEST_ASSERT_EQUAL(0, res); +#endif + res = dir[0].read(&ent); + TEST_ASSERT_EQUAL(1, res); + res = strcmp(ent.d_name, (char *)buffer); + TEST_ASSERT_EQUAL(0, res); + + dir[0].seek(pos); + sprintf((char *)buffer, "kitty%d", i); + res = dir[0].read(&ent); + TEST_ASSERT_EQUAL(1, res); + res = strcmp(ent.d_name, (char *)buffer); + TEST_ASSERT_EQUAL(0, res); + res = dir[0].close(); + TEST_ASSERT_EQUAL(0, res); + res = fs.unmount(); + TEST_ASSERT_EQUAL(0, res); + } + + res = bd.deinit(); + TEST_ASSERT_EQUAL(0, res); +} + +void test_large_dir_seek() +{ + int res = bd.init(); + TEST_ASSERT_EQUAL(0, res); + + { + res = fs.mount(&bd); + TEST_ASSERT_EQUAL(0, res); + res = dir[0].open(&fs, "hello"); + TEST_ASSERT_EQUAL(0, res); +#if (MBED_TEST_FILESYSTEM != FATFileSystem) + res = dir[0].read(&ent); + TEST_ASSERT_EQUAL(1, res); + res = strcmp(ent.d_name, "."); + TEST_ASSERT_EQUAL(0, res); + res = dir[0].read(&ent); + TEST_ASSERT_EQUAL(1, res); + res = strcmp(ent.d_name, ".."); + TEST_ASSERT_EQUAL(0, res); +#endif + + off_t pos; + int i; + for (i = 0; i < 128; i++) { + sprintf((char *)buffer, "kitty%d", i); + res = dir[0].read(&ent); + TEST_ASSERT_EQUAL(1, res); + res = strcmp(ent.d_name, (char *)buffer); + TEST_ASSERT_EQUAL(0, res); + pos = dir[0].tell(); + } + res = pos >= 0; + TEST_ASSERT_EQUAL(1, res); + + dir[0].seek(pos); + sprintf((char *)buffer, "kitty%d", i); + res = dir[0].read(&ent); + TEST_ASSERT_EQUAL(1, res); + res = strcmp(ent.d_name, (char *)buffer); + TEST_ASSERT_EQUAL(0, res); + + dir[0].rewind(); + sprintf((char *)buffer, "kitty%d", 0); +#if (MBED_TEST_FILESYSTEM != FATFileSystem) + res = dir[0].read(&ent); + TEST_ASSERT_EQUAL(1, res); + res = strcmp(ent.d_name, "."); + TEST_ASSERT_EQUAL(0, res); + res = dir[0].read(&ent); + TEST_ASSERT_EQUAL(1, res); + res = strcmp(ent.d_name, ".."); + TEST_ASSERT_EQUAL(0, res); +#endif + res = dir[0].read(&ent); + TEST_ASSERT_EQUAL(1, res); + res = strcmp(ent.d_name, (char *)buffer); + TEST_ASSERT_EQUAL(0, res); + + dir[0].seek(pos); + sprintf((char *)buffer, "kitty%d", i); + res = dir[0].read(&ent); + TEST_ASSERT_EQUAL(1, res); + res = strcmp(ent.d_name, (char *)buffer); + TEST_ASSERT_EQUAL(0, res); + res = dir[0].close(); + TEST_ASSERT_EQUAL(0, res); + res = fs.unmount(); + TEST_ASSERT_EQUAL(0, res); + } + + res = bd.deinit(); + TEST_ASSERT_EQUAL(0, res); +} + +void test_simple_file_seek() +{ + int res = bd.init(); + TEST_ASSERT_EQUAL(0, res); + + { + res = fs.mount(&bd); + TEST_ASSERT_EQUAL(0, res); + res = file[0].open(&fs, "hello/kitty42", O_RDONLY); + TEST_ASSERT_EQUAL(0, res); + + off_t pos; + size = strlen("kittycatcat"); + for (int i = 0; i < 4; i++) { + res = file[0].read(buffer, size); + TEST_ASSERT_EQUAL(size, res); + res = memcmp(buffer, "kittycatcat", size); + TEST_ASSERT_EQUAL(0, res); + pos = file[0].tell(); + } + res = pos >= 0; + TEST_ASSERT_EQUAL(1, res); + res = file[0].seek(pos, SEEK_SET); + TEST_ASSERT_EQUAL(pos, res); + res = file[0].read(buffer, size); + TEST_ASSERT_EQUAL(size, res); + res = memcmp(buffer, "kittycatcat", size); + TEST_ASSERT_EQUAL(0, res); + + file[0].rewind(); + res = file[0].read(buffer, size); + TEST_ASSERT_EQUAL(size, res); + res = memcmp(buffer, "kittycatcat", size); + TEST_ASSERT_EQUAL(0, res); + res = file[0].seek(pos, SEEK_SET); + TEST_ASSERT_EQUAL(pos, res); + res = file[0].read(buffer, size); + TEST_ASSERT_EQUAL(size, res); + res = memcmp(buffer, "kittycatcat", size); + TEST_ASSERT_EQUAL(0, res); + res = file[0].seek(-size, SEEK_CUR); + TEST_ASSERT_EQUAL(pos, res); + res = file[0].read(buffer, size); + TEST_ASSERT_EQUAL(size, res); + res = memcmp(buffer, "kittycatcat", size); + TEST_ASSERT_EQUAL(0, res); + res = file[0].seek(-size, SEEK_END) >= 0; + TEST_ASSERT_EQUAL(1, res); + res = file[0].read(buffer, size); + TEST_ASSERT_EQUAL(size, res); + res = memcmp(buffer, "kittycatcat", size); + TEST_ASSERT_EQUAL(0, res); + + size_t size = file[0].size(); + res = file[0].seek(0, SEEK_CUR); + TEST_ASSERT_EQUAL(size, res); + res = file[0].close(); + TEST_ASSERT_EQUAL(0, res); + res = fs.unmount(); + TEST_ASSERT_EQUAL(0, res); + } + + res = bd.deinit(); + TEST_ASSERT_EQUAL(0, res); +} + +void test_large_file_seek() +{ + int res = bd.init(); + TEST_ASSERT_EQUAL(0, res); + + { + res = fs.mount(&bd); + TEST_ASSERT_EQUAL(0, res); + res = file[0].open(&fs, "hello/kitty42", O_RDONLY); + TEST_ASSERT_EQUAL(0, res); + + off_t pos; + size = strlen("kittycatcat"); + for (int i = 0; i < 128; i++) { + res = file[0].read(buffer, size); + TEST_ASSERT_EQUAL(size, res); + res = memcmp(buffer, "kittycatcat", size); + TEST_ASSERT_EQUAL(0, res); + pos = file[0].tell(); + } + res = pos >= 0; + TEST_ASSERT_EQUAL(1, res); + res = file[0].seek(pos, SEEK_SET); + TEST_ASSERT_EQUAL(pos, res); + res = file[0].read(buffer, size); + TEST_ASSERT_EQUAL(size, res); + res = memcmp(buffer, "kittycatcat", size); + TEST_ASSERT_EQUAL(0, res); + + file[0].rewind(); + res = file[0].read(buffer, size); + TEST_ASSERT_EQUAL(size, res); + res = memcmp(buffer, "kittycatcat", size); + TEST_ASSERT_EQUAL(0, res); + res = file[0].seek(pos, SEEK_SET); + TEST_ASSERT_EQUAL(pos, res); + res = file[0].read(buffer, size); + TEST_ASSERT_EQUAL(size, res); + res = memcmp(buffer, "kittycatcat", size); + TEST_ASSERT_EQUAL(0, res); + res = file[0].seek(-size, SEEK_CUR); + TEST_ASSERT_EQUAL(pos, res); + res = file[0].read(buffer, size); + TEST_ASSERT_EQUAL(size, res); + res = memcmp(buffer, "kittycatcat", size); + TEST_ASSERT_EQUAL(0, res); + res = file[0].seek(-size, SEEK_END) >= 0; + TEST_ASSERT_EQUAL(1, res); + res = file[0].read(buffer, size); + TEST_ASSERT_EQUAL(size, res); + res = memcmp(buffer, "kittycatcat", size); + TEST_ASSERT_EQUAL(0, res); + + size_t size = file[0].size(); + res = file[0].seek(0, SEEK_CUR); + TEST_ASSERT_EQUAL(size, res); + res = file[0].close(); + TEST_ASSERT_EQUAL(0, res); + res = fs.unmount(); + TEST_ASSERT_EQUAL(0, res); + } + + res = bd.deinit(); + TEST_ASSERT_EQUAL(0, res); +} + +void test_simple_file_seek_and_write() +{ + int res = bd.init(); + TEST_ASSERT_EQUAL(0, res); + + { + res = fs.mount(&bd); + TEST_ASSERT_EQUAL(0, res); + res = file[0].open(&fs, "hello/kitty42", O_RDWR); + TEST_ASSERT_EQUAL(0, res); + + off_t pos; + size = strlen("kittycatcat"); + for (int i = 0; i < 4; i++) { + res = file[0].read(buffer, size); + TEST_ASSERT_EQUAL(size, res); + res = memcmp(buffer, "kittycatcat", size); + TEST_ASSERT_EQUAL(0, res); + pos = file[0].tell(); + } + res = pos >= 0; + TEST_ASSERT_EQUAL(1, res); + + memcpy(buffer, "doggodogdog", size); + res = file[0].seek(pos, SEEK_SET); + TEST_ASSERT_EQUAL(pos, res); + res = file[0].write(buffer, size); + TEST_ASSERT_EQUAL(size, res); + res = file[0].seek(pos, SEEK_SET); + TEST_ASSERT_EQUAL(pos, res); + res = file[0].read(buffer, size); + TEST_ASSERT_EQUAL(size, res); + res = memcmp(buffer, "doggodogdog", size); + TEST_ASSERT_EQUAL(0, res); + + file[0].rewind(); + res = file[0].read(buffer, size); + TEST_ASSERT_EQUAL(size, res); + res = memcmp(buffer, "kittycatcat", size); + TEST_ASSERT_EQUAL(0, res); + res = file[0].seek(pos, SEEK_SET); + TEST_ASSERT_EQUAL(pos, res); + res = file[0].read(buffer, size); + TEST_ASSERT_EQUAL(size, res); + res = memcmp(buffer, "doggodogdog", size); + TEST_ASSERT_EQUAL(0, res); + res = file[0].seek(-size, SEEK_END) >= 0; + TEST_ASSERT_EQUAL(1, res); + res = file[0].read(buffer, size); + TEST_ASSERT_EQUAL(size, res); + res = memcmp(buffer, "kittycatcat", size); + TEST_ASSERT_EQUAL(0, res); + + size_t size = file[0].size(); + res = file[0].seek(0, SEEK_CUR); + TEST_ASSERT_EQUAL(size, res); + res = file[0].close(); + TEST_ASSERT_EQUAL(0, res); + res = fs.unmount(); + TEST_ASSERT_EQUAL(0, res); + } + + res = bd.deinit(); + TEST_ASSERT_EQUAL(0, res); +} + +void test_large_file_seek_and_write() +{ + int res = bd.init(); + TEST_ASSERT_EQUAL(0, res); + + { + res = fs.mount(&bd); + TEST_ASSERT_EQUAL(0, res); + res = file[0].open(&fs, "hello/kitty42", O_RDWR); + TEST_ASSERT_EQUAL(0, res); + + off_t pos; + size = strlen("kittycatcat"); + for (int i = 0; i < 128; i++) { + res = file[0].read(buffer, size); + TEST_ASSERT_EQUAL(size, res); + if (i != 4) { + res = memcmp(buffer, "kittycatcat", size); + TEST_ASSERT_EQUAL(0, res); + } + pos = file[0].tell(); + } + res = pos >= 0; + TEST_ASSERT_EQUAL(1, res); + + memcpy(buffer, "doggodogdog", size); + res = file[0].seek(pos, SEEK_SET); + TEST_ASSERT_EQUAL(pos, res); + res = file[0].write(buffer, size); + TEST_ASSERT_EQUAL(size, res); + res = file[0].seek(pos, SEEK_SET); + TEST_ASSERT_EQUAL(pos, res); + res = file[0].read(buffer, size); + TEST_ASSERT_EQUAL(size, res); + res = memcmp(buffer, "doggodogdog", size); + TEST_ASSERT_EQUAL(0, res); + + file[0].rewind(); + res = file[0].read(buffer, size); + TEST_ASSERT_EQUAL(size, res); + res = memcmp(buffer, "kittycatcat", size); + TEST_ASSERT_EQUAL(0, res); + res = file[0].seek(pos, SEEK_SET); + TEST_ASSERT_EQUAL(pos, res); + res = file[0].read(buffer, size); + TEST_ASSERT_EQUAL(size, res); + res = memcmp(buffer, "doggodogdog", size); + TEST_ASSERT_EQUAL(0, res); + res = file[0].seek(-size, SEEK_END) >= 0; + TEST_ASSERT_EQUAL(1, res); + res = file[0].read(buffer, size); + TEST_ASSERT_EQUAL(size, res); + res = memcmp(buffer, "kittycatcat", size); + TEST_ASSERT_EQUAL(0, res); + + size_t size = file[0].size(); + res = file[0].seek(0, SEEK_CUR); + TEST_ASSERT_EQUAL(size, res); + res = file[0].close(); + TEST_ASSERT_EQUAL(0, res); + res = fs.unmount(); + TEST_ASSERT_EQUAL(0, res); + } + + res = bd.deinit(); + TEST_ASSERT_EQUAL(0, res); +} + +void test_boundary_seek_and_write() +{ + int res = bd.init(); + TEST_ASSERT_EQUAL(0, res); + + { + res = fs.mount(&bd); + TEST_ASSERT_EQUAL(0, res); + res = file[0].open(&fs, "hello/kitty42", O_RDWR); + TEST_ASSERT_EQUAL(0, res); + + size = strlen("hedgehoghog"); + const off_t offsets[] = {512, 1020, 513, 1021, 511, 1019}; + + for (int i = 0; i < sizeof(offsets) / sizeof(offsets[0]); i++) { + off_t off = offsets[i]; + memcpy(buffer, "hedgehoghog", size); + res = file[0].seek(off, SEEK_SET); + TEST_ASSERT_EQUAL(off, res); + res = file[0].write(buffer, size); + TEST_ASSERT_EQUAL(size, res); + res = file[0].seek(off, SEEK_SET); + TEST_ASSERT_EQUAL(off, res); + res = file[0].read(buffer, size); + TEST_ASSERT_EQUAL(size, res); + res = memcmp(buffer, "hedgehoghog", size); + TEST_ASSERT_EQUAL(0, res); + res = file[0].seek(0, SEEK_SET); + TEST_ASSERT_EQUAL(0, res); + res = file[0].read(buffer, size); + TEST_ASSERT_EQUAL(size, res); + res = memcmp(buffer, "kittycatcat", size); + TEST_ASSERT_EQUAL(0, res); + res = file[0].sync(); + TEST_ASSERT_EQUAL(0, res); + } + res = file[0].close(); + TEST_ASSERT_EQUAL(0, res); + res = fs.unmount(); + TEST_ASSERT_EQUAL(0, res); + } + + res = bd.deinit(); + TEST_ASSERT_EQUAL(0, res); +} + +void test_out_of_bounds_seek() +{ + int res = bd.init(); + TEST_ASSERT_EQUAL(0, res); + + { + res = fs.mount(&bd); + TEST_ASSERT_EQUAL(0, res); + res = file[0].open(&fs, "hello/kitty42", O_RDWR); + TEST_ASSERT_EQUAL(0, res); + + size = strlen("kittycatcat"); + res = file[0].size(); + TEST_ASSERT_EQUAL(132 * size, res); + res = file[0].seek((132 + 4) * size, + SEEK_SET); + TEST_ASSERT_EQUAL((132 + 4)*size, res); + res = file[0].read(buffer, size); + TEST_ASSERT_EQUAL(0, res); + + memcpy(buffer, "porcupineee", size); + res = file[0].write(buffer, size); + TEST_ASSERT_EQUAL(size, res); + res = file[0].seek((132 + 4) * size, + SEEK_SET); + TEST_ASSERT_EQUAL((132 + 4)*size, res); + res = file[0].read(buffer, size); + TEST_ASSERT_EQUAL(size, res); + res = memcmp(buffer, "porcupineee", size); + TEST_ASSERT_EQUAL(0, res); + res = file[0].seek(132 * size, + SEEK_SET); + TEST_ASSERT_EQUAL(132 * size, res); + res = file[0].read(buffer, size); + TEST_ASSERT_EQUAL(size, res); +#if (MBED_TEST_FILESYSTEM != FATFileSystem) + // FatFs does not guarantee empty expanded buffer + res = memcmp(buffer, "\0\0\0\0\0\0\0\0\0\0\0", size); + TEST_ASSERT_EQUAL(0, res); +#endif + res = file[0].close(); + TEST_ASSERT_EQUAL(0, res); + res = fs.unmount(); + TEST_ASSERT_EQUAL(0, res); + } + + res = bd.deinit(); + TEST_ASSERT_EQUAL(0, res); +} + + + +// test setup +utest::v1::status_t test_setup(const size_t number_of_cases) +{ + GREENTEA_SETUP(MBED_TEST_TIMEOUT, "default_auto"); + return verbose_test_setup_handler(number_of_cases); +} + +Case cases[] = { + Case("Seek tests", test_seek_tests), + Case("Simple dir seek", test_simple_dir_seek), + Case("Large dir seek", test_large_dir_seek), + Case("Simple file seek", test_simple_file_seek), + Case("Large file seek", test_large_file_seek), + Case("Simple file seek and write", test_simple_file_seek_and_write), + Case("Large file seek and write", test_large_file_seek_and_write), + Case("Boundary seek and write", test_boundary_seek_and_write), + Case("Out-of-bounds seek", test_out_of_bounds_seek), +}; + +Specification specification(test_setup, cases); + +int main() +{ + return !Harness::run(specification); +} From ea63ddae9b083f59a7b25a060fb8ceb78bc0f341 Mon Sep 17 00:00:00 2001 From: JojoS62 Date: Thu, 1 Nov 2018 16:57:05 +0100 Subject: [PATCH 06/13] add reference countig for init/deinit removed also debug outputs. --- .../COMPONENT_SDIO/SDIOBlockDevice.cpp | 67 ++++++++++++++----- 1 file changed, 49 insertions(+), 18 deletions(-) diff --git a/components/storage/blockdevice/COMPONENT_SDIO/SDIOBlockDevice.cpp b/components/storage/blockdevice/COMPONENT_SDIO/SDIOBlockDevice.cpp index 7dfb0b0e686..7dbb3e69b2a 100644 --- a/components/storage/blockdevice/COMPONENT_SDIO/SDIOBlockDevice.cpp +++ b/components/storage/blockdevice/COMPONENT_SDIO/SDIOBlockDevice.cpp @@ -88,38 +88,72 @@ SDIOBlockDevice::~SDIOBlockDevice() { int SDIOBlockDevice::init() { debug_if(SD_DBG, "init Card...\r\n"); + int retVal = BD_ERROR_OK; + + lock(); + + if (!_is_initialized) { + _init_ref_count = 0; + } + + _init_ref_count++; + + if (_init_ref_count != 1) { + goto end; + } + if (isPresent() == false) { return SD_BLOCK_DEVICE_ERROR_NO_DEVICE; } - if (!_is_initialized) { - _sd_state = SD_Init(); - if (BD_ERROR_OK != _sd_state) - return BD_ERROR_DEVICE_ERROR; - - SD_GetCardInfo(&_cardInfo); - _is_initialized = true; - debug_if(SD_DBG, "SD initialized: type: %d version: %d class: %d\n", - _cardInfo.CardType, _cardInfo.CardVersion, _cardInfo.Class); - debug_if(SD_DBG, "SD size: %d MB\n", - _cardInfo.LogBlockNbr / 2 / 1024); + _sd_state = SD_Init(); + if (BD_ERROR_OK != _sd_state) { + retVal = BD_ERROR_DEVICE_ERROR; + goto end; } + SD_GetCardInfo(&_cardInfo); + _is_initialized = true; + debug_if(SD_DBG, "SD initialized: type: %d version: %d class: %d\n", + _cardInfo.CardType, _cardInfo.CardVersion, _cardInfo.Class); + debug_if(SD_DBG, "SD size: %d MB\n", + _cardInfo.LogBlockNbr / 2 / 1024); + // get sectors count from cardinfo _sectors = _cardInfo.LogBlockNbr; if (BLOCK_SIZE_HC != _cardInfo.BlockSize) { - return SD_BLOCK_DEVICE_ERROR_UNSUPPORTED_BLOCKSIZE; + retVal = SD_BLOCK_DEVICE_ERROR_UNSUPPORTED_BLOCKSIZE; + goto end; } - return BD_ERROR_OK; +end: + unlock(); + return retVal; } int SDIOBlockDevice::deinit() { debug_if(SD_DBG, "deinit Card...\r\n"); + lock(); + + if (!_is_initialized) { + _init_ref_count = 0; + goto end; + } + + _init_ref_count--; + + if (_init_ref_count) { + goto end; + } + _sd_state = SD_DeInit(); _is_initialized = false; + _sectors = 0; + +end: + unlock(); return BD_ERROR_OK; } @@ -158,8 +192,6 @@ int SDIOBlockDevice::read(void* b, bd_addr_t addr, bd_size_t size) { if (_sd_state != 0) { debug_if(SD_DBG, "ReadBlocks failed! addr: %lld blockCnt: %lld \n", addr, blockCnt); debug_if(SD_DBG, " hsd.errorcode: %lu 0x%lx\n", hsd.ErrorCode, hsd.ErrorCode); - printf("ReadBlocks failed! addr: %lld blockCnt: %lld \n", addr, blockCnt); - printf(" hsd.errorcode: %lu 0x%lx\n", hsd.ErrorCode, hsd.ErrorCode); status = SD_BLOCK_DEVICE_ERROR_READBLOCKS; } else { @@ -215,8 +247,6 @@ int SDIOBlockDevice::program(const void* b, bd_addr_t addr, bd_size_t size) { if (_sd_state != 0) { debug_if(SD_DBG, "WriteBlocks failed! addr: %lld blockCnt: %lld \n", addr, blockCnt); debug_if(SD_DBG, " hsd.errorcode: %lu 0x%lx\n", hsd.ErrorCode, hsd.ErrorCode); - printf("ReadBlocks failed! addr: %lld blockCnt: %lld \n", addr, blockCnt); - printf(" hsd.errorcode: %lu 0x%lx\n", hsd.ErrorCode, hsd.ErrorCode); status = SD_BLOCK_DEVICE_ERROR_WRITEBLOCKS; } else { @@ -229,7 +259,7 @@ int SDIOBlockDevice::program(const void* b, bd_addr_t addr, bd_size_t size) { #if (TRANSFER_MODE == TRANSFER_MODE_DMA) while (SD_DMA_WritePending() != SD_TRANSFER_OK) { // wait until DMA transfer done - wait_ms(20); + wait_ms(10); } #endif @@ -265,6 +295,7 @@ int SDIOBlockDevice::trim(bd_addr_t addr, bd_size_t size) { else { while (SD_GetCardState() != SD_TRANSFER_OK) { // wait until SD ready + wait_ms(10); } } From a989251797cb293d8f65b981ed080d5e6ca48e22 Mon Sep 17 00:00:00 2001 From: JojoS62 Date: Thu, 1 Nov 2018 16:57:25 +0100 Subject: [PATCH 07/13] add test for init/deinit sequence --- .../TESTS/blockdevice/basic/main.cpp | 119 ++++++++++++++++++ 1 file changed, 119 insertions(+) create mode 100644 components/storage/blockdevice/COMPONENT_SDIO/TESTS/blockdevice/basic/main.cpp diff --git a/components/storage/blockdevice/COMPONENT_SDIO/TESTS/blockdevice/basic/main.cpp b/components/storage/blockdevice/COMPONENT_SDIO/TESTS/blockdevice/basic/main.cpp new file mode 100644 index 00000000000..709c07bbc48 --- /dev/null +++ b/components/storage/blockdevice/COMPONENT_SDIO/TESTS/blockdevice/basic/main.cpp @@ -0,0 +1,119 @@ +/* mbed Microcontroller Library + * Copyright (c) 2016 ARM Limited + * + * 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. + */ + +#include "mbed.h" +#include "greentea-client/test_env.h" +#include "unity.h" +#include "utest.h" +#include +#include + +using namespace utest::v1; + +// test configuration +#ifndef MBED_TEST_BLOCKDEVICE +#define MBED_TEST_BLOCKDEVICE SDIOBlockDevice +#define MBED_TEST_BLOCKDEVICE_DECL SDIOBlockDevice bd; +#endif + +#ifndef MBED_TEST_BLOCKDEVICE_DECL +#define MBED_TEST_BLOCKDEVICE_DECL MBED_TEST_BLOCKDEVICE bd +#endif + +#ifndef MBED_TEST_BUFFER +#define MBED_TEST_BUFFER 8192 +#endif + +#ifndef MBED_TEST_TIMEOUT +#define MBED_TEST_TIMEOUT 120 +#endif + + +// declarations +#define STRINGIZE(x) STRINGIZE2(x) +#define STRINGIZE2(x) #x +#define INCLUDE(x) STRINGIZE(x.h) + +#include INCLUDE(MBED_TEST_BLOCKDEVICE) + +MBED_TEST_BLOCKDEVICE_DECL; + +size_t size; +uint8_t buffer[MBED_TEST_BUFFER]; +uint8_t rbuffer[MBED_TEST_BUFFER]; +uint8_t wbuffer[MBED_TEST_BUFFER]; + + +// tests + +// test multiple init-deinit sequences +void test_init_deinit() +{ + for (int repeatCount=0; repeatCount < 10; repeatCount++) + { + int res = bd.init(); + TEST_ASSERT_EQUAL(0, res); + + res = bd.deinit(); + TEST_ASSERT_EQUAL(0, res); + } +} + +void test_init_deinit_stacked() +{ + for (int repeatCount=0; repeatCount < 10; repeatCount++) + { + // multiple init + int res = bd.init(); + TEST_ASSERT_EQUAL(0, res); + + res = bd.init(); + TEST_ASSERT_EQUAL(0, res); + + res = bd.init(); + TEST_ASSERT_EQUAL(0, res); + + // same number of deinit + res = bd.deinit(); + TEST_ASSERT_EQUAL(0, res); + + res = bd.deinit(); + TEST_ASSERT_EQUAL(0, res); + + res = bd.deinit(); + TEST_ASSERT_EQUAL(0, res); + } +} + + +// test setup +utest::v1::status_t test_setup(const size_t number_of_cases) +{ + GREENTEA_SETUP(MBED_TEST_TIMEOUT, "default_auto"); + return verbose_test_setup_handler(number_of_cases); +} + +Case cases[] = { + Case("Init/Deinit test", test_init_deinit), + Case("Init/Deinit stacked test", test_init_deinit_stacked) +}; + +Specification specification(test_setup, cases); + +int main() +{ + return !Harness::run(specification); +} From 645ceb0ec841be06232b49d746164958f462df12 Mon Sep 17 00:00:00 2001 From: JojoS62 Date: Sat, 3 Nov 2018 10:39:40 +0100 Subject: [PATCH 08/13] modified SD_Init, use own structure for GetCardInfo Init uses a local SD_WideBus_Enable and not the HAL version. The HAL version has the problem with FindSCR(), this fails due to slow HAL_GetTick / ticker_read_us implementation (using many locks and checks for thread safety). Cardinfo struckture was defined in sdio_device to be independant from HAL functions in SDioblockdevice.cpp user API. --- .../TARGET_STM/TARGET_STM32F4/sdio_device.c | 56 +++++++++++++++++-- .../TARGET_STM/TARGET_STM32F4/sdio_device.h | 25 +++++++-- 2 files changed, 71 insertions(+), 10 deletions(-) diff --git a/targets/TARGET_STM/TARGET_STM32F4/sdio_device.c b/targets/TARGET_STM/TARGET_STM32F4/sdio_device.c index 78c19985876..1e076d5d3e1 100644 --- a/targets/TARGET_STM/TARGET_STM32F4/sdio_device.c +++ b/targets/TARGET_STM/TARGET_STM32F4/sdio_device.c @@ -259,6 +259,40 @@ __weak void SD_MspDeInit(SD_HandleTypeDef *hsd, void *Params) { __HAL_RCC_SDIO_CLK_DISABLE(); } +/** + * @brief Enables the SDIO wide bus mode. + * @param hsd pointer to SD handle + * @retval error state + */ +static uint32_t SD_WideBus_Enable(SD_HandleTypeDef *hsd) +{ + uint32_t errorstate = HAL_SD_ERROR_NONE; + + if((SDIO_GetResponse(hsd->Instance, SDIO_RESP1) & SDMMC_CARD_LOCKED) == SDMMC_CARD_LOCKED) + { + return HAL_SD_ERROR_LOCK_UNLOCK_FAILED; + } + + /* Send CMD55 APP_CMD with argument as card's RCA.*/ + errorstate = SDMMC_CmdAppCommand(hsd->Instance, (uint32_t)(hsd->SdCard.RelCardAdd << 16U)); + if(errorstate != HAL_OK) + { + return errorstate; + } + + /* Send ACMD6 APP_CMD with argument as 2 for wide bus mode */ + errorstate = SDMMC_CmdBusWidth(hsd->Instance, 2U); + if(errorstate != HAL_OK) + { + return errorstate; + } + + hsd->Init.BusWide = SDIO_BUS_WIDE_4B; + SDIO_Init(hsd->Instance, hsd->Init); + + return HAL_SD_ERROR_NONE; +} + /** * @brief Initializes the SD card device. * @retval SD status @@ -273,14 +307,13 @@ uint8_t SD_Init(void) { hsd.Init.BusWide = SDIO_BUS_WIDE_1B; hsd.Init.HardwareFlowControl = SDIO_HARDWARE_FLOW_CONTROL_DISABLE; hsd.Init.ClockDiv = 0; - // !!! clock must be slower in polling mode if compiled w/o optimization !!! /* HAL SD initialization */ sd_state = HAL_SD_Init(&hsd); /* Configure SD Bus width (4 bits mode selected) */ if (sd_state == MSD_OK) { /* Enable wide operation */ - if (HAL_SD_ConfigWideBusOperation(&hsd, SDIO_BUS_WIDE_4B) != HAL_OK) { + if (SD_WideBus_Enable(&hsd) != HAL_OK) { sd_state = MSD_ERROR; } } @@ -418,9 +451,22 @@ uint8_t SD_GetCardState(void) { * @param CardInfo: Pointer to HAL_SD_CardInfoTypedef structure * @retval None */ -void SD_GetCardInfo(HAL_SD_CardInfoTypeDef *CardInfo) { - /* Get SD card Information */ - HAL_SD_GetCardInfo(&hsd, CardInfo); +void SD_GetCardInfo(SD_Cardinfo_t *CardInfo) { + /* Get SD card Information, copy structure for portability */ + HAL_SD_CardInfoTypeDef HAL_CardInfo; + + HAL_SD_GetCardInfo(&hsd, &HAL_CardInfo); + + if (CardInfo) { + CardInfo->CardType = HAL_CardInfo.CardType; + CardInfo->CardVersion = HAL_CardInfo.CardVersion; + CardInfo->Class = HAL_CardInfo.Class; + CardInfo->RelCardAdd = HAL_CardInfo.RelCardAdd; + CardInfo->BlockNbr = HAL_CardInfo.BlockNbr; + CardInfo->BlockSize = HAL_CardInfo.BlockSize; + CardInfo->LogBlockNbr = HAL_CardInfo.LogBlockNbr; + CardInfo->LogBlockSize = HAL_CardInfo.LogBlockSize; + } } /** diff --git a/targets/TARGET_STM/TARGET_STM32F4/sdio_device.h b/targets/TARGET_STM/TARGET_STM32F4/sdio_device.h index 93b34baa57e..c86227172a6 100644 --- a/targets/TARGET_STM/TARGET_STM32F4/sdio_device.h +++ b/targets/TARGET_STM/TARGET_STM32F4/sdio_device.h @@ -59,18 +59,33 @@ extern "C" { #endif -/* Includes ------------------------------------------------------------------*/ #include "stm32f4xx_hal.h" + /* Typedefs */ + +typedef struct{ + uint32_t CardType; /* Specifies the card Type */ + uint32_t CardVersion; /* Specifies the card version */ + uint32_t Class; /* Specifies the class of the card class */ + uint32_t RelCardAdd; /* Specifies the Relative Card Address */ + uint32_t BlockNbr; /* Specifies the Card Capacity in blocks */ + uint32_t BlockSize; /* Specifies one block size in bytes */ + uint32_t LogBlockNbr; /* Specifies the Card logical Capacity in blocks */ + uint32_t LogBlockSize; /* Specifies logical block size in bytes */ +} SD_Cardinfo_t; + + +/* External Global var */ + extern SD_HandleTypeDef hsd; -/* Exported types --------------------------------------------------------*/ +/* Exported types */ /** * @brief SD Card information structure */ #define BSP_SD_CardInfo HAL_SD_CardInfoTypeDef -/* Exported constants --------------------------------------------------------*/ +/* Exported constants */ /** * @brief SD status structure definition */ @@ -83,7 +98,7 @@ extern SD_HandleTypeDef hsd; #define SD_TRANSFER_OK ((uint8_t)0x00) #define SD_TRANSFER_BUSY ((uint8_t)0x01) -/* Exported functions --------------------------------------------------------*/ +/* Exported functions */ uint8_t SD_Init(void); uint8_t SD_DeInit(void); uint8_t SD_ReadBlocks(uint32_t *pData, uint32_t ReadAddr, uint32_t NumOfBlocks, uint32_t Timeout); @@ -95,7 +110,7 @@ uint8_t SD_DMA_WritePending(void); uint8_t SD_Erase(uint32_t StartAddr, uint32_t EndAddr); uint8_t SD_GetCardState(void); -void SD_GetCardInfo(HAL_SD_CardInfoTypeDef *CardInfo); +void SD_GetCardInfo(SD_Cardinfo_t *CardInfo); /* callback function for DMA Rx/Tx completete, called by HAL SDIO interrupt handler */ void HAL_SD_TxCpltCallback(SD_HandleTypeDef *hsd); From 30081cfbcc56c163f76bfb79cf3d2dd0ae9a18e6 Mon Sep 17 00:00:00 2001 From: JojoS62 Date: Sat, 3 Nov 2018 10:41:50 +0100 Subject: [PATCH 09/13] remove dependency from HAL code use private SD_Cardinfo_t struct for cardinfo. --- components/storage/blockdevice/COMPONENT_SDIO/SDIOBlockDevice.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/storage/blockdevice/COMPONENT_SDIO/SDIOBlockDevice.h b/components/storage/blockdevice/COMPONENT_SDIO/SDIOBlockDevice.h index 60e43283432..7f26f042291 100644 --- a/components/storage/blockdevice/COMPONENT_SDIO/SDIOBlockDevice.h +++ b/components/storage/blockdevice/COMPONENT_SDIO/SDIOBlockDevice.h @@ -122,7 +122,7 @@ class SDIOBlockDevice: public BlockDevice { bd_size_t _sectors; uint32_t _sd_state; uint32_t _init_ref_count; - HAL_SD_CardInfoTypeDef _cardInfo; + SD_Cardinfo_t _cardInfo; uint32_t _card_type; PlatformMutex _mutex; From c85f3b94589852cd1b8aed8f366da3a2ae2b3a14 Mon Sep 17 00:00:00 2001 From: JojoS62 Date: Sun, 4 Nov 2018 20:16:06 +0100 Subject: [PATCH 10/13] changed read/write ready checking and clean up after a read opteration, just check for DMA ready. Speeds up the operation a lot. Check if SD card ready before reading/writing. Leave check if SD ready aftere writing, DMA ready seems not to be sufficient for checking ready state. Removed unused member vars. Lock iis called on function entry to make multithreaded apps safer. --- .../COMPONENT_SDIO/SDIOBlockDevice.cpp | 150 +++++++++--------- .../COMPONENT_SDIO/SDIOBlockDevice.h | 2 - 2 files changed, 75 insertions(+), 77 deletions(-) diff --git a/components/storage/blockdevice/COMPONENT_SDIO/SDIOBlockDevice.cpp b/components/storage/blockdevice/COMPONENT_SDIO/SDIOBlockDevice.cpp index 7dbb3e69b2a..6000d01d2db 100644 --- a/components/storage/blockdevice/COMPONENT_SDIO/SDIOBlockDevice.cpp +++ b/components/storage/blockdevice/COMPONENT_SDIO/SDIOBlockDevice.cpp @@ -26,14 +26,6 @@ namespace mbed { * defines */ -/* - * TRANSFER_MODE : must be either DMA or POLLING - * ATTENTION: in POLLING mode, HAL code is slow and SDIO_CLOCK must be reduced! - */ -#define TRANSFER_MODE_DMA (0) -#define TRANSFER_MODE_POLLING (1) -#define TRANSFER_MODE TRANSFER_MODE_DMA - #define SD_DBG 0 /*!< 1 - Enable debugging */ #define SD_CMD_TRACE 0 /*!< 1 - Enable SD command tracing */ @@ -70,7 +62,6 @@ SDIOBlockDevice::SDIOBlockDevice(PinName cardDetect) : _cardDetect(cardDetect), _is_initialized(0), _sectors(0), - _sd_state(0), _init_ref_count(0) { _card_type = SDCARD_NONE; @@ -88,7 +79,6 @@ SDIOBlockDevice::~SDIOBlockDevice() { int SDIOBlockDevice::init() { debug_if(SD_DBG, "init Card...\r\n"); - int retVal = BD_ERROR_OK; lock(); @@ -99,17 +89,19 @@ int SDIOBlockDevice::init() { _init_ref_count++; if (_init_ref_count != 1) { - goto end; + unlock(); + return BD_ERROR_OK; } if (isPresent() == false) { + unlock(); return SD_BLOCK_DEVICE_ERROR_NO_DEVICE; } - _sd_state = SD_Init(); - if (BD_ERROR_OK != _sd_state) { - retVal = BD_ERROR_DEVICE_ERROR; - goto end; + int status = SD_Init(); + if (BD_ERROR_OK != status) { + unlock(); + return BD_ERROR_DEVICE_ERROR; } SD_GetCardInfo(&_cardInfo); @@ -122,13 +114,12 @@ int SDIOBlockDevice::init() { // get sectors count from cardinfo _sectors = _cardInfo.LogBlockNbr; if (BLOCK_SIZE_HC != _cardInfo.BlockSize) { - retVal = SD_BLOCK_DEVICE_ERROR_UNSUPPORTED_BLOCKSIZE; - goto end; + unlock(); + return SD_BLOCK_DEVICE_ERROR_UNSUPPORTED_BLOCKSIZE; } -end: unlock(); - return retVal; + return status; } @@ -138,75 +129,79 @@ int SDIOBlockDevice::deinit() { if (!_is_initialized) { _init_ref_count = 0; - goto end; + unlock(); + return BD_ERROR_OK; } _init_ref_count--; if (_init_ref_count) { - goto end; + unlock(); + return BD_ERROR_OK; } - _sd_state = SD_DeInit(); + int status = SD_DeInit(); _is_initialized = false; _sectors = 0; -end: unlock(); - return BD_ERROR_OK; + return status; } int SDIOBlockDevice::read(void* b, bd_addr_t addr, bd_size_t size) { //debug_if(SD_DBG, "read Card...\r\n"); + lock(); if (isPresent() == false) { + unlock(); return SD_BLOCK_DEVICE_ERROR_NO_DEVICE; } if (!is_valid_read(addr, size)) { + unlock(); return SD_BLOCK_DEVICE_ERROR_PARAMETER; } - lock(); if (!_is_initialized) { unlock(); return SD_BLOCK_DEVICE_ERROR_NO_INIT; } uint32_t *buffer = static_cast(b); - int status = BD_ERROR_OK; // ReadBlocks uses byte unit address // SDHC and SDXC Cards different addressing is handled in ReadBlocks() bd_addr_t blockCnt = size / _block_size; addr = addr / _block_size; + // make sure card is ready + while (SD_GetCardState() != SD_TRANSFER_OK) { + // wait until SD ready + wait_ms(1); + } + // receive the data : one block/ multiple blocks is handled in ReadBlocks() -#if (TRANSFER_MODE == TRANSFER_MODE_POLLING) - _sd_state = SD_ReadBlocks(buffer, addr, blockCnt, MBED_CONF_SD_TIMEOUT); -#elif (TRANSFER_MODE == TRANSFER_MODE_DMA) - _sd_state = SD_ReadBlocks_DMA(buffer, addr, blockCnt); -#else -# error "TRANSFER_MODE must be either TRANSFER_MODE_POLLING or TRANSFER_MODE_DMA" -#endif + int status = SD_ReadBlocks_DMA(buffer, addr, blockCnt); debug_if(SD_DBG, "ReadBlocks dbgtest addr: %lld blockCnt: %lld \n", addr, blockCnt); - if (_sd_state != 0) { + + if (status == MSD_OK) { + // wait until DMA finished + while (SD_DMA_ReadPending() != SD_TRANSFER_OK) { + uint32_t tickstart = HAL_GetTick(); + if((HAL_GetTick() - tickstart) >= MBED_CONF_SD_TIMEOUT) { + unlock(); + return SD_BLOCK_DEVICE_ERROR_READBLOCKS; + } + while (SD_GetCardState() != SD_TRANSFER_OK) { + // wait until SD ready + wait_ms(10); + } + } + } + else { debug_if(SD_DBG, "ReadBlocks failed! addr: %lld blockCnt: %lld \n", addr, blockCnt); debug_if(SD_DBG, " hsd.errorcode: %lu 0x%lx\n", hsd.ErrorCode, hsd.ErrorCode); status = SD_BLOCK_DEVICE_ERROR_READBLOCKS; } - else { - while (SD_GetCardState() != SD_TRANSFER_OK) { - // wait until SD ready - wait_ms(10); - } - } - -#if (TRANSFER_MODE == TRANSFER_MODE_DMA) - while (SD_DMA_ReadPending() != SD_TRANSFER_OK) { - // wait until DMA transfer done - wait_ms(10); - } -#endif unlock(); return status; @@ -214,14 +209,17 @@ int SDIOBlockDevice::read(void* b, bd_addr_t addr, bd_size_t size) { int SDIOBlockDevice::program(const void* b, bd_addr_t addr, bd_size_t size) { //debug_if(SD_DBG, "program Card...\r\n"); + lock(); + if (isPresent() == false) { + unlock(); return SD_BLOCK_DEVICE_ERROR_NO_DEVICE; } if (!is_valid_program(addr, size)) { + unlock(); return SD_BLOCK_DEVICE_ERROR_PARAMETER; } - lock(); if (!_is_initialized) { unlock(); return SD_BLOCK_DEVICE_ERROR_NO_INIT; @@ -230,65 +228,67 @@ int SDIOBlockDevice::program(const void* b, bd_addr_t addr, bd_size_t size) { //uint32_t *buffer = static_cast< uint32_t *>(b); // HAL layer uses uint32_t for addr/size uint32_t *buffer = (uint32_t *)(b); - int status = BD_ERROR_OK; // Get block count bd_size_t blockCnt = size / _block_size; addr = addr / _block_size; -#if (TRANSFER_MODE == TRANSFER_MODE_POLLING) - _sd_state = SD_WriteBlocks(buffer, addr, blockCnt, MBED_CONF_SD_TIMEOUT); -#elif (TRANSFER_MODE == TRANSFER_MODE_DMA) - _sd_state = SD_WriteBlocks_DMA(buffer, addr, blockCnt); -#else -# error "TRANSFER_MODE must be either TRANSFER_MODE_POLLING or TRANSFER_MODE_DMA" -#endif - debug_if(SD_DBG, "WriteBlocks dbgtest addr: %lld blockCnt: %lld \n", addr, blockCnt); - if (_sd_state != 0) { - debug_if(SD_DBG, "WriteBlocks failed! addr: %lld blockCnt: %lld \n", addr, blockCnt); - debug_if(SD_DBG, " hsd.errorcode: %lu 0x%lx\n", hsd.ErrorCode, hsd.ErrorCode); - status = SD_BLOCK_DEVICE_ERROR_WRITEBLOCKS; + // make sure card is ready + while (SD_GetCardState() != SD_TRANSFER_OK) { + // wait until SD ready + wait_ms(1); } - else { + + int status = SD_WriteBlocks_DMA(buffer, addr, blockCnt); + debug_if(SD_DBG, "WriteBlocks dbgtest addr: %lld blockCnt: %lld \n", addr, blockCnt); + + if (status == MSD_OK) { + // wait until DMA finished + while (SD_DMA_WritePending() != SD_TRANSFER_OK) { + uint32_t tickstart = HAL_GetTick(); + if((HAL_GetTick() - tickstart) >= MBED_CONF_SD_TIMEOUT) { + unlock(); + status = SD_BLOCK_DEVICE_ERROR_WRITEBLOCKS; + } + } + // make sure card is ready while (SD_GetCardState() != SD_TRANSFER_OK) { // wait until SD ready - wait_ms(10); + wait_ms(1); } } - - #if (TRANSFER_MODE == TRANSFER_MODE_DMA) - while (SD_DMA_WritePending() != SD_TRANSFER_OK) { - // wait until DMA transfer done - wait_ms(10); + else { + debug_if(SD_DBG, "WriteBlocks failed! addr: %lld blockCnt: %lld \n", addr, blockCnt); + debug_if(SD_DBG, " hsd.errorcode: %lu 0x%lx\n", hsd.ErrorCode, hsd.ErrorCode); + status = SD_BLOCK_DEVICE_ERROR_WRITEBLOCKS; } -#endif unlock(); return status; } int SDIOBlockDevice::trim(bd_addr_t addr, bd_size_t size) { - //debug_if(SD_DBG, "trim Card...\r\n"); + debug_if(SD_DBG, "trim Card...\r\n"); + lock(); if (isPresent() == false) { + unlock(); return SD_BLOCK_DEVICE_ERROR_NO_DEVICE; } if (!_is_valid_trim(addr, size)) { + unlock(); return SD_BLOCK_DEVICE_ERROR_PARAMETER; } - lock(); if (!_is_initialized) { unlock(); return SD_BLOCK_DEVICE_ERROR_NO_INIT; } - int status = BD_ERROR_OK; - bd_size_t blockCnt = size / _block_size; addr = addr / _block_size; - _sd_state = SD_Erase(addr, blockCnt); - if (_sd_state != 0) { + int status = SD_Erase(addr, blockCnt); + if (status != 0) { debug_if(SD_DBG, "Erase blocks failed! addr: %lld blockCnt: %lld \n", addr, blockCnt); status = SD_BLOCK_DEVICE_ERROR_ERASEBLOCKS; } diff --git a/components/storage/blockdevice/COMPONENT_SDIO/SDIOBlockDevice.h b/components/storage/blockdevice/COMPONENT_SDIO/SDIOBlockDevice.h index 7f26f042291..1afa1d927f0 100644 --- a/components/storage/blockdevice/COMPONENT_SDIO/SDIOBlockDevice.h +++ b/components/storage/blockdevice/COMPONENT_SDIO/SDIOBlockDevice.h @@ -114,13 +114,11 @@ class SDIOBlockDevice: public BlockDevice { virtual bool isPresent(void); private: - //SD_HandleTypeDef _hsd; DigitalIn _cardDetect; bool _is_initialized; bd_size_t _block_size; bd_size_t _erase_size; bd_size_t _sectors; - uint32_t _sd_state; uint32_t _init_ref_count; SD_Cardinfo_t _cardInfo; uint32_t _card_type; From 4e5bb1c819e7c3110607e36fe7ca9e0cd26b110d Mon Sep 17 00:00:00 2001 From: JojoS62 Date: Sun, 4 Nov 2018 20:30:49 +0100 Subject: [PATCH 11/13] fix card status checking was wrong inside other loop --- .../blockdevice/COMPONENT_SDIO/SDIOBlockDevice.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/components/storage/blockdevice/COMPONENT_SDIO/SDIOBlockDevice.cpp b/components/storage/blockdevice/COMPONENT_SDIO/SDIOBlockDevice.cpp index 6000d01d2db..ec1cd0d1a44 100644 --- a/components/storage/blockdevice/COMPONENT_SDIO/SDIOBlockDevice.cpp +++ b/components/storage/blockdevice/COMPONENT_SDIO/SDIOBlockDevice.cpp @@ -191,10 +191,11 @@ int SDIOBlockDevice::read(void* b, bd_addr_t addr, bd_size_t size) { unlock(); return SD_BLOCK_DEVICE_ERROR_READBLOCKS; } - while (SD_GetCardState() != SD_TRANSFER_OK) { - // wait until SD ready - wait_ms(10); - } + } + // make sure card is ready + while (SD_GetCardState() != SD_TRANSFER_OK) { + // wait until SD ready + wait_ms(10); } } else { From 3928760915880048634560020ee9c17227b31c9c Mon Sep 17 00:00:00 2001 From: JojoS62 Date: Mon, 5 Nov 2018 12:08:47 +0100 Subject: [PATCH 12/13] applied AStyle formatting --- .../COMPONENT_SDIO/SDIOBlockDevice.cpp | 209 +++++++++++------- .../COMPONENT_SDIO/SDIOBlockDevice.h | 19 +- .../TARGET_STM/TARGET_STM32F4/sdio_device.c | 137 +++++++----- .../TARGET_STM/TARGET_STM32F4/sdio_device.h | 82 +++---- 4 files changed, 253 insertions(+), 194 deletions(-) diff --git a/components/storage/blockdevice/COMPONENT_SDIO/SDIOBlockDevice.cpp b/components/storage/blockdevice/COMPONENT_SDIO/SDIOBlockDevice.cpp index ec1cd0d1a44..86572bb8101 100644 --- a/components/storage/blockdevice/COMPONENT_SDIO/SDIOBlockDevice.cpp +++ b/components/storage/blockdevice/COMPONENT_SDIO/SDIOBlockDevice.cpp @@ -14,55 +14,54 @@ * limitations under the License. */ - #include #include "platform/mbed_debug.h" #include "platform/mbed_wait_api.h" #include "SDIOBlockDevice.h" -namespace mbed { +namespace mbed +{ /* * defines */ -#define SD_DBG 0 /*!< 1 - Enable debugging */ -#define SD_CMD_TRACE 0 /*!< 1 - Enable SD command tracing */ - -#define SD_BLOCK_DEVICE_ERROR_WOULD_BLOCK -5001 /*!< operation would block */ -#define SD_BLOCK_DEVICE_ERROR_UNSUPPORTED -5002 /*!< unsupported operation */ -#define SD_BLOCK_DEVICE_ERROR_PARAMETER -5003 /*!< invalid parameter */ -#define SD_BLOCK_DEVICE_ERROR_NO_INIT -5004 /*!< uninitialized */ -#define SD_BLOCK_DEVICE_ERROR_NO_DEVICE -5005 /*!< device is missing or not connected */ -#define SD_BLOCK_DEVICE_ERROR_WRITE_PROTECTED -5006 /*!< write protected */ -#define SD_BLOCK_DEVICE_ERROR_UNUSABLE -5007 /*!< unusable card */ -#define SD_BLOCK_DEVICE_ERROR_NO_RESPONSE -5008 /*!< No response from device */ -#define SD_BLOCK_DEVICE_ERROR_CRC -5009 /*!< CRC error */ -#define SD_BLOCK_DEVICE_ERROR_ERASE -5010 /*!< Erase error: reset/sequence */ -#define SD_BLOCK_DEVICE_ERROR_WRITE -5011 /*!< SPI Write error: !SPI_DATA_ACCEPTED */ -#define SD_BLOCK_DEVICE_ERROR_UNSUPPORTED_BLOCKSIZE -5012 /*!< unsupported blocksize, only 512 byte supported */ -#define SD_BLOCK_DEVICE_ERROR_READBLOCKS -5013 /*!< read data blocks from SD failed */ -#define SD_BLOCK_DEVICE_ERROR_WRITEBLOCKS -5014 /*!< write data blocks to SD failed */ -#define SD_BLOCK_DEVICE_ERROR_ERASEBLOCKS -5015 /*!< erase data blocks to SD failed */ - -#define BLOCK_SIZE_HC 512 /*!< Block size supported for SD card is 512 bytes */ +#define SD_DBG 0 /*!< 1 - Enable debugging */ +#define SD_CMD_TRACE 0 /*!< 1 - Enable SD command tracing */ + +#define SD_BLOCK_DEVICE_ERROR_WOULD_BLOCK -5001 /*!< operation would block */ +#define SD_BLOCK_DEVICE_ERROR_UNSUPPORTED -5002 /*!< unsupported operation */ +#define SD_BLOCK_DEVICE_ERROR_PARAMETER -5003 /*!< invalid parameter */ +#define SD_BLOCK_DEVICE_ERROR_NO_INIT -5004 /*!< uninitialized */ +#define SD_BLOCK_DEVICE_ERROR_NO_DEVICE -5005 /*!< device is missing or not connected */ +#define SD_BLOCK_DEVICE_ERROR_WRITE_PROTECTED -5006 /*!< write protected */ +#define SD_BLOCK_DEVICE_ERROR_UNUSABLE -5007 /*!< unusable card */ +#define SD_BLOCK_DEVICE_ERROR_NO_RESPONSE -5008 /*!< No response from device */ +#define SD_BLOCK_DEVICE_ERROR_CRC -5009 /*!< CRC error */ +#define SD_BLOCK_DEVICE_ERROR_ERASE -5010 /*!< Erase error: reset/sequence */ +#define SD_BLOCK_DEVICE_ERROR_WRITE -5011 /*!< SPI Write error: !SPI_DATA_ACCEPTED */ +#define SD_BLOCK_DEVICE_ERROR_UNSUPPORTED_BLOCKSIZE -5012 /*!< unsupported blocksize, only 512 byte supported */ +#define SD_BLOCK_DEVICE_ERROR_READBLOCKS -5013 /*!< read data blocks from SD failed */ +#define SD_BLOCK_DEVICE_ERROR_WRITEBLOCKS -5014 /*!< write data blocks to SD failed */ +#define SD_BLOCK_DEVICE_ERROR_ERASEBLOCKS -5015 /*!< erase data blocks to SD failed */ + +#define BLOCK_SIZE_HC 512 /*!< Block size supported for SD card is 512 bytes */ // Types -#define SDCARD_NONE 0 /**< No card is present */ -#define SDCARD_V1 1 /**< v1.x Standard Capacity */ -#define SDCARD_V2 2 /**< v2.x Standard capacity SD card */ -#define SDCARD_V2HC 3 /**< v2.x High capacity SD card */ -#define CARD_UNKNOWN 4 /**< Unknown or unsupported card */ +#define SDCARD_NONE 0 /**< No card is present */ +#define SDCARD_V1 1 /**< v1.x Standard Capacity */ +#define SDCARD_V2 2 /**< v2.x Standard capacity SD card */ +#define SDCARD_V2HC 3 /**< v2.x High capacity SD card */ +#define CARD_UNKNOWN 4 /**< Unknown or unsupported card */ #ifndef MBED_CONF_SD_TIMEOUT -# define MBED_CONF_SD_TIMEOUT (30 * 1000) /* ms */ +#define MBED_CONF_SD_TIMEOUT (30 * 1000) /* ms */ #endif -SDIOBlockDevice::SDIOBlockDevice(PinName cardDetect) : - _cardDetect(cardDetect), - _is_initialized(0), - _sectors(0), - _init_ref_count(0) +SDIOBlockDevice::SDIOBlockDevice(PinName cardDetect) : _cardDetect(cardDetect), + _is_initialized(0), + _sectors(0), + _init_ref_count(0) { _card_type = SDCARD_NONE; @@ -71,37 +70,44 @@ SDIOBlockDevice::SDIOBlockDevice(PinName cardDetect) : _erase_size = BLOCK_SIZE_HC; } -SDIOBlockDevice::~SDIOBlockDevice() { - if (_is_initialized) { +SDIOBlockDevice::~SDIOBlockDevice() +{ + if (_is_initialized) + { deinit(); } } -int SDIOBlockDevice::init() { +int SDIOBlockDevice::init() +{ debug_if(SD_DBG, "init Card...\r\n"); lock(); - if (!_is_initialized) { + if (!_is_initialized) + { _init_ref_count = 0; } _init_ref_count++; - if (_init_ref_count != 1) { + if (_init_ref_count != 1) + { unlock(); return BD_ERROR_OK; } - if (isPresent() == false) { + if (isPresent() == false) + { unlock(); return SD_BLOCK_DEVICE_ERROR_NO_DEVICE; } int status = SD_Init(); - if (BD_ERROR_OK != status) { + if (BD_ERROR_OK != status) + { unlock(); - return BD_ERROR_DEVICE_ERROR; + return BD_ERROR_DEVICE_ERROR; } SD_GetCardInfo(&_cardInfo); @@ -113,21 +119,23 @@ int SDIOBlockDevice::init() { // get sectors count from cardinfo _sectors = _cardInfo.LogBlockNbr; - if (BLOCK_SIZE_HC != _cardInfo.BlockSize) { + if (BLOCK_SIZE_HC != _cardInfo.BlockSize) + { unlock(); - return SD_BLOCK_DEVICE_ERROR_UNSUPPORTED_BLOCKSIZE; + return SD_BLOCK_DEVICE_ERROR_UNSUPPORTED_BLOCKSIZE; } unlock(); return status; } - -int SDIOBlockDevice::deinit() { +int SDIOBlockDevice::deinit() +{ debug_if(SD_DBG, "deinit Card...\r\n"); lock(); - if (!_is_initialized) { + if (!_is_initialized) + { _init_ref_count = 0; unlock(); return BD_ERROR_OK; @@ -135,7 +143,8 @@ int SDIOBlockDevice::deinit() { _init_ref_count--; - if (_init_ref_count) { + if (_init_ref_count) + { unlock(); return BD_ERROR_OK; } @@ -149,19 +158,23 @@ int SDIOBlockDevice::deinit() { return status; } -int SDIOBlockDevice::read(void* b, bd_addr_t addr, bd_size_t size) { +int SDIOBlockDevice::read(void *b, bd_addr_t addr, bd_size_t size) +{ //debug_if(SD_DBG, "read Card...\r\n"); lock(); - if (isPresent() == false) { + if (isPresent() == false) + { unlock(); return SD_BLOCK_DEVICE_ERROR_NO_DEVICE; } - if (!is_valid_read(addr, size)) { + if (!is_valid_read(addr, size)) + { unlock(); return SD_BLOCK_DEVICE_ERROR_PARAMETER; } - if (!_is_initialized) { + if (!_is_initialized) + { unlock(); return SD_BLOCK_DEVICE_ERROR_NO_INIT; } @@ -170,11 +183,12 @@ int SDIOBlockDevice::read(void* b, bd_addr_t addr, bd_size_t size) { // ReadBlocks uses byte unit address // SDHC and SDXC Cards different addressing is handled in ReadBlocks() - bd_addr_t blockCnt = size / _block_size; + bd_addr_t blockCnt = size / _block_size; addr = addr / _block_size; // make sure card is ready - while (SD_GetCardState() != SD_TRANSFER_OK) { + while (SD_GetCardState() != SD_TRANSFER_OK) + { // wait until SD ready wait_ms(1); } @@ -183,22 +197,27 @@ int SDIOBlockDevice::read(void* b, bd_addr_t addr, bd_size_t size) { int status = SD_ReadBlocks_DMA(buffer, addr, blockCnt); debug_if(SD_DBG, "ReadBlocks dbgtest addr: %lld blockCnt: %lld \n", addr, blockCnt); - if (status == MSD_OK) { + if (status == MSD_OK) + { // wait until DMA finished - while (SD_DMA_ReadPending() != SD_TRANSFER_OK) { + while (SD_DMA_ReadPending() != SD_TRANSFER_OK) + { uint32_t tickstart = HAL_GetTick(); - if((HAL_GetTick() - tickstart) >= MBED_CONF_SD_TIMEOUT) { + if ((HAL_GetTick() - tickstart) >= MBED_CONF_SD_TIMEOUT) + { unlock(); return SD_BLOCK_DEVICE_ERROR_READBLOCKS; } } // make sure card is ready - while (SD_GetCardState() != SD_TRANSFER_OK) { + while (SD_GetCardState() != SD_TRANSFER_OK) + { // wait until SD ready wait_ms(10); } } - else { + else + { debug_if(SD_DBG, "ReadBlocks failed! addr: %lld blockCnt: %lld \n", addr, blockCnt); debug_if(SD_DBG, " hsd.errorcode: %lu 0x%lx\n", hsd.ErrorCode, hsd.ErrorCode); status = SD_BLOCK_DEVICE_ERROR_READBLOCKS; @@ -208,20 +227,24 @@ int SDIOBlockDevice::read(void* b, bd_addr_t addr, bd_size_t size) { return status; } -int SDIOBlockDevice::program(const void* b, bd_addr_t addr, bd_size_t size) { +int SDIOBlockDevice::program(const void *b, bd_addr_t addr, bd_size_t size) +{ //debug_if(SD_DBG, "program Card...\r\n"); lock(); - if (isPresent() == false) { + if (isPresent() == false) + { unlock(); return SD_BLOCK_DEVICE_ERROR_NO_DEVICE; } - if (!is_valid_program(addr, size)) { + if (!is_valid_program(addr, size)) + { unlock(); return SD_BLOCK_DEVICE_ERROR_PARAMETER; } - if (!_is_initialized) { + if (!_is_initialized) + { unlock(); return SD_BLOCK_DEVICE_ERROR_NO_INIT; } @@ -235,7 +258,8 @@ int SDIOBlockDevice::program(const void* b, bd_addr_t addr, bd_size_t size) { addr = addr / _block_size; // make sure card is ready - while (SD_GetCardState() != SD_TRANSFER_OK) { + while (SD_GetCardState() != SD_TRANSFER_OK) + { // wait until SD ready wait_ms(1); } @@ -243,22 +267,27 @@ int SDIOBlockDevice::program(const void* b, bd_addr_t addr, bd_size_t size) { int status = SD_WriteBlocks_DMA(buffer, addr, blockCnt); debug_if(SD_DBG, "WriteBlocks dbgtest addr: %lld blockCnt: %lld \n", addr, blockCnt); - if (status == MSD_OK) { + if (status == MSD_OK) + { // wait until DMA finished - while (SD_DMA_WritePending() != SD_TRANSFER_OK) { + while (SD_DMA_WritePending() != SD_TRANSFER_OK) + { uint32_t tickstart = HAL_GetTick(); - if((HAL_GetTick() - tickstart) >= MBED_CONF_SD_TIMEOUT) { + if ((HAL_GetTick() - tickstart) >= MBED_CONF_SD_TIMEOUT) + { unlock(); status = SD_BLOCK_DEVICE_ERROR_WRITEBLOCKS; } } // make sure card is ready - while (SD_GetCardState() != SD_TRANSFER_OK) { + while (SD_GetCardState() != SD_TRANSFER_OK) + { // wait until SD ready wait_ms(1); } } - else { + else + { debug_if(SD_DBG, "WriteBlocks failed! addr: %lld blockCnt: %lld \n", addr, blockCnt); debug_if(SD_DBG, " hsd.errorcode: %lu 0x%lx\n", hsd.ErrorCode, hsd.ErrorCode); status = SD_BLOCK_DEVICE_ERROR_WRITEBLOCKS; @@ -268,19 +297,23 @@ int SDIOBlockDevice::program(const void* b, bd_addr_t addr, bd_size_t size) { return status; } -int SDIOBlockDevice::trim(bd_addr_t addr, bd_size_t size) { +int SDIOBlockDevice::trim(bd_addr_t addr, bd_size_t size) +{ debug_if(SD_DBG, "trim Card...\r\n"); lock(); - if (isPresent() == false) { + if (isPresent() == false) + { unlock(); return SD_BLOCK_DEVICE_ERROR_NO_DEVICE; } - if (!_is_valid_trim(addr, size)) { + if (!_is_valid_trim(addr, size)) + { unlock(); return SD_BLOCK_DEVICE_ERROR_PARAMETER; } - if (!_is_initialized) { + if (!_is_initialized) + { unlock(); return SD_BLOCK_DEVICE_ERROR_NO_INIT; } @@ -289,12 +322,15 @@ int SDIOBlockDevice::trim(bd_addr_t addr, bd_size_t size) { addr = addr / _block_size; int status = SD_Erase(addr, blockCnt); - if (status != 0) { + if (status != 0) + { debug_if(SD_DBG, "Erase blocks failed! addr: %lld blockCnt: %lld \n", addr, blockCnt); status = SD_BLOCK_DEVICE_ERROR_ERASEBLOCKS; } - else { - while (SD_GetCardState() != SD_TRANSFER_OK) { + else + { + while (SD_GetCardState() != SD_TRANSFER_OK) + { // wait until SD ready wait_ms(10); } @@ -304,36 +340,39 @@ int SDIOBlockDevice::trim(bd_addr_t addr, bd_size_t size) { return status; } -bd_size_t SDIOBlockDevice::get_read_size() const { +bd_size_t SDIOBlockDevice::get_read_size() const +{ return _block_size; } -bd_size_t SDIOBlockDevice::get_program_size() const { +bd_size_t SDIOBlockDevice::get_program_size() const +{ return _block_size; } -bd_size_t SDIOBlockDevice::size() const { +bd_size_t SDIOBlockDevice::size() const +{ return _block_size * _sectors; } -void SDIOBlockDevice::debug(bool dbg) { +void SDIOBlockDevice::debug(bool dbg) +{ } bool SDIOBlockDevice::_is_valid_trim(bd_addr_t addr, bd_size_t size) { return ( - addr % _erase_size == 0 && - size % _erase_size == 0 && - addr + size <= this->size()); + addr % _erase_size == 0 && + size % _erase_size == 0 && + addr + size <= this->size()); } -bool SDIOBlockDevice::isPresent(void) { +bool SDIOBlockDevice::isPresent(void) +{ if (_cardDetect.is_connected()) return (_cardDetect.read() == 0); else return true; } - } // namespace mbed - diff --git a/components/storage/blockdevice/COMPONENT_SDIO/SDIOBlockDevice.h b/components/storage/blockdevice/COMPONENT_SDIO/SDIOBlockDevice.h index 1afa1d927f0..68feeab24ca 100644 --- a/components/storage/blockdevice/COMPONENT_SDIO/SDIOBlockDevice.h +++ b/components/storage/blockdevice/COMPONENT_SDIO/SDIOBlockDevice.h @@ -14,7 +14,6 @@ * limitations under the License. */ - #ifndef MBED_OS_FEATURES_STORAGE_BLOCKDEVICE_SDIOBLOCKDEVICE_H_ #define MBED_OS_FEATURES_STORAGE_BLOCKDEVICE_SDIOBLOCKDEVICE_H_ @@ -24,11 +23,13 @@ #include "platform/PlatformMutex.h" #include "targets/TARGET_STM/TARGET_STM32F4/sdio_device.h" -namespace mbed { +namespace mbed +{ -class SDIOBlockDevice: public BlockDevice { -public: - SDIOBlockDevice(PinName cardDetect=NC); +class SDIOBlockDevice : public BlockDevice +{ + public: + SDIOBlockDevice(PinName cardDetect = NC); virtual ~SDIOBlockDevice(); /** Initialize a block device * @@ -105,7 +106,7 @@ class SDIOBlockDevice: public BlockDevice { * @param freq Transfer frequency * @note Max frequency supported is 25MHZ */ - virtual int frequency(uint64_t freq) {return BD_ERROR_OK;}; + virtual int frequency(uint64_t freq) { return BD_ERROR_OK; }; /** check if SD is present * @@ -113,7 +114,7 @@ class SDIOBlockDevice: public BlockDevice { */ virtual bool isPresent(void); -private: + private: DigitalIn _cardDetect; bool _is_initialized; bd_size_t _block_size; @@ -135,12 +136,8 @@ class SDIOBlockDevice: public BlockDevice { } bool _is_valid_trim(bd_addr_t addr, bd_size_t size); - - }; - } // namespace mbed - #endif /* MBED_OS_FEATURES_STORAGE_BLOCKDEVICE_SDIOBLOCKDEVICE_H_ */ diff --git a/targets/TARGET_STM/TARGET_STM32F4/sdio_device.c b/targets/TARGET_STM/TARGET_STM32F4/sdio_device.c index 1e076d5d3e1..6979c7140a6 100644 --- a/targets/TARGET_STM/TARGET_STM32F4/sdio_device.c +++ b/targets/TARGET_STM/TARGET_STM32F4/sdio_device.c @@ -60,9 +60,8 @@ DMA_HandleTypeDef hdma_sdio_rx; DMA_HandleTypeDef hdma_sdio_tx; // simple flags for DMA pending signaling -volatile uint8_t SD_DMA_ReadPendingState = SD_TRANSFER_OK; -volatile uint8_t SD_DMA_WritePendingState = SD_TRANSFER_OK; - +volatile uint8_t SD_DMA_ReadPendingState = SD_TRANSFER_OK; +volatile uint8_t SD_DMA_WritePendingState = SD_TRANSFER_OK; /* DMA Handlers are global, there is only one SDIO interface */ @@ -79,7 +78,7 @@ void _SDIO_IRQHandler(void) */ void _DMA_Stream_Rx_IRQHandler(void) { - HAL_DMA_IRQHandler(hsd.hdmarx); + HAL_DMA_IRQHandler(hsd.hdmarx); } /** @@ -87,18 +86,20 @@ void _DMA_Stream_Rx_IRQHandler(void) */ void _DMA_Stream_Tx_IRQHandler(void) { - HAL_DMA_IRQHandler(hsd.hdmatx); + HAL_DMA_IRQHandler(hsd.hdmatx); } /** * * @param hsd: Handle for SD handle Structure definition */ -void HAL_SD_MspInit(SD_HandleTypeDef *hsd) { +void HAL_SD_MspInit(SD_HandleTypeDef *hsd) +{ IRQn_Type IRQn; GPIO_InitTypeDef GPIO_InitStruct; - if (hsd->Instance == SDIO) { + if (hsd->Instance == SDIO) + { /* Peripheral clock enable */ __HAL_RCC_SDIO_CLK_ENABLE(); __HAL_RCC_DMA2_CLK_ENABLE(); @@ -132,7 +133,7 @@ void HAL_SD_MspInit(SD_HandleTypeDef *hsd) { /* NVIC configuration for SDIO interrupts */ IRQn = SDIO_IRQn; HAL_NVIC_SetPriority(IRQn, 0x0E, 0); - NVIC_SetVector(IRQn, (uint32_t) &_SDIO_IRQHandler); + NVIC_SetVector(IRQn, (uint32_t)&_SDIO_IRQHandler); HAL_NVIC_EnableIRQ(IRQn); /* SDIO DMA Init */ @@ -150,7 +151,8 @@ void HAL_SD_MspInit(SD_HandleTypeDef *hsd) { hdma_sdio_rx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; hdma_sdio_rx.Init.MemBurst = DMA_MBURST_INC4; hdma_sdio_rx.Init.PeriphBurst = DMA_PBURST_INC4; - if (HAL_DMA_Init(&hdma_sdio_rx) != HAL_OK) { + if (HAL_DMA_Init(&hdma_sdio_rx) != HAL_OK) + { error("SDIO DMA Init error at %d in %s", __FILE__, __LINE__); } @@ -162,7 +164,6 @@ void HAL_SD_MspInit(SD_HandleTypeDef *hsd) { /* Configure the DMA stream */ HAL_DMA_Init(&hdma_sdio_rx); - /* SDIO_TX Init */ hdma_sdio_tx.Instance = DMA2_Stream6; hdma_sdio_tx.Init.Channel = DMA_CHANNEL_4; @@ -177,7 +178,8 @@ void HAL_SD_MspInit(SD_HandleTypeDef *hsd) { hdma_sdio_tx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; hdma_sdio_tx.Init.MemBurst = DMA_MBURST_INC4; hdma_sdio_tx.Init.PeriphBurst = DMA_PBURST_INC4; - if (HAL_DMA_Init(&hdma_sdio_tx) != HAL_OK) { + if (HAL_DMA_Init(&hdma_sdio_tx) != HAL_OK) + { error("SDIO DMA Init error at %d in %s", __FILE__, __LINE__); } @@ -191,12 +193,12 @@ void HAL_SD_MspInit(SD_HandleTypeDef *hsd) { /* Enable NVIC for DMA transfer complete interrupts */ IRQn = DMA2_Stream3_IRQn; - NVIC_SetVector(IRQn, (uint32_t) &_DMA_Stream_Rx_IRQHandler); + NVIC_SetVector(IRQn, (uint32_t)&_DMA_Stream_Rx_IRQHandler); HAL_NVIC_SetPriority(IRQn, 0x0F, 0); HAL_NVIC_EnableIRQ(IRQn); IRQn = DMA2_Stream6_IRQn; - NVIC_SetVector(IRQn, (uint32_t) &_DMA_Stream_Tx_IRQHandler); + NVIC_SetVector(IRQn, (uint32_t)&_DMA_Stream_Tx_IRQHandler); HAL_NVIC_SetPriority(IRQn, 0x0F, 0); HAL_NVIC_EnableIRQ(IRQn); } @@ -206,9 +208,11 @@ void HAL_SD_MspInit(SD_HandleTypeDef *hsd) { * * @param hsd: Handle for SD handle Structure definition */ -void HAL_SD_MspDeInit(SD_HandleTypeDef *hsd) { +void HAL_SD_MspDeInit(SD_HandleTypeDef *hsd) +{ - if (hsd->Instance == SDIO) { + if (hsd->Instance == SDIO) + { /* Peripheral clock disable */ __HAL_RCC_SDIO_CLK_DISABLE(); @@ -228,7 +232,6 @@ void HAL_SD_MspDeInit(SD_HandleTypeDef *hsd) { HAL_DMA_DeInit(hsd->hdmarx); HAL_DMA_DeInit(hsd->hdmatx); } - } /** @@ -236,7 +239,8 @@ void HAL_SD_MspDeInit(SD_HandleTypeDef *hsd) { * @param hsd: SD handle * @param Params : pointer on additional configuration parameters, can be NULL. */ -__weak void SD_MspDeInit(SD_HandleTypeDef *hsd, void *Params) { +__weak void SD_MspDeInit(SD_HandleTypeDef *hsd, void *Params) +{ static DMA_HandleTypeDef dma_rx_handle; static DMA_HandleTypeDef dma_tx_handle; @@ -268,23 +272,23 @@ static uint32_t SD_WideBus_Enable(SD_HandleTypeDef *hsd) { uint32_t errorstate = HAL_SD_ERROR_NONE; - if((SDIO_GetResponse(hsd->Instance, SDIO_RESP1) & SDMMC_CARD_LOCKED) == SDMMC_CARD_LOCKED) + if ((SDIO_GetResponse(hsd->Instance, SDIO_RESP1) & SDMMC_CARD_LOCKED) == SDMMC_CARD_LOCKED) { - return HAL_SD_ERROR_LOCK_UNLOCK_FAILED; + return HAL_SD_ERROR_LOCK_UNLOCK_FAILED; } /* Send CMD55 APP_CMD with argument as card's RCA.*/ errorstate = SDMMC_CmdAppCommand(hsd->Instance, (uint32_t)(hsd->SdCard.RelCardAdd << 16U)); - if(errorstate != HAL_OK) + if (errorstate != HAL_OK) { - return errorstate; + return errorstate; } /* Send ACMD6 APP_CMD with argument as 2 for wide bus mode */ errorstate = SDMMC_CmdBusWidth(hsd->Instance, 2U); - if(errorstate != HAL_OK) + if (errorstate != HAL_OK) { - return errorstate; + return errorstate; } hsd->Init.BusWide = SDIO_BUS_WIDE_4B; @@ -297,7 +301,8 @@ static uint32_t SD_WideBus_Enable(SD_HandleTypeDef *hsd) * @brief Initializes the SD card device. * @retval SD status */ -uint8_t SD_Init(void) { +uint8_t SD_Init(void) +{ uint8_t sd_state = MSD_OK; hsd.Instance = SDIO; @@ -311,9 +316,11 @@ uint8_t SD_Init(void) { /* HAL SD initialization */ sd_state = HAL_SD_Init(&hsd); /* Configure SD Bus width (4 bits mode selected) */ - if (sd_state == MSD_OK) { + if (sd_state == MSD_OK) + { /* Enable wide operation */ - if (SD_WideBus_Enable(&hsd) != HAL_OK) { + if (SD_WideBus_Enable(&hsd) != HAL_OK) + { sd_state = MSD_ERROR; } } @@ -325,13 +332,15 @@ uint8_t SD_Init(void) { * @brief DeInitializes the SD card device. * @retval SD status */ -uint8_t SD_DeInit(void) { +uint8_t SD_DeInit(void) +{ uint8_t sd_state = MSD_OK; hsd.Instance = SDIO; /* HAL SD deinitialization */ - if (HAL_SD_DeInit(&hsd) != HAL_OK) { + if (HAL_SD_DeInit(&hsd) != HAL_OK) + { sd_state = MSD_ERROR; } @@ -350,10 +359,12 @@ uint8_t SD_DeInit(void) { * @param Timeout: Timeout for read operation * @retval SD status */ -uint8_t SD_ReadBlocks(uint32_t *pData, uint32_t ReadAddr, uint32_t NumOfBlocks, uint32_t Timeout) { +uint8_t SD_ReadBlocks(uint32_t *pData, uint32_t ReadAddr, uint32_t NumOfBlocks, uint32_t Timeout) +{ uint8_t sd_state = MSD_OK; - if (HAL_SD_ReadBlocks(&hsd, (uint8_t *) pData, ReadAddr, NumOfBlocks, Timeout) != HAL_OK) { + if (HAL_SD_ReadBlocks(&hsd, (uint8_t *)pData, ReadAddr, NumOfBlocks, Timeout) != HAL_OK) + { sd_state = MSD_ERROR; } @@ -368,10 +379,12 @@ uint8_t SD_ReadBlocks(uint32_t *pData, uint32_t ReadAddr, uint32_t NumOfBlocks, * @param Timeout: Timeout for write operation * @retval SD status */ -uint8_t SD_WriteBlocks(uint32_t *pData, uint32_t WriteAddr, uint32_t NumOfBlocks, uint32_t Timeout) { +uint8_t SD_WriteBlocks(uint32_t *pData, uint32_t WriteAddr, uint32_t NumOfBlocks, uint32_t Timeout) +{ uint8_t sd_state = MSD_OK; - if (HAL_SD_WriteBlocks(&hsd, (uint8_t *) pData, WriteAddr, NumOfBlocks, Timeout) != HAL_OK) { + if (HAL_SD_WriteBlocks(&hsd, (uint8_t *)pData, WriteAddr, NumOfBlocks, Timeout) != HAL_OK) + { sd_state = MSD_ERROR; } @@ -385,14 +398,16 @@ uint8_t SD_WriteBlocks(uint32_t *pData, uint32_t WriteAddr, uint32_t NumOfBlocks * @param NumOfBlocks: Number of SD blocks to read * @retval SD status */ -uint8_t SD_ReadBlocks_DMA(uint32_t *pData, uint32_t ReadAddr, uint32_t NumOfBlocks) { +uint8_t SD_ReadBlocks_DMA(uint32_t *pData, uint32_t ReadAddr, uint32_t NumOfBlocks) +{ uint8_t sd_state = MSD_OK; SD_DMA_ReadPendingState = SD_TRANSFER_BUSY; /* Read block(s) in DMA transfer mode */ - if (HAL_SD_ReadBlocks_DMA(&hsd, (uint8_t *) pData, ReadAddr, NumOfBlocks) != HAL_OK) { + if (HAL_SD_ReadBlocks_DMA(&hsd, (uint8_t *)pData, ReadAddr, NumOfBlocks) != HAL_OK) + { sd_state = MSD_ERROR; - SD_DMA_ReadPendingState = SD_TRANSFER_OK; + SD_DMA_ReadPendingState = SD_TRANSFER_OK; } return sd_state; @@ -405,14 +420,16 @@ uint8_t SD_ReadBlocks_DMA(uint32_t *pData, uint32_t ReadAddr, uint32_t NumOfBloc * @param NumOfBlocks: Number of SD blocks to write * @retval SD status */ -uint8_t SD_WriteBlocks_DMA(uint32_t *pData, uint32_t WriteAddr, uint32_t NumOfBlocks) { +uint8_t SD_WriteBlocks_DMA(uint32_t *pData, uint32_t WriteAddr, uint32_t NumOfBlocks) +{ uint8_t sd_state = MSD_OK; SD_DMA_WritePendingState = SD_TRANSFER_BUSY; /* Write block(s) in DMA transfer mode */ - if (HAL_SD_WriteBlocks_DMA(&hsd, (uint8_t *) pData, WriteAddr, NumOfBlocks) != HAL_OK) { + if (HAL_SD_WriteBlocks_DMA(&hsd, (uint8_t *)pData, WriteAddr, NumOfBlocks) != HAL_OK) + { sd_state = MSD_ERROR; - SD_DMA_WritePendingState = SD_TRANSFER_OK; + SD_DMA_WritePendingState = SD_TRANSFER_OK; } return sd_state; @@ -424,10 +441,12 @@ uint8_t SD_WriteBlocks_DMA(uint32_t *pData, uint32_t WriteAddr, uint32_t NumOfBl * @param EndAddr: End byte address * @retval SD status */ -uint8_t SD_Erase(uint32_t StartAddr, uint32_t EndAddr) { +uint8_t SD_Erase(uint32_t StartAddr, uint32_t EndAddr) +{ uint8_t sd_state = MSD_OK; - if (HAL_SD_Erase(&hsd, StartAddr, EndAddr) != HAL_OK) { + if (HAL_SD_Erase(&hsd, StartAddr, EndAddr) != HAL_OK) + { sd_state = MSD_ERROR; } @@ -442,7 +461,8 @@ uint8_t SD_Erase(uint32_t StartAddr, uint32_t EndAddr) { * @arg SD_TRANSFER_OK: No data transfer is acting * @arg SD_TRANSFER_BUSY: Data transfer is acting */ -uint8_t SD_GetCardState(void) { +uint8_t SD_GetCardState(void) +{ return ((HAL_SD_GetCardState(&hsd) == HAL_SD_CARD_TRANSFER) ? SD_TRANSFER_OK : SD_TRANSFER_BUSY); } @@ -451,21 +471,23 @@ uint8_t SD_GetCardState(void) { * @param CardInfo: Pointer to HAL_SD_CardInfoTypedef structure * @retval None */ -void SD_GetCardInfo(SD_Cardinfo_t *CardInfo) { +void SD_GetCardInfo(SD_Cardinfo_t *CardInfo) +{ /* Get SD card Information, copy structure for portability */ - HAL_SD_CardInfoTypeDef HAL_CardInfo; + HAL_SD_CardInfoTypeDef HAL_CardInfo; HAL_SD_GetCardInfo(&hsd, &HAL_CardInfo); - if (CardInfo) { - CardInfo->CardType = HAL_CardInfo.CardType; - CardInfo->CardVersion = HAL_CardInfo.CardVersion; - CardInfo->Class = HAL_CardInfo.Class; - CardInfo->RelCardAdd = HAL_CardInfo.RelCardAdd; - CardInfo->BlockNbr = HAL_CardInfo.BlockNbr; - CardInfo->BlockSize = HAL_CardInfo.BlockSize; - CardInfo->LogBlockNbr = HAL_CardInfo.LogBlockNbr; - CardInfo->LogBlockSize = HAL_CardInfo.LogBlockSize; + if (CardInfo) + { + CardInfo->CardType = HAL_CardInfo.CardType; + CardInfo->CardVersion = HAL_CardInfo.CardVersion; + CardInfo->Class = HAL_CardInfo.Class; + CardInfo->RelCardAdd = HAL_CardInfo.RelCardAdd; + CardInfo->BlockNbr = HAL_CardInfo.BlockNbr; + CardInfo->BlockSize = HAL_CardInfo.BlockSize; + CardInfo->LogBlockNbr = HAL_CardInfo.LogBlockNbr; + CardInfo->LogBlockSize = HAL_CardInfo.LogBlockSize; } } @@ -476,7 +498,8 @@ void SD_GetCardInfo(SD_Cardinfo_t *CardInfo) { * @arg SD_TRANSFER_OK: No data transfer is acting * @arg SD_TRANSFER_BUSY: Data transfer is acting */ -uint8_t SD_DMA_ReadPending(void) { +uint8_t SD_DMA_ReadPending(void) +{ return SD_DMA_ReadPendingState; } @@ -487,7 +510,8 @@ uint8_t SD_DMA_ReadPending(void) { * @arg SD_TRANSFER_OK: No data transfer is acting * @arg SD_TRANSFER_BUSY: Data transfer is acting */ -uint8_t SD_DMA_WritePending(void) { +uint8_t SD_DMA_WritePending(void) +{ return SD_DMA_WritePendingState; } @@ -498,7 +522,7 @@ uint8_t SD_DMA_WritePending(void) { */ void HAL_SD_RxCpltCallback(SD_HandleTypeDef *hsd) { - SD_DMA_ReadPendingState = SD_TRANSFER_OK; + SD_DMA_ReadPendingState = SD_TRANSFER_OK; } /** @@ -508,8 +532,7 @@ void HAL_SD_RxCpltCallback(SD_HandleTypeDef *hsd) */ void HAL_SD_TxCpltCallback(SD_HandleTypeDef *hsd) { - SD_DMA_WritePendingState = SD_TRANSFER_OK; + SD_DMA_WritePendingState = SD_TRANSFER_OK; } - /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/targets/TARGET_STM/TARGET_STM32F4/sdio_device.h b/targets/TARGET_STM/TARGET_STM32F4/sdio_device.h index c86227172a6..edd20ac4527 100644 --- a/targets/TARGET_STM/TARGET_STM32F4/sdio_device.h +++ b/targets/TARGET_STM/TARGET_STM32F4/sdio_device.h @@ -56,28 +56,29 @@ #define __STM32F4_SD_H #ifdef __cplusplus - extern "C" { -#endif +extern "C" +{ +#endif #include "stm32f4xx_hal.h" - /* Typedefs */ - -typedef struct{ - uint32_t CardType; /* Specifies the card Type */ - uint32_t CardVersion; /* Specifies the card version */ - uint32_t Class; /* Specifies the class of the card class */ - uint32_t RelCardAdd; /* Specifies the Relative Card Address */ - uint32_t BlockNbr; /* Specifies the Card Capacity in blocks */ - uint32_t BlockSize; /* Specifies one block size in bytes */ - uint32_t LogBlockNbr; /* Specifies the Card logical Capacity in blocks */ - uint32_t LogBlockSize; /* Specifies logical block size in bytes */ -} SD_Cardinfo_t; + /* Typedefs */ + typedef struct + { + uint32_t CardType; /* Specifies the card Type */ + uint32_t CardVersion; /* Specifies the card version */ + uint32_t Class; /* Specifies the class of the card class */ + uint32_t RelCardAdd; /* Specifies the Relative Card Address */ + uint32_t BlockNbr; /* Specifies the Card Capacity in blocks */ + uint32_t BlockSize; /* Specifies one block size in bytes */ + uint32_t LogBlockNbr; /* Specifies the Card logical Capacity in blocks */ + uint32_t LogBlockSize; /* Specifies logical block size in bytes */ + } SD_Cardinfo_t; -/* External Global var */ + /* External Global var */ -extern SD_HandleTypeDef hsd; + extern SD_HandleTypeDef hsd; /* Exported types */ /** @@ -88,34 +89,33 @@ extern SD_HandleTypeDef hsd; /* Exported constants */ /** * @brief SD status structure definition - */ -#define MSD_OK ((uint8_t)0x00) -#define MSD_ERROR ((uint8_t)0x01) + */ +#define MSD_OK ((uint8_t)0x00) +#define MSD_ERROR ((uint8_t)0x01) /** * @brief SD transfer state definition - */ -#define SD_TRANSFER_OK ((uint8_t)0x00) -#define SD_TRANSFER_BUSY ((uint8_t)0x01) - -/* Exported functions */ -uint8_t SD_Init(void); -uint8_t SD_DeInit(void); -uint8_t SD_ReadBlocks(uint32_t *pData, uint32_t ReadAddr, uint32_t NumOfBlocks, uint32_t Timeout); -uint8_t SD_WriteBlocks(uint32_t *pData, uint32_t WriteAddr, uint32_t NumOfBlocks, uint32_t Timeout); -uint8_t SD_ReadBlocks_DMA(uint32_t *pData, uint32_t ReadAddr, uint32_t NumOfBlocks); -uint8_t SD_WriteBlocks_DMA(uint32_t *pData, uint32_t WriteAddr, uint32_t NumOfBlocks); -uint8_t SD_DMA_ReadPending(void); -uint8_t SD_DMA_WritePending(void); -uint8_t SD_Erase(uint32_t StartAddr, uint32_t EndAddr); - -uint8_t SD_GetCardState(void); -void SD_GetCardInfo(SD_Cardinfo_t *CardInfo); - -/* callback function for DMA Rx/Tx completete, called by HAL SDIO interrupt handler */ -void HAL_SD_TxCpltCallback(SD_HandleTypeDef *hsd); -void HAL_SD_RxCpltCallback(SD_HandleTypeDef *hsd); - + */ +#define SD_TRANSFER_OK ((uint8_t)0x00) +#define SD_TRANSFER_BUSY ((uint8_t)0x01) + + /* Exported functions */ + uint8_t SD_Init(void); + uint8_t SD_DeInit(void); + uint8_t SD_ReadBlocks(uint32_t *pData, uint32_t ReadAddr, uint32_t NumOfBlocks, uint32_t Timeout); + uint8_t SD_WriteBlocks(uint32_t *pData, uint32_t WriteAddr, uint32_t NumOfBlocks, uint32_t Timeout); + uint8_t SD_ReadBlocks_DMA(uint32_t *pData, uint32_t ReadAddr, uint32_t NumOfBlocks); + uint8_t SD_WriteBlocks_DMA(uint32_t *pData, uint32_t WriteAddr, uint32_t NumOfBlocks); + uint8_t SD_DMA_ReadPending(void); + uint8_t SD_DMA_WritePending(void); + uint8_t SD_Erase(uint32_t StartAddr, uint32_t EndAddr); + + uint8_t SD_GetCardState(void); + void SD_GetCardInfo(SD_Cardinfo_t *CardInfo); + + /* callback function for DMA Rx/Tx completete, called by HAL SDIO interrupt handler */ + void HAL_SD_TxCpltCallback(SD_HandleTypeDef *hsd); + void HAL_SD_RxCpltCallback(SD_HandleTypeDef *hsd); #ifdef __cplusplus } From fc7e628728bdf04f8c38e04f6068c2f9068b7ff1 Mon Sep 17 00:00:00 2001 From: JojoS62 Date: Mon, 5 Nov 2018 15:30:34 +0100 Subject: [PATCH 13/13] remvove target specific path from include remvove target specific path from include, add full path for feature blockdevice.h --- .../storage/blockdevice/COMPONENT_SDIO/SDIOBlockDevice.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/storage/blockdevice/COMPONENT_SDIO/SDIOBlockDevice.h b/components/storage/blockdevice/COMPONENT_SDIO/SDIOBlockDevice.h index 68feeab24ca..98408331d54 100644 --- a/components/storage/blockdevice/COMPONENT_SDIO/SDIOBlockDevice.h +++ b/components/storage/blockdevice/COMPONENT_SDIO/SDIOBlockDevice.h @@ -18,10 +18,10 @@ #define MBED_OS_FEATURES_STORAGE_BLOCKDEVICE_SDIOBLOCKDEVICE_H_ -#include "BlockDevice.h" +#include "features/storage/blockdevice/BlockDevice.h" #include "drivers/DigitalIn.h" #include "platform/PlatformMutex.h" -#include "targets/TARGET_STM/TARGET_STM32F4/sdio_device.h" +#include "sdio_device.h" namespace mbed {