From a9deb13504ecc96c24fa7addfcad0d625000499b Mon Sep 17 00:00:00 2001 From: JojoS62 Date: Fri, 9 Nov 2018 22:36:28 +0100 Subject: [PATCH 01/17] initial commit add SDIOBlockdevice implementation for STM32F4 --- SDIOBlockDevice.cpp | 378 ++++++ SDIOBlockDevice.h | 143 ++ TARGET_STM/TARGET_STM32F4/sdio_device.c | 538 ++++++++ TARGET_STM/TARGET_STM32F4/sdio_device.h | 126 ++ TESTS/blockdevice/basic/main.cpp | 119 ++ 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 +++++++++ config/mbed_lib.json | 12 + 11 files changed, 4639 insertions(+) create mode 100644 SDIOBlockDevice.cpp create mode 100644 SDIOBlockDevice.h create mode 100644 TARGET_STM/TARGET_STM32F4/sdio_device.c create mode 100644 TARGET_STM/TARGET_STM32F4/sdio_device.h create mode 100644 TESTS/blockdevice/basic/main.cpp create mode 100644 TESTS/filesystem/dirs/main.cpp create mode 100644 TESTS/filesystem/files/main.cpp create mode 100644 TESTS/filesystem/fopen/fopen.cpp create mode 100644 TESTS/filesystem/parallel/main.cpp create mode 100644 TESTS/filesystem/seek/main.cpp create mode 100644 config/mbed_lib.json diff --git a/SDIOBlockDevice.cpp b/SDIOBlockDevice.cpp new file mode 100644 index 0000000..86572bb --- /dev/null +++ b/SDIOBlockDevice.cpp @@ -0,0 +1,378 @@ +/* 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 + */ + +#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), + _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"); + + lock(); + + if (!_is_initialized) + { + _init_ref_count = 0; + } + + _init_ref_count++; + + if (_init_ref_count != 1) + { + unlock(); + return BD_ERROR_OK; + } + + if (isPresent() == false) + { + unlock(); + return SD_BLOCK_DEVICE_ERROR_NO_DEVICE; + } + + int status = SD_Init(); + if (BD_ERROR_OK != status) + { + unlock(); + 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) + { + unlock(); + return SD_BLOCK_DEVICE_ERROR_UNSUPPORTED_BLOCKSIZE; + } + + unlock(); + return status; +} + +int SDIOBlockDevice::deinit() +{ + debug_if(SD_DBG, "deinit Card...\r\n"); + lock(); + + if (!_is_initialized) + { + _init_ref_count = 0; + unlock(); + return BD_ERROR_OK; + } + + _init_ref_count--; + + if (_init_ref_count) + { + unlock(); + return BD_ERROR_OK; + } + + int status = SD_DeInit(); + _is_initialized = false; + + _sectors = 0; + + unlock(); + 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; + } + + if (!_is_initialized) + { + unlock(); + return SD_BLOCK_DEVICE_ERROR_NO_INIT; + } + + uint32_t *buffer = static_cast(b); + + // 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() + 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) + { + // 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; + } + } + // make sure card is ready + 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; + } + + 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"); + 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; + } + + 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); + + // Get block count + bd_size_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); + } + + 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(1); + } + } + 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; + } + + unlock(); + return status; +} + +int SDIOBlockDevice::trim(bd_addr_t addr, bd_size_t size) +{ + 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; + } + + if (!_is_initialized) + { + unlock(); + return SD_BLOCK_DEVICE_ERROR_NO_INIT; + } + + bd_size_t blockCnt = size / _block_size; + addr = addr / _block_size; + + 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; + } + else + { + while (SD_GetCardState() != SD_TRANSFER_OK) + { + // wait until SD ready + wait_ms(10); + } + } + + 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/SDIOBlockDevice.h b/SDIOBlockDevice.h new file mode 100644 index 0000000..9840833 --- /dev/null +++ b/SDIOBlockDevice.h @@ -0,0 +1,143 @@ +/* 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 "features/storage/blockdevice/BlockDevice.h" +#include "drivers/DigitalIn.h" +#include "platform/PlatformMutex.h" +#include "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: + DigitalIn _cardDetect; + bool _is_initialized; + bd_size_t _block_size; + bd_size_t _erase_size; + bd_size_t _sectors; + uint32_t _init_ref_count; + SD_Cardinfo_t _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_ */ diff --git a/TARGET_STM/TARGET_STM32F4/sdio_device.c b/TARGET_STM/TARGET_STM32F4/sdio_device.c new file mode 100644 index 0000000..6979c71 --- /dev/null +++ b/TARGET_STM/TARGET_STM32F4/sdio_device.c @@ -0,0 +1,538 @@ +/** + * + * 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 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 + */ +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; + + /* 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 (SD_WideBus_Enable(&hsd) != 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(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; + } +} + +/** + * @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/TARGET_STM/TARGET_STM32F4/sdio_device.h b/TARGET_STM/TARGET_STM32F4/sdio_device.h new file mode 100644 index 0000000..edd20ac --- /dev/null +++ b/TARGET_STM/TARGET_STM32F4/sdio_device.h @@ -0,0 +1,126 @@ +/** + * + * 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 + +#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 */ +/** + * @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(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 +} +#endif + +#endif /* __STM32F4_SD_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/TESTS/blockdevice/basic/main.cpp b/TESTS/blockdevice/basic/main.cpp new file mode 100644 index 0000000..709c07b --- /dev/null +++ b/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); +} diff --git a/TESTS/filesystem/dirs/main.cpp b/TESTS/filesystem/dirs/main.cpp new file mode 100644 index 0000000..fcb055a --- /dev/null +++ b/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/TESTS/filesystem/files/main.cpp b/TESTS/filesystem/files/main.cpp new file mode 100644 index 0000000..ed4d242 --- /dev/null +++ b/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/TESTS/filesystem/fopen/fopen.cpp b/TESTS/filesystem/fopen/fopen.cpp new file mode 100644 index 0000000..03c6fda --- /dev/null +++ b/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/TESTS/filesystem/parallel/main.cpp b/TESTS/filesystem/parallel/main.cpp new file mode 100644 index 0000000..2ae26ee --- /dev/null +++ b/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/TESTS/filesystem/seek/main.cpp b/TESTS/filesystem/seek/main.cpp new file mode 100644 index 0000000..e2fd2bd --- /dev/null +++ b/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); +} diff --git a/config/mbed_lib.json b/config/mbed_lib.json new file mode 100644 index 0000000..30d5324 --- /dev/null +++ b/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 d6beb4d96c3bfdcae0ef052e1b699fec4e93a674 Mon Sep 17 00:00:00 2001 From: JojoS62 Date: Fri, 9 Nov 2018 23:00:32 +0100 Subject: [PATCH 02/17] Update README.md added some description --- README.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/README.md b/README.md index e68e1c0..c0dde34 100644 --- a/README.md +++ b/README.md @@ -7,3 +7,22 @@ This is not officially supported driver. ## License & Contributions The software is provided under [Apache-2.0 license](LICENSE). Contributions to this project are accepted under the same license. Please see [contributing.md](CONTRIBUTING.md) for more info. + +This is an implementation for a blockdevice to use SDHC cards via SDIO interface. + +## Supported Hardware +- STM32F4 + +## Tested Hardware +- STM Discovery board 32F469IDISCOVERY, Targetname: DISCO_F469NI + https://os.mbed.com/platforms/ST-Discovery-F469NI/ + + +## Driver Description +This SDIOBlockdevice inherits from Blockdevice. The implementation uses an intermediate layer for the target specific code. This version uses the STM HAL +for the SD card communication, an approach that is not fully mBed compliant. So this driver is not part of the mbed-os, a cleaner solution maybe supplied in the future. Anyway, this driver passes the same tests as for a SDBlockdevice with SPI interface. + +## Usage +The driver is used like other blockdevices, a good starting point is https://github.com/ARMmbed/mbed-os-example-filesystem + + From e59a952ca8dbc85212f018b06d18eb6d37263d57 Mon Sep 17 00:00:00 2001 From: JojoS62 Date: Sat, 10 Nov 2018 09:38:15 +0100 Subject: [PATCH 03/17] add uitl folder, necessary for tests --- util/fsfat_debug.h | 103 ++++++++++++++++++++++++++++++++++++++++ util/fsfat_test.c | 116 +++++++++++++++++++++++++++++++++++++++++++++ util/fsfat_test.h | 74 +++++++++++++++++++++++++++++ 3 files changed, 293 insertions(+) create mode 100644 util/fsfat_debug.h create mode 100644 util/fsfat_test.c create mode 100644 util/fsfat_test.h diff --git a/util/fsfat_debug.h b/util/fsfat_debug.h new file mode 100644 index 0000000..f3d0a65 --- /dev/null +++ b/util/fsfat_debug.h @@ -0,0 +1,103 @@ +/* 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. + */ + +/** @file fsfat_debug.h + * + * component debug header file. + */ + + +#ifndef __FSFAT_DEBUG +#define __FSFAT_DEBUG + +#include +#include +#include + + +/* Debug Support */ + +#define FSFAT_LOG_NONE 0 +#define FSFAT_LOG_ERR 1 +#define FSFAT_LOG_WARN 2 +#define FSFAT_LOG_NOTICE 3 +#define FSFAT_LOG_INFO 4 +#define FSFAT_LOG_DEBUG 5 +#define FSFAT_LOG_FENTRY 6 + +#define FSFAT_LOG(_fmt, ...) \ + do \ + { \ + printf(_fmt, __VA_ARGS__); \ + }while(0); + +#define noFSFAT_DEBUG +#ifdef FSFAT_DEBUG + +extern uint32_t fsfat_optDebug_g; +extern uint32_t fsfat_optLogLevel_g; + +/* uncomment for asserts to work */ +/* #undef NDEBUG */ +// todo: port to mbedOSV3++ #include + +#define FSFAT_INLINE +// todo: port to mbedOSV3++ #define FSFAT_ASSERT CORE_UTIL_ASSERT +#define FSFAT_ASSERT(...) + +#define FSFAT_DBGLOG(_fmt, ...) \ + do \ + { \ + if(fsfat_optDebug_g && (fsfat_optLogLevel_g >= FSFAT_LOG_DEBUG)) \ + { \ + printf(_fmt, __VA_ARGS__); \ + } \ + }while(0); + + +#define FSFAT_ERRLOG(_fmt, ...) \ + do \ + { \ + if(fsfat_optDebug_g && (fsfat_optLogLevel_g >= FSFAT_LOG_ERR)) \ + { \ + printf(_fmt, __VA_ARGS__); \ + } \ + }while(0); + + +#define FSFAT_FENTRYLOG(_fmt, ...) \ + do \ + { \ + if(fsfat_optDebug_g && (fsfat_optLogLevel_g >= FSFAT_LOG_FENTRY)) \ + { \ + printf(_fmt, __VA_ARGS__); \ + } \ + }while(0); + + + + + +#else +#define FSFAT_ASSERT(_x) do { } while(0) +#define FSFAT_INLINE inline +#define FSFAT_DBGLOG(_fmt, ...) do { } while(0) +#define FSFAT_ERRLOG(_fmt, ...) do { } while(0) +#define FSFAT_FENTRYLOG(_fmt, ...) do { } while(0) +#endif /* FSFAT_DEBUG */ + + +#endif /*__FSFAT_DEBUG*/ diff --git a/util/fsfat_test.c b/util/fsfat_test.c new file mode 100644 index 0000000..d16997f --- /dev/null +++ b/util/fsfat_test.c @@ -0,0 +1,116 @@ +/* @file fsfat_test.c + * + * 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. + * + * test support code implementation file. + */ + +#include "fsfat_debug.h" +#include "fsfat_test.h" + +#include +#include +#include +#include +#include +#include + + +#ifdef FSFAT_DEBUG +uint32_t fsfat_optDebug_g = 1; +uint32_t fsfat_optLogLevel_g = FSFAT_LOG_FENTRY; /*FSFAT_LOG_NONE|FSFAT_LOG_ERR|FSFAT_LOG_DEBUG|FSFAT_LOG_FENTRY; */ +#endif + +/* ruler for measuring text strings */ +/* 1 1 1 1 1 1 1 1 1 1 2 2 2 */ +/* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 */ +/* 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890 */ + +const uint8_t fsfat_test_byte_data_table[FSFAT_TEST_BYTE_DATA_TABLE_SIZE] = { + 0x2d, 0xf3, 0x31, 0x4c, 0x11, 0x4f, 0xde, 0x0d, 0xbd, 0xbc, 0xa6, 0x78, 0x36, 0x5c, 0x1d, 0x28, + 0x5f, 0xa9, 0x10, 0x65, 0x54, 0x45, 0x21, 0x1a, 0x88, 0xfe, 0x76, 0x45, 0xb9, 0xac, 0x65, 0x9a, + 0x34, 0x9d, 0x73, 0x10, 0xb4, 0xa9, 0x2e, 0x90, 0x95, 0x68, 0xac, 0xfe, 0xc5, 0x2d, 0x15, 0x03, + 0x34, 0x70, 0xf1, 0x1d, 0x48, 0xa1, 0xa0, 0xed, 0x5c, 0x2f, 0xf5, 0x2b, 0xb9, 0x84, 0xbb, 0x45, + 0x32, 0xdd, 0xb1, 0x33, 0x95, 0x2a, 0xbc, 0x26, 0xf0, 0x89, 0xba, 0xf4, 0xbd, 0xf9, 0x5d, 0x2e, + 0x6e, 0x11, 0xc6, 0xa7, 0x78, 0xfc, 0xc9, 0x0e, 0x6b, 0x38, 0xba, 0x14, 0x1b, 0xab, 0x4c, 0x20, + 0x91, 0xe4, 0xb0, 0xf1, 0x2b, 0x14, 0x07, 0x6b, 0xb5, 0xcd, 0xe3, 0x49, 0x75, 0xac, 0xe8, 0x98, + 0xf1, 0x58, 0x8f, 0xd9, 0xc4, 0x8f, 0x00, 0x17, 0xb5, 0x06, 0x6a, 0x33, 0xbd, 0xa7, 0x40, 0x5a, + 0xbf, 0x49, 0xf7, 0x27, 0x1b, 0x4c, 0x3e, 0x6f, 0xe3, 0x08, 0x1f, 0xfd, 0xa6, 0xd4, 0xc7, 0x5f, + 0xa4, 0xa6, 0x82, 0xad, 0x19, 0xd5, 0x5c, 0xd8, 0x3a, 0x49, 0x85, 0xc9, 0x21, 0x83, 0xf6, 0xc6, + 0x84, 0xf9, 0x76, 0x89, 0xf3, 0x2d, 0x17, 0x50, 0x97, 0x38, 0x48, 0x9a, 0xe1, 0x82, 0xcd, 0xac, + 0xa8, 0x1d, 0xd7, 0x96, 0x5e, 0xb3, 0x08, 0xa8, 0x3a, 0xc7, 0x2b, 0x05, 0xaf, 0xdc, 0x16, 0xdf, + 0x48, 0x0f, 0x2a, 0x7e, 0x3a, 0x82, 0xd7, 0x80, 0xd6, 0x49, 0x27, 0x5d, 0xe3, 0x07, 0x62, 0xb3, + 0xc3, 0x6c, 0xba, 0xb2, 0xaa, 0x9f, 0xd9, 0x03, 0x0d, 0x27, 0xa8, 0xe0, 0xd6, 0xee, 0x79, 0x4b, + 0xd6, 0x97, 0x99, 0xb7, 0x11, 0xd6, 0x0d, 0x34, 0xae, 0x99, 0x4a, 0x93, 0x95, 0xd0, 0x5a, 0x34, + 0x19, 0xa2, 0x69, 0x57, 0xcf, 0x7c, 0x3d, 0x98, 0x88, 0x5d, 0x04, 0xf2, 0xd7, 0xac, 0xa5, 0x63 +}; + + +/* @brief test utility function to delete the file identified by filename + */ +int32_t fsfat_test_delete(const char *filename) +{ + FSFAT_FENTRYLOG("%s:entered.\r\n", __func__); + return remove(filename); +} + + +/* @brief test utility function to create a 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(const char *filename, const char *data, size_t len) +{ + int32_t ret = -1; + FILE *fp = NULL; + + FSFAT_FENTRYLOG("%s:entered (filename=%s, len=%d).\n", __func__, filename, (int) len); + fp = fopen(filename, "w+"); + if (fp == NULL) { + return ret; + } + ret = fwrite((const void *) data, len, 1, fp); + if (ret < 0) { + fclose(fp); + return ret; + } + fclose(fp); + return ret; +} + + +/* @brief support function for generating a kv_name + * @param name buffer to hold kv name + * @param len length of kv name to generate + * + */ +int32_t fsfat_test_filename_gen(char *name, const size_t len) +{ + size_t i; + uint32_t pos = 0; + + const char *buf = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!$-_@"; + const int buf_len = strlen(buf); + FSFAT_FENTRYLOG("%s:entered\n", __func__); + for (i = 0; i < len; i++) { + pos = rand() % (buf_len); + name[i] = buf[pos]; + } + return 0; +} + diff --git a/util/fsfat_test.h b/util/fsfat_test.h new file mode 100644 index 0000000..421c6a2 --- /dev/null +++ b/util/fsfat_test.h @@ -0,0 +1,74 @@ +/** @file fsfat_test.h + * + * 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. + * + * Header file for test support data structures and function API. + */ +#ifndef __FSFAT_TEST_H +#define __FSFAT_TEST_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Defines */ +//#define FSFAT_INIT_1_TABLE_HEAD { "a", ""} +#define FSFAT_INIT_1_TABLE_MID_NODE { "/sd/01234567.txt", "abcdefghijklmnopqrstuvwxyz"} +//#define FSFAT_INIT_1_TABLE_TAIL { "/sd/fopentst/hello/world/animal/wobbly/dog/foot/backrght.txt", "present"} +#define FSFAT_TEST_RW_TABLE_SENTINEL 0xffffffff +#define FSFAT_TEST_BYTE_DATA_TABLE_SIZE 256 +#define FSFAT_UTEST_MSG_BUF_SIZE 256 +#define FSFAT_UTEST_DEFAULT_TIMEOUT_MS 10000 +#define FSFAT_MBED_HOSTTEST_TIMEOUT 60 +#define FSFAT_MAX_FILE_BASENAME 8 +#define FSFAT_MAX_FILE_EXTNAME 3 +#define FSFAT_BUF_MAX_LENGTH 64 +#define FSFAT_FILENAME_MAX_LENGTH 255 + + +/* support macro for make string for utest _MESSAGE macros, which dont support formatted output */ +#define FSFAT_TEST_UTEST_MESSAGE(_buf, _max_len, _fmt, ...) \ + do \ + { \ + snprintf((_buf), (_max_len), (_fmt), __VA_ARGS__); \ + }while(0); + + +/* + * Structures + */ + +/* kv data for test */ +typedef struct fsfat_kv_data_t { + const char *filename; + const char *value; +} fsfat_kv_data_t; + + +extern const uint8_t fsfat_test_byte_data_table[FSFAT_TEST_BYTE_DATA_TABLE_SIZE]; + +int32_t fsfat_test_create(const char *filename, const char *data, size_t len); +int32_t fsfat_test_delete(const char *key_name); +int32_t fsfat_test_filename_gen(char *name, const size_t len); +#ifdef __cplusplus +} +#endif + +#endif /* __FSFAT_TEST_H */ From 73b18fcab40941389bb6515db4d78aa623d221cd Mon Sep 17 00:00:00 2001 From: JojoS62 Date: Mon, 12 Nov 2018 17:51:23 +0100 Subject: [PATCH 04/17] add implementation for STM32F7 almost the same as for STM32F4, but in F7 SDIO device is renamed to SDMMC SDMMC1 is used for DISCO_F746NG updated readme.md for new target --- README.md | 5 +- TARGET_STM/TARGET_STM32F7/sdio_device.c | 538 ++++++++++++++++++++++++ TARGET_STM/TARGET_STM32F7/sdio_device.h | 126 ++++++ 3 files changed, 668 insertions(+), 1 deletion(-) create mode 100644 TARGET_STM/TARGET_STM32F7/sdio_device.c create mode 100644 TARGET_STM/TARGET_STM32F7/sdio_device.h diff --git a/README.md b/README.md index c0dde34..0b0ddee 100644 --- a/README.md +++ b/README.md @@ -11,11 +11,14 @@ The software is provided under [Apache-2.0 license](LICENSE). Contributions to t This is an implementation for a blockdevice to use SDHC cards via SDIO interface. ## Supported Hardware -- STM32F4 +- STM32F4 +- STM32F7 ## Tested Hardware - STM Discovery board 32F469IDISCOVERY, Targetname: DISCO_F469NI https://os.mbed.com/platforms/ST-Discovery-F469NI/ +- STM Discovery board 32F746IDISCOVERY, Targetname: DISCO_F746NG + https://os.mbed.com/platforms/ST-Discovery-F746NG/ ## Driver Description diff --git a/TARGET_STM/TARGET_STM32F7/sdio_device.c b/TARGET_STM/TARGET_STM32F7/sdio_device.c new file mode 100644 index 0000000..e9b3fae --- /dev/null +++ b/TARGET_STM/TARGET_STM32F7/sdio_device.c @@ -0,0 +1,538 @@ +/** + * + * 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_sdmmc_rx; +DMA_HandleTypeDef hdma_sdmmc_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 SDMMC global interrupt. +*/ +void _SDMMC_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 == SDMMC1) + { + /* Peripheral clock enable */ + __HAL_RCC_SDMMC1_CLK_ENABLE(); + __HAL_RCC_DMA2_CLK_ENABLE(); + + /* Enable GPIOs clock */ + __HAL_RCC_GPIOC_CLK_ENABLE(); + __HAL_RCC_GPIOD_CLK_ENABLE(); + + /** SDMMC 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_SDMMC1; + 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_SDMMC1; + HAL_GPIO_Init(GPIOD, &GPIO_InitStruct); + + /* NVIC configuration for SDMMC interrupts */ + IRQn = SDMMC1_IRQn; + HAL_NVIC_SetPriority(IRQn, 0x0E, 0); + NVIC_SetVector(IRQn, (uint32_t)&_SDMMC_IRQHandler); + HAL_NVIC_EnableIRQ(IRQn); + + /* SDMMC DMA Init */ + /* SDMMC_RX Init */ + hdma_sdmmc_rx.Instance = DMA2_Stream3; + hdma_sdmmc_rx.Init.Channel = DMA_CHANNEL_4; + hdma_sdmmc_rx.Init.Direction = DMA_PERIPH_TO_MEMORY; + hdma_sdmmc_rx.Init.PeriphInc = DMA_PINC_DISABLE; + hdma_sdmmc_rx.Init.MemInc = DMA_MINC_ENABLE; + hdma_sdmmc_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD; + hdma_sdmmc_rx.Init.MemDataAlignment = DMA_MDATAALIGN_WORD; + hdma_sdmmc_rx.Init.Mode = DMA_PFCTRL; + hdma_sdmmc_rx.Init.Priority = DMA_PRIORITY_LOW; + hdma_sdmmc_rx.Init.FIFOMode = DMA_FIFOMODE_ENABLE; + hdma_sdmmc_rx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; + hdma_sdmmc_rx.Init.MemBurst = DMA_MBURST_INC4; + hdma_sdmmc_rx.Init.PeriphBurst = DMA_PBURST_INC4; + if (HAL_DMA_Init(&hdma_sdmmc_rx) != HAL_OK) + { + error("SDMMC DMA Init error at %d in %s", __FILE__, __LINE__); + } + + __HAL_LINKDMA(hsd, hdmarx, hdma_sdmmc_rx); + + /* Deinitialize the stream for new transfer */ + HAL_DMA_DeInit(&hdma_sdmmc_rx); + + /* Configure the DMA stream */ + HAL_DMA_Init(&hdma_sdmmc_rx); + + /* SDMMC_TX Init */ + hdma_sdmmc_tx.Instance = DMA2_Stream6; + hdma_sdmmc_tx.Init.Channel = DMA_CHANNEL_4; + hdma_sdmmc_tx.Init.Direction = DMA_MEMORY_TO_PERIPH; + hdma_sdmmc_tx.Init.PeriphInc = DMA_PINC_DISABLE; + hdma_sdmmc_tx.Init.MemInc = DMA_MINC_ENABLE; + hdma_sdmmc_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD; + hdma_sdmmc_tx.Init.MemDataAlignment = DMA_MDATAALIGN_WORD; + hdma_sdmmc_tx.Init.Mode = DMA_PFCTRL; + hdma_sdmmc_tx.Init.Priority = DMA_PRIORITY_LOW; + hdma_sdmmc_tx.Init.FIFOMode = DMA_FIFOMODE_ENABLE; + hdma_sdmmc_tx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; + hdma_sdmmc_tx.Init.MemBurst = DMA_MBURST_INC4; + hdma_sdmmc_tx.Init.PeriphBurst = DMA_PBURST_INC4; + if (HAL_DMA_Init(&hdma_sdmmc_tx) != HAL_OK) + { + error("SDMMC DMA Init error at %d in %s", __FILE__, __LINE__); + } + + __HAL_LINKDMA(hsd, hdmatx, hdma_sdmmc_tx); + + /* Deinitialize the stream for new transfer */ + HAL_DMA_DeInit(&hdma_sdmmc_tx); + + /* Configure the DMA stream */ + HAL_DMA_Init(&hdma_sdmmc_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 == SDMMC1) + { + /* Peripheral clock disable */ + __HAL_RCC_SDMMC1_CLK_DISABLE(); + + /** SDSDMMC1 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); + + /* SDMMC1 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 SDMMC interrupts */ + HAL_NVIC_DisableIRQ(SDMMC1_IRQn); + + /* Disable SDMMC clock */ + __HAL_RCC_SDMMC1_CLK_DISABLE(); +} + +/** + * @brief Enables the SD 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 ((SDMMC_GetResponse(hsd->Instance, SDMMC_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 = SDMMC_BUS_WIDE_4B; + SDMMC_Init(hsd->Instance, hsd->Init); + + return HAL_SD_ERROR_NONE; +} + +/** + * @brief Initializes the SD card device. + * @retval SD status + */ +uint8_t SD_Init(void) +{ + uint8_t sd_state = MSD_OK; + + hsd.Instance = SDMMC1; + hsd.Init.ClockEdge = SDMMC_CLOCK_EDGE_RISING; + hsd.Init.ClockBypass = SDMMC_CLOCK_BYPASS_DISABLE; + hsd.Init.ClockPowerSave = SDMMC_CLOCK_POWER_SAVE_DISABLE; + hsd.Init.BusWide = SDMMC_BUS_WIDE_1B; + hsd.Init.HardwareFlowControl = SDMMC_HARDWARE_FLOW_CONTROL_DISABLE; + hsd.Init.ClockDiv = 0; + + /* 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 (SD_WideBus_Enable(&hsd) != 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 = SDMMC1; + + /* HAL SD deinitialization */ + if (HAL_SD_DeInit(&hsd) != HAL_OK) + { + sd_state = MSD_ERROR; + } + + /* Msp SD deinitialization */ + hsd.Instance = SDMMC1; + 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(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; + } +} + +/** + * @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/TARGET_STM/TARGET_STM32F7/sdio_device.h b/TARGET_STM/TARGET_STM32F7/sdio_device.h new file mode 100644 index 0000000..f5af32b --- /dev/null +++ b/TARGET_STM/TARGET_STM32F7/sdio_device.h @@ -0,0 +1,126 @@ +/** + * + * 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 __SDIO_DEVICE_H +#define __SDIO_DEVICE_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "stm32f7xx_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 */ +/** + * @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(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 +} +#endif + +#endif /* __SDIO_DEVICE_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ From 8717513c9a6d86edac7708a1b182d92dbe009daf Mon Sep 17 00:00:00 2001 From: JojoS62 Date: Mon, 12 Nov 2018 17:52:52 +0100 Subject: [PATCH 05/17] changed copyright notice to standard mBed --- TARGET_STM/TARGET_STM32F7/sdio_device.c | 61 +++++------------------ TARGET_STM/TARGET_STM32F7/sdio_device.h | 64 ++++++------------------- 2 files changed, 26 insertions(+), 99 deletions(-) diff --git a/TARGET_STM/TARGET_STM32F7/sdio_device.c b/TARGET_STM/TARGET_STM32F7/sdio_device.c index e9b3fae..29cfb01 100644 --- a/TARGET_STM/TARGET_STM32F7/sdio_device.c +++ b/TARGET_STM/TARGET_STM32F7/sdio_device.c @@ -1,55 +1,20 @@ -/** - * - * 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. +/* mbed Microcontroller Library + * Copyright (c) 2017 ARM Limited * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted, provided that the following conditions are met: + * 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 * - * 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. + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. - * - ****************************************************************************** + * 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 "sdio_device.h" #include "platform/mbed_error.h" @@ -534,5 +499,3 @@ void HAL_SD_TxCpltCallback(SD_HandleTypeDef *hsd) { SD_DMA_WritePendingState = SD_TRANSFER_OK; } - -/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/TARGET_STM/TARGET_STM32F7/sdio_device.h b/TARGET_STM/TARGET_STM32F7/sdio_device.h index f5af32b..db20c95 100644 --- a/TARGET_STM/TARGET_STM32F7/sdio_device.h +++ b/TARGET_STM/TARGET_STM32F7/sdio_device.h @@ -1,55 +1,19 @@ -/** +/* mbed Microcontroller Library + * Copyright (c) 2017 ARM Limited * - * This sourcecode is derived from STMicroelectronics CubeMX generated code. - * It is modified to work with mbed RTOS. + * 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 * - ****************************************************************************** - * @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. - * - ****************************************************************************** - */ + * 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. + */ + /* Define to prevent recursive inclusion -------------------------------------*/ #ifndef __SDIO_DEVICE_H From 2d8e3d1f751fab138793b79c559745f08b2d3c69 Mon Sep 17 00:00:00 2001 From: JojoS62 Date: Mon, 12 Nov 2018 17:58:00 +0100 Subject: [PATCH 06/17] changed copyright to mBed standard --- TARGET_STM/TARGET_STM32F4/sdio_device.c | 61 +++++---------------- TARGET_STM/TARGET_STM32F4/sdio_device.h | 71 ++++++------------------- TARGET_STM/TARGET_STM32F7/sdio_device.h | 2 - 3 files changed, 28 insertions(+), 106 deletions(-) diff --git a/TARGET_STM/TARGET_STM32F4/sdio_device.c b/TARGET_STM/TARGET_STM32F4/sdio_device.c index 6979c71..0e6b9d1 100644 --- a/TARGET_STM/TARGET_STM32F4/sdio_device.c +++ b/TARGET_STM/TARGET_STM32F4/sdio_device.c @@ -1,55 +1,20 @@ -/** - * - * 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. +/* mbed Microcontroller Library + * Copyright (c) 2017 ARM Limited * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted, provided that the following conditions are met: + * 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 * - * 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. + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. - * - ****************************************************************************** + * 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 "sdio_device.h" #include "platform/mbed_error.h" @@ -534,5 +499,3 @@ void HAL_SD_TxCpltCallback(SD_HandleTypeDef *hsd) { SD_DMA_WritePendingState = SD_TRANSFER_OK; } - -/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/TARGET_STM/TARGET_STM32F4/sdio_device.h b/TARGET_STM/TARGET_STM32F4/sdio_device.h index edd20ac..02266d4 100644 --- a/TARGET_STM/TARGET_STM32F4/sdio_device.h +++ b/TARGET_STM/TARGET_STM32F4/sdio_device.h @@ -1,59 +1,22 @@ -/** +/* mbed Microcontroller Library + * Copyright (c) 2017 ARM Limited * - * This sourcecode is derived from STMicroelectronics CubeMX generated code. - * It is modified to work with mbed RTOS. + * 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 * - ****************************************************************************** - * @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. - * - ****************************************************************************** - */ + * 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. + */ /* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef __STM32F4_SD_H -#define __STM32F4_SD_H +#ifndef __SDIO_DEVICE_H +#define __SDIO_DEVICE_H #ifdef __cplusplus extern "C" @@ -121,6 +84,4 @@ extern "C" } #endif -#endif /* __STM32F4_SD_H */ - -/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ +#endif /* __SDIO_DEVICE_H */ diff --git a/TARGET_STM/TARGET_STM32F7/sdio_device.h b/TARGET_STM/TARGET_STM32F7/sdio_device.h index db20c95..7deaa14 100644 --- a/TARGET_STM/TARGET_STM32F7/sdio_device.h +++ b/TARGET_STM/TARGET_STM32F7/sdio_device.h @@ -86,5 +86,3 @@ extern "C" #endif #endif /* __SDIO_DEVICE_H */ - -/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ From 016abcce5ab7108bc06f388c0afebab8b1b2556c Mon Sep 17 00:00:00 2001 From: JojoS62 Date: Fri, 7 Dec 2018 00:52:58 +0100 Subject: [PATCH 07/17] code cleanup - removed comments - renamed short variable names --- SDIOBlockDevice.cpp | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/SDIOBlockDevice.cpp b/SDIOBlockDevice.cpp index 86572bb..2270b42 100644 --- a/SDIOBlockDevice.cpp +++ b/SDIOBlockDevice.cpp @@ -158,9 +158,8 @@ int SDIOBlockDevice::deinit() return status; } -int SDIOBlockDevice::read(void *b, bd_addr_t addr, bd_size_t size) +int SDIOBlockDevice::read(void *buffer, bd_addr_t addr, bd_size_t size) { - //debug_if(SD_DBG, "read Card...\r\n"); lock(); if (isPresent() == false) { @@ -179,7 +178,7 @@ int SDIOBlockDevice::read(void *b, bd_addr_t addr, bd_size_t size) return SD_BLOCK_DEVICE_ERROR_NO_INIT; } - uint32_t *buffer = static_cast(b); + uint32_t *_buffer = static_cast(buffer); // ReadBlocks uses byte unit address // SDHC and SDXC Cards different addressing is handled in ReadBlocks() @@ -194,7 +193,7 @@ int SDIOBlockDevice::read(void *b, bd_addr_t addr, bd_size_t size) } // receive the data : one block/ multiple blocks is handled in ReadBlocks() - int status = SD_ReadBlocks_DMA(buffer, addr, blockCnt); + 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) @@ -227,9 +226,8 @@ 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 *buffer, bd_addr_t addr, bd_size_t size) { - //debug_if(SD_DBG, "program Card...\r\n"); lock(); if (isPresent() == false) @@ -249,9 +247,8 @@ int SDIOBlockDevice::program(const void *b, bd_addr_t addr, bd_size_t size) 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); + uint32_t *_buffer = (uint32_t *)(buffer); // Get block count bd_size_t blockCnt = size / _block_size; @@ -264,7 +261,7 @@ int SDIOBlockDevice::program(const void *b, bd_addr_t addr, bd_size_t size) wait_ms(1); } - int status = SD_WriteBlocks_DMA(buffer, addr, blockCnt); + 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) @@ -369,10 +366,12 @@ bool SDIOBlockDevice::_is_valid_trim(bd_addr_t addr, bd_size_t size) bool SDIOBlockDevice::isPresent(void) { - if (_cardDetect.is_connected()) + if (_cardDetect.is_connected()) { return (_cardDetect.read() == 0); - else + } + else { return true; + } } } // namespace mbed From c03489c8011f13e7040936f45e559dd28d6678ad Mon Sep 17 00:00:00 2001 From: JojoS62 Date: Sun, 16 Dec 2018 14:58:07 +0100 Subject: [PATCH 08/17] fiixed timeout checking tickstart was inside checking loop removed wait_ms() calls added timeout checks for all while loops --- SDIOBlockDevice.cpp | 64 +++++++++++++++++++++++++++++++++------------ 1 file changed, 47 insertions(+), 17 deletions(-) diff --git a/SDIOBlockDevice.cpp b/SDIOBlockDevice.cpp index 2270b42..99b89d8 100644 --- a/SDIOBlockDevice.cpp +++ b/SDIOBlockDevice.cpp @@ -186,10 +186,17 @@ int SDIOBlockDevice::read(void *buffer, bd_addr_t addr, bd_size_t size) addr = addr / _block_size; // make sure card is ready - while (SD_GetCardState() != SD_TRANSFER_OK) { - // wait until SD ready - wait_ms(1); + uint32_t tickstart = HAL_GetTick(); + while (SD_GetCardState() != SD_TRANSFER_OK) + { + // wait until SD ready + if ((HAL_GetTick() - tickstart) >= MBED_CONF_SD_TIMEOUT) + { + unlock(); + return SD_BLOCK_DEVICE_ERROR_READBLOCKS; + } + } } // receive the data : one block/ multiple blocks is handled in ReadBlocks() @@ -199,9 +206,9 @@ int SDIOBlockDevice::read(void *buffer, bd_addr_t addr, bd_size_t size) if (status == MSD_OK) { // wait until DMA finished + uint32_t tickstart = HAL_GetTick(); while (SD_DMA_ReadPending() != SD_TRANSFER_OK) { - uint32_t tickstart = HAL_GetTick(); if ((HAL_GetTick() - tickstart) >= MBED_CONF_SD_TIMEOUT) { unlock(); @@ -209,17 +216,22 @@ int SDIOBlockDevice::read(void *buffer, bd_addr_t addr, bd_size_t size) } } // make sure card is ready + tickstart = HAL_GetTick(); while (SD_GetCardState() != SD_TRANSFER_OK) { // wait until SD ready - wait_ms(10); + if ((HAL_GetTick() - tickstart) >= MBED_CONF_SD_TIMEOUT) + { + unlock(); + return SD_BLOCK_DEVICE_ERROR_READBLOCKS; + } } } 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; + unlock(); + return SD_BLOCK_DEVICE_ERROR_READBLOCKS; } unlock(); @@ -255,10 +267,17 @@ int SDIOBlockDevice::program(const void *buffer, bd_addr_t addr, bd_size_t size) addr = addr / _block_size; // make sure card is ready - while (SD_GetCardState() != SD_TRANSFER_OK) { - // wait until SD ready - wait_ms(1); + uint32_t tickstart = HAL_GetTick(); + while (SD_GetCardState() != SD_TRANSFER_OK) + { + // wait until SD ready + if ((HAL_GetTick() - tickstart) >= MBED_CONF_SD_TIMEOUT) + { + unlock(); + return SD_BLOCK_DEVICE_ERROR_WRITEBLOCKS; + } + } } int status = SD_WriteBlocks_DMA(_buffer, addr, blockCnt); @@ -267,27 +286,32 @@ int SDIOBlockDevice::program(const void *buffer, bd_addr_t addr, bd_size_t size) if (status == MSD_OK) { // wait until DMA finished + uint32_t tickstart = HAL_GetTick(); 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; + return SD_BLOCK_DEVICE_ERROR_WRITEBLOCKS; } } // make sure card is ready + tickstart = HAL_GetTick(); while (SD_GetCardState() != SD_TRANSFER_OK) { // wait until SD ready - wait_ms(1); + if ((HAL_GetTick() - tickstart) >= MBED_CONF_SD_TIMEOUT) + { + unlock(); + return SD_BLOCK_DEVICE_ERROR_WRITEBLOCKS; + } } } 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; + unlock(); + return SD_BLOCK_DEVICE_ERROR_WRITEBLOCKS; } unlock(); @@ -322,14 +346,20 @@ int SDIOBlockDevice::trim(bd_addr_t addr, bd_size_t size) if (status != 0) { debug_if(SD_DBG, "Erase blocks failed! addr: %lld blockCnt: %lld \n", addr, blockCnt); - status = SD_BLOCK_DEVICE_ERROR_ERASEBLOCKS; + unlock(); + return SD_BLOCK_DEVICE_ERROR_ERASEBLOCKS; } else { + uint32_t tickstart = HAL_GetTick(); while (SD_GetCardState() != SD_TRANSFER_OK) { // wait until SD ready - wait_ms(10); + if ((HAL_GetTick() - tickstart) >= MBED_CONF_SD_TIMEOUT) + { + unlock(); + return SD_BLOCK_DEVICE_ERROR_ERASEBLOCKS; + } } } From 06289dd63052ccd405e5ad512085be7485347d7e Mon Sep 17 00:00:00 2001 From: Mathias Brossard Date: Thu, 8 Aug 2019 20:42:09 -0500 Subject: [PATCH 09/17] Fix order order of parameters --- TARGET_STM/TARGET_STM32F4/sdio_device.c | 4 ++-- TARGET_STM/TARGET_STM32F7/sdio_device.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/TARGET_STM/TARGET_STM32F4/sdio_device.c b/TARGET_STM/TARGET_STM32F4/sdio_device.c index 0e6b9d1..eecb893 100644 --- a/TARGET_STM/TARGET_STM32F4/sdio_device.c +++ b/TARGET_STM/TARGET_STM32F4/sdio_device.c @@ -118,7 +118,7 @@ void HAL_SD_MspInit(SD_HandleTypeDef *hsd) 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__); + error("SDIO DMA Init error at %d in %s", __LINE__, __FILE__); } __HAL_LINKDMA(hsd, hdmarx, hdma_sdio_rx); @@ -145,7 +145,7 @@ void HAL_SD_MspInit(SD_HandleTypeDef *hsd) 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__); + error("SDIO DMA Init error at %d in %s", __LINE__, __FILE__); } __HAL_LINKDMA(hsd, hdmatx, hdma_sdio_tx); diff --git a/TARGET_STM/TARGET_STM32F7/sdio_device.c b/TARGET_STM/TARGET_STM32F7/sdio_device.c index 29cfb01..06d515e 100644 --- a/TARGET_STM/TARGET_STM32F7/sdio_device.c +++ b/TARGET_STM/TARGET_STM32F7/sdio_device.c @@ -118,7 +118,7 @@ void HAL_SD_MspInit(SD_HandleTypeDef *hsd) hdma_sdmmc_rx.Init.PeriphBurst = DMA_PBURST_INC4; if (HAL_DMA_Init(&hdma_sdmmc_rx) != HAL_OK) { - error("SDMMC DMA Init error at %d in %s", __FILE__, __LINE__); + error("SDMMC DMA Init error at %d in %s", __LINE__, __FILE__); } __HAL_LINKDMA(hsd, hdmarx, hdma_sdmmc_rx); @@ -145,7 +145,7 @@ void HAL_SD_MspInit(SD_HandleTypeDef *hsd) hdma_sdmmc_tx.Init.PeriphBurst = DMA_PBURST_INC4; if (HAL_DMA_Init(&hdma_sdmmc_tx) != HAL_OK) { - error("SDMMC DMA Init error at %d in %s", __FILE__, __LINE__); + error("SDMMC DMA Init error at %d in %s", __LINE__, __FILE__); } __HAL_LINKDMA(hsd, hdmatx, hdma_sdmmc_tx); From e2ade7639ac6b2bf22c0f0d27bc6c9b1c230e94c Mon Sep 17 00:00:00 2001 From: JojoS62 Date: Thu, 19 Dec 2019 17:27:17 +0100 Subject: [PATCH 10/17] added get_type() function --- SDIOBlockDevice.cpp | 5 +++++ SDIOBlockDevice.h | 7 +++++++ 2 files changed, 12 insertions(+) diff --git a/SDIOBlockDevice.cpp b/SDIOBlockDevice.cpp index 99b89d8..cee4db6 100644 --- a/SDIOBlockDevice.cpp +++ b/SDIOBlockDevice.cpp @@ -404,4 +404,9 @@ bool SDIOBlockDevice::isPresent(void) } } +const char *SDIOBlockDevice::get_type() const +{ + return "SDIO"; +} + } // namespace mbed diff --git a/SDIOBlockDevice.h b/SDIOBlockDevice.h index 9840833..836ba28 100644 --- a/SDIOBlockDevice.h +++ b/SDIOBlockDevice.h @@ -114,6 +114,13 @@ class SDIOBlockDevice : public BlockDevice */ virtual bool isPresent(void); + /** Get the BlockDevice class type. + * + * @return A string representation of the BlockDevice class type. + */ + virtual const char *get_type() const; + + private: DigitalIn _cardDetect; bool _is_initialized; From f1b70f2d0a6f6ee23705a9b4c8a3e988fde73456 Mon Sep 17 00:00:00 2001 From: JojoS62 Date: Thu, 19 Dec 2019 17:35:24 +0100 Subject: [PATCH 11/17] fixed printf warning --- SDIOBlockDevice.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SDIOBlockDevice.cpp b/SDIOBlockDevice.cpp index cee4db6..33e4ba6 100644 --- a/SDIOBlockDevice.cpp +++ b/SDIOBlockDevice.cpp @@ -112,9 +112,9 @@ int SDIOBlockDevice::init() SD_GetCardInfo(&_cardInfo); _is_initialized = true; - debug_if(SD_DBG, "SD initialized: type: %d version: %d class: %d\n", + debug_if(SD_DBG, "SD initialized: type: %ld version: %ld class: %ld\n", _cardInfo.CardType, _cardInfo.CardVersion, _cardInfo.Class); - debug_if(SD_DBG, "SD size: %d MB\n", + debug_if(SD_DBG, "SD size: %ld MB\n", _cardInfo.LogBlockNbr / 2 / 1024); // get sectors count from cardinfo From 55d15574d99f7628ca0ef471a296d099a239d546 Mon Sep 17 00:00:00 2001 From: JojoS62 Date: Sun, 16 Aug 2020 12:51:06 +0200 Subject: [PATCH 12/17] remove path from include mbed file structure has changed again --- SDIOBlockDevice.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/SDIOBlockDevice.h b/SDIOBlockDevice.h index 836ba28..86dea74 100644 --- a/SDIOBlockDevice.h +++ b/SDIOBlockDevice.h @@ -18,9 +18,9 @@ #define MBED_OS_FEATURES_STORAGE_BLOCKDEVICE_SDIOBLOCKDEVICE_H_ -#include "features/storage/blockdevice/BlockDevice.h" -#include "drivers/DigitalIn.h" -#include "platform/PlatformMutex.h" +#include "BlockDevice.h" +#include "DigitalIn.h" +#include "PlatformMutex.h" #include "sdio_device.h" namespace mbed From 4985bb9c887001f63d7b511aca6028b8681796b9 Mon Sep 17 00:00:00 2001 From: Johannes Stratmann Date: Mon, 17 May 2021 17:19:26 +0200 Subject: [PATCH 13/17] add SDMM2 for F7 with 2 infterfaces --- TARGET_STM/TARGET_STM32F7/sdio_device.c | 214 ++++++++++++++++++++---- 1 file changed, 185 insertions(+), 29 deletions(-) diff --git a/TARGET_STM/TARGET_STM32F7/sdio_device.c b/TARGET_STM/TARGET_STM32F7/sdio_device.c index 06d515e..262d0d0 100644 --- a/TARGET_STM/TARGET_STM32F7/sdio_device.c +++ b/TARGET_STM/TARGET_STM32F7/sdio_device.c @@ -61,7 +61,7 @@ void _DMA_Stream_Tx_IRQHandler(void) void HAL_SD_MspInit(SD_HandleTypeDef *hsd) { IRQn_Type IRQn; - GPIO_InitTypeDef GPIO_InitStruct; + GPIO_InitTypeDef GPIO_InitStruct = {0}; if (hsd->Instance == SDMMC1) { @@ -116,8 +116,7 @@ void HAL_SD_MspInit(SD_HandleTypeDef *hsd) hdma_sdmmc_rx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; hdma_sdmmc_rx.Init.MemBurst = DMA_MBURST_INC4; hdma_sdmmc_rx.Init.PeriphBurst = DMA_PBURST_INC4; - if (HAL_DMA_Init(&hdma_sdmmc_rx) != HAL_OK) - { + if (HAL_DMA_Init(&hdma_sdmmc_rx) != HAL_OK) { error("SDMMC DMA Init error at %d in %s", __LINE__, __FILE__); } @@ -143,8 +142,7 @@ void HAL_SD_MspInit(SD_HandleTypeDef *hsd) hdma_sdmmc_tx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; hdma_sdmmc_tx.Init.MemBurst = DMA_MBURST_INC4; hdma_sdmmc_tx.Init.PeriphBurst = DMA_PBURST_INC4; - if (HAL_DMA_Init(&hdma_sdmmc_tx) != HAL_OK) - { + if (HAL_DMA_Init(&hdma_sdmmc_tx) != HAL_OK) { error("SDMMC DMA Init error at %d in %s", __LINE__, __FILE__); } @@ -159,14 +157,130 @@ 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); - HAL_NVIC_SetPriority(IRQn, 0x0F, 0); + HAL_NVIC_SetPriority(IRQn, 0x0, 0); HAL_NVIC_EnableIRQ(IRQn); IRQn = DMA2_Stream6_IRQn; NVIC_SetVector(IRQn, (uint32_t)&_DMA_Stream_Tx_IRQHandler); + HAL_NVIC_SetPriority(IRQn, 0x0, 0); + HAL_NVIC_EnableIRQ(IRQn); + } + +#ifdef SDMMC2 + if(hsd->Instance==SDMMC2) { + // set clock source for SDMMC2 to CLK48 + RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0}; + PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_SDMMC2; + PeriphClkInitStruct.Sdmmc2ClockSelection = RCC_SDMMC2CLKSOURCE_CLK48; + [[maybe_unused]] volatile int err = HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct); + + /* Peripheral clock enable */ + __HAL_RCC_SDMMC2_CLK_ENABLE(); + __HAL_RCC_DMA2_CLK_ENABLE(); + + __HAL_RCC_GPIOB_CLK_ENABLE(); + __HAL_RCC_GPIOD_CLK_ENABLE(); + __HAL_RCC_GPIOG_CLK_ENABLE(); + /**SDMMC2 GPIO Configuration + PB4 ------> SDMMC2_D3 + PB3 ------> SDMMC2_D2 + PD7 ------> SDMMC2_CMD + PD6 ------> SDMMC2_CK + PG10 ------> SDMMC2_D1 + PG9 ------> SDMMC2_D0 + */ + GPIO_InitStruct.Pin = GPIO_PIN_4|GPIO_PIN_3; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + GPIO_InitStruct.Alternate = GPIO_AF10_SDMMC2; + HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); + + GPIO_InitStruct.Pin = GPIO_PIN_7|GPIO_PIN_6; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + GPIO_InitStruct.Alternate = GPIO_AF11_SDMMC2; + HAL_GPIO_Init(GPIOD, &GPIO_InitStruct); + + GPIO_InitStruct.Pin = GPIO_PIN_9|GPIO_PIN_10; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + GPIO_InitStruct.Alternate = GPIO_AF11_SDMMC2; + HAL_GPIO_Init(GPIOG, &GPIO_InitStruct); + + /* NVIC configuration for SDMMC interrupts */ + IRQn = SDMMC2_IRQn; + HAL_NVIC_SetPriority(IRQn, 0x0, 0); + NVIC_SetVector(IRQn, (uint32_t)&_SDMMC_IRQHandler); + HAL_NVIC_EnableIRQ(IRQn); + + /* SDMMC DMA Init */ + /* SDMMC_RX Init */ + hdma_sdmmc_rx.Instance = DMA2_Stream0; + hdma_sdmmc_rx.Init.Channel = DMA_CHANNEL_11; + hdma_sdmmc_rx.Init.Direction = DMA_PERIPH_TO_MEMORY; + hdma_sdmmc_rx.Init.PeriphInc = DMA_PINC_DISABLE; + hdma_sdmmc_rx.Init.MemInc = DMA_MINC_ENABLE; + hdma_sdmmc_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD; + hdma_sdmmc_rx.Init.MemDataAlignment = DMA_MDATAALIGN_WORD; + hdma_sdmmc_rx.Init.Mode = DMA_PFCTRL; + hdma_sdmmc_rx.Init.Priority = DMA_PRIORITY_LOW; + hdma_sdmmc_rx.Init.FIFOMode = DMA_FIFOMODE_ENABLE; + hdma_sdmmc_rx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; + hdma_sdmmc_rx.Init.MemBurst = DMA_MBURST_INC4; + hdma_sdmmc_rx.Init.PeriphBurst = DMA_PBURST_INC4; + if (HAL_DMA_Init(&hdma_sdmmc_rx) != HAL_OK) { + error("SDMMC DMA Init error at %d in %s", __LINE__, __FILE__); + } + + __HAL_LINKDMA(hsd, hdmarx, hdma_sdmmc_rx); + + /* Deinitialize the stream for new transfer */ + HAL_DMA_DeInit(&hdma_sdmmc_rx); + + /* Configure the DMA stream */ + HAL_DMA_Init(&hdma_sdmmc_rx); + + /* SDMMC_TX Init */ + hdma_sdmmc_tx.Instance = DMA2_Stream5; + hdma_sdmmc_tx.Init.Channel = DMA_CHANNEL_11; + hdma_sdmmc_tx.Init.Direction = DMA_MEMORY_TO_PERIPH; + hdma_sdmmc_tx.Init.PeriphInc = DMA_PINC_DISABLE; + hdma_sdmmc_tx.Init.MemInc = DMA_MINC_ENABLE; + hdma_sdmmc_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD; + hdma_sdmmc_tx.Init.MemDataAlignment = DMA_MDATAALIGN_WORD; + hdma_sdmmc_tx.Init.Mode = DMA_PFCTRL; + hdma_sdmmc_tx.Init.Priority = DMA_PRIORITY_LOW; + hdma_sdmmc_tx.Init.FIFOMode = DMA_FIFOMODE_ENABLE; + hdma_sdmmc_tx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; + hdma_sdmmc_tx.Init.MemBurst = DMA_MBURST_INC4; + hdma_sdmmc_tx.Init.PeriphBurst = DMA_PBURST_INC4; + if (HAL_DMA_Init(&hdma_sdmmc_tx) != HAL_OK) { + error("SDMMC DMA Init error at %d in %s", __LINE__, __FILE__); + } + + __HAL_LINKDMA(hsd, hdmatx, hdma_sdmmc_tx); + + /* Deinitialize the stream for new transfer */ + HAL_DMA_DeInit(&hdma_sdmmc_tx); + + /* Configure the DMA stream */ + HAL_DMA_Init(&hdma_sdmmc_tx); + + /* Enable NVIC for DMA transfer complete interrupts */ + IRQn = DMA2_Stream0_IRQn; + NVIC_SetVector(IRQn, (uint32_t)&_DMA_Stream_Rx_IRQHandler); + HAL_NVIC_SetPriority(IRQn, 0x0F, 0); + HAL_NVIC_EnableIRQ(IRQn); + + IRQn = DMA2_Stream5_IRQn; + NVIC_SetVector(IRQn, (uint32_t)&_DMA_Stream_Tx_IRQHandler); HAL_NVIC_SetPriority(IRQn, 0x0F, 0); HAL_NVIC_EnableIRQ(IRQn); } +#endif } /** @@ -175,9 +289,7 @@ void HAL_SD_MspInit(SD_HandleTypeDef *hsd) */ void HAL_SD_MspDeInit(SD_HandleTypeDef *hsd) { - - if (hsd->Instance == SDMMC1) - { + if (hsd->Instance == SDMMC1) { /* Peripheral clock disable */ __HAL_RCC_SDMMC1_CLK_DISABLE(); @@ -190,13 +302,31 @@ void HAL_SD_MspDeInit(SD_HandleTypeDef *hsd) 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); + } - /* SDMMC1 DMA DeInit */ - HAL_DMA_DeInit(hsd->hdmarx); - HAL_DMA_DeInit(hsd->hdmatx); +#ifdef SDMMC2 + if (hsd->Instance == SDMMC2) { + /* Peripheral clock disable */ + __HAL_RCC_SDMMC2_CLK_DISABLE(); + + /**SDMMC2 GPIO Configuration + PB4 ------> SDMMC2_D3 + PB3 ------> SDMMC2_D2 + PD7 ------> SDMMC2_CMD + PD6 ------> SDMMC2_CK + PG10 ------> SDMMC2_D1 + PG9 ------> SDMMC2_D0 + */ + HAL_GPIO_DeInit(GPIOB, GPIO_PIN_4|GPIO_PIN_3); + HAL_GPIO_DeInit(GPIOD, GPIO_PIN_7|GPIO_PIN_6); + HAL_GPIO_DeInit(GPIOG, GPIO_PIN_9|GPIO_PIN_10); } +#endif + + /* SDMMC DMA DeInit */ + HAL_DMA_DeInit(hsd->hdmarx); + HAL_DMA_DeInit(hsd->hdmatx); } /** @@ -209,25 +339,50 @@ __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); + if (hsd->Instance == SDMMC1) { + /* 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 SDMMC interrupts */ + HAL_NVIC_DisableIRQ(SDMMC1_IRQn); + + /* Disable SDMMC clock */ + __HAL_RCC_SDMMC1_CLK_DISABLE(); + } + +#ifdef SDMMC2 + if (hsd->Instance == SDMMC2) { + /* Disable NVIC for DMA transfer complete interrupts */ + HAL_NVIC_DisableIRQ(DMA2_Stream0_IRQn); + HAL_NVIC_DisableIRQ(DMA2_Stream5_IRQn); - /* Deinitialize the stream for new transfer */ - dma_tx_handle.Instance = DMA2_Stream6; - HAL_DMA_DeInit(&dma_tx_handle); + /* Deinitialize the stream for new transfer */ + dma_rx_handle.Instance = DMA2_Stream0; + HAL_DMA_DeInit(&dma_rx_handle); - /* Disable NVIC for SDMMC interrupts */ - HAL_NVIC_DisableIRQ(SDMMC1_IRQn); + /* Deinitialize the stream for new transfer */ + dma_tx_handle.Instance = DMA2_Stream5; + HAL_DMA_DeInit(&dma_tx_handle); + /* Disable NVIC for SDMMC interrupts */ + HAL_NVIC_DisableIRQ(SDMMC2_IRQn); - /* Disable SDMMC clock */ - __HAL_RCC_SDMMC1_CLK_DISABLE(); + /* Disable SDMMC clock */ + __HAL_RCC_SDMMC2_CLK_DISABLE(); + } +#endif } + /** * @brief Enables the SD wide bus mode. * @param hsd pointer to SD handle @@ -270,7 +425,11 @@ uint8_t SD_Init(void) { uint8_t sd_state = MSD_OK; +#ifdef TARGET_DISCO_F769NI + hsd.Instance = SDMMC2; +#else hsd.Instance = SDMMC1; +#endif hsd.Init.ClockEdge = SDMMC_CLOCK_EDGE_RISING; hsd.Init.ClockBypass = SDMMC_CLOCK_BYPASS_DISABLE; hsd.Init.ClockPowerSave = SDMMC_CLOCK_POWER_SAVE_DISABLE; @@ -301,8 +460,6 @@ uint8_t SD_DeInit(void) { uint8_t sd_state = MSD_OK; - hsd.Instance = SDMMC1; - /* HAL SD deinitialization */ if (HAL_SD_DeInit(&hsd) != HAL_OK) { @@ -310,7 +467,6 @@ uint8_t SD_DeInit(void) } /* Msp SD deinitialization */ - hsd.Instance = SDMMC1; SD_MspDeInit(&hsd, NULL); return sd_state; From dd0c09c90b0f2afc630dd6d61253933f922bdb9f Mon Sep 17 00:00:00 2001 From: Johannes Stratmann Date: Mon, 31 Oct 2022 19:22:12 +0100 Subject: [PATCH 14/17] update for mbed-os 6 --- CMakeLists.txt | 27 +++++++++++++++++++++++++++ SDIOBlockDevice.h | 4 ++-- 2 files changed, 29 insertions(+), 2 deletions(-) create mode 100644 CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..2ba0840 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,27 @@ +add_library(component_sdio INTERFACE) + +target_include_directories(component_sdio INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) + +list(APPEND SOURCEFILES + SDIOBlockDevice.cpp +) + +if("STM32F4" IN_LIST MBED_TARGET_LABELS) + target_include_directories(component_sdio INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/TARGET_STM/TARGET_STM32F4) + list(APPEND SOURCEFILES + TARGET_STM/TARGET_STM32F4/sdio_device.c + ) +endif() + +if("STM32F7" IN_LIST MBED_TARGET_LABELS) + target_include_directories(component_sdio INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/TARGET_STM/TARGET_STM32F7) + list(APPEND SOURCEFILES + TARGET_STM/TARGET_STM32F7/sdio_device.c + ) +endif() + + +target_sources(component_sdio + INTERFACE + ${SOURCEFILES} +) diff --git a/SDIOBlockDevice.h b/SDIOBlockDevice.h index 86dea74..3c4fd3f 100644 --- a/SDIOBlockDevice.h +++ b/SDIOBlockDevice.h @@ -20,7 +20,7 @@ #include "BlockDevice.h" #include "DigitalIn.h" -#include "PlatformMutex.h" +#include "rtos/Mutex.h" #include "sdio_device.h" namespace mbed @@ -131,7 +131,7 @@ class SDIOBlockDevice : public BlockDevice SD_Cardinfo_t _cardInfo; uint32_t _card_type; - PlatformMutex _mutex; + mutable rtos::Mutex _mutex; virtual void lock() { _mutex.lock(); From a61242ca2a03de4a25f9b4c5e1cceee3559cea2d Mon Sep 17 00:00:00 2001 From: Johannes Stratmann Date: Tue, 21 Nov 2023 19:52:47 +0100 Subject: [PATCH 15/17] add H7 --- CMakeLists.txt | 7 + TARGET_STM/TARGET_STM32H7/sdio_device.c | 393 ++++++++++++++++++++++++ TARGET_STM/TARGET_STM32H7/sdio_device.h | 83 +++++ 3 files changed, 483 insertions(+) create mode 100644 TARGET_STM/TARGET_STM32H7/sdio_device.c create mode 100644 TARGET_STM/TARGET_STM32H7/sdio_device.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 2ba0840..f2d9421 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,6 +20,13 @@ if("STM32F7" IN_LIST MBED_TARGET_LABELS) ) endif() +if("STM32H7" IN_LIST MBED_TARGET_LABELS) + target_include_directories(component_sdio INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/TARGET_STM/TARGET_STM32H7) + list(APPEND SOURCEFILES + TARGET_STM/TARGET_STM32H7/sdio_device.c + ) +endif() + target_sources(component_sdio INTERFACE diff --git a/TARGET_STM/TARGET_STM32H7/sdio_device.c b/TARGET_STM/TARGET_STM32H7/sdio_device.c new file mode 100644 index 0000000..db6063e --- /dev/null +++ b/TARGET_STM/TARGET_STM32H7/sdio_device.c @@ -0,0 +1,393 @@ +/* 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 "sdio_device.h" +#include "platform/mbed_error.h" + +/* Extern variables ---------------------------------------------------------*/ + +SD_HandleTypeDef hsd; + +// simple flags for DMA pending signaling +volatile uint8_t SD_DMA_ReadPendingState = SD_TRANSFER_OK; +volatile uint8_t SD_DMA_WritePendingState = SD_TRANSFER_OK; + +static void _SDMMC1_IRQHandler(void) +{ + HAL_SD_IRQHandler(&hsd); +} + + +/** + * + * @param hsd: Handle for SD handle Structure definition + */ +void HAL_SD_MspInit(SD_HandleTypeDef *hsd) +{ + IRQn_Type IRQn; + GPIO_InitTypeDef GPIO_InitStruct = {0}; + RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0}; + + if (hsd->Instance == SDMMC1) + { + PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_SDMMC; + PeriphClkInitStruct.PLL2.PLL2M = 5; // 25 MHz / 5 = 5 MHz + PeriphClkInitStruct.PLL2.PLL2N = 160; // 5 MHz * 160 = 800 MHz (140: 700 MHz, 120: 600 MHz) + PeriphClkInitStruct.PLL2.PLL2P = 4; + PeriphClkInitStruct.PLL2.PLL2Q = 8; + PeriphClkInitStruct.PLL2.PLL2R = 4; // 64: 12.5 MHz 32: 25 MHz 16: 50 MHz 8: 100 MHz 4: 200 MHz + PeriphClkInitStruct.PLL2.PLL2RGE = RCC_PLL2VCIRANGE_2; + PeriphClkInitStruct.PLL2.PLL2VCOSEL = RCC_PLL2VCOWIDE; + PeriphClkInitStruct.PLL2.PLL2FRACN = 0; + PeriphClkInitStruct.SdmmcClockSelection = RCC_SDMMCCLKSOURCE_PLL2; + if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK) + { + error("SDMMC clock Init error at %d in %s", __LINE__, __FILE__); + } + + /* Peripheral clock enable */ + __HAL_RCC_SDMMC1_CLK_ENABLE(); + + __HAL_RCC_GPIOC_CLK_ENABLE(); + __HAL_RCC_GPIOD_CLK_ENABLE(); + /**SDMMC1 GPIO Configuration + PC8 ------> SDMMC1_D0 + PC9 ------> SDMMC1_D1 + PC10 ------> SDMMC1_D2 + PC11 ------> SDMMC1_D3 + PC12 ------> SDMMC1_CK + PD2 ------> SDMMC1_CMD + */ + GPIO_InitStruct.Pin = GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + GPIO_InitStruct.Alternate = GPIO_AF12_SDIO1; + HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); + + GPIO_InitStruct.Pin = GPIO_PIN_2; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + GPIO_InitStruct.Alternate = GPIO_AF12_SDIO1; + HAL_GPIO_Init(GPIOD, &GPIO_InitStruct); + + // SDMMC1 interrupt Init + IRQn = SDMMC1_IRQn; + HAL_NVIC_SetPriority(IRQn, 0, 0); // 0: highest prio, 15 lowest + NVIC_SetVector(IRQn, (uint32_t)&_SDMMC1_IRQHandler); + HAL_NVIC_EnableIRQ(IRQn); + } + +} + +/** + * + * @param hsd: Handle for SD handle Structure definition + */ +void HAL_SD_MspDeInit(SD_HandleTypeDef *hsd) +{ + if (hsd->Instance == SDMMC1) { + __HAL_RCC_SDMMC1_CLK_DISABLE(); + + /**SDMMC1 GPIO Configuration + PC8 ------> SDMMC1_D0 + PC9 ------> SDMMC1_D1 + PC10 ------> SDMMC1_D2 + PC11 ------> SDMMC1_D3 + PC12 ------> SDMMC1_CK + PD2 ------> SDMMC1_CMD + */ + HAL_GPIO_DeInit(GPIOC, GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11 + |GPIO_PIN_12); + + HAL_GPIO_DeInit(GPIOD, GPIO_PIN_2); + } +} + +/** + * @brief DeInitializes the SD MSP. + * @param hsd: SD handle + * @param Params : pointer on additional configuration parameters, can be NULL. + */ +void SD_MspDeInit(SD_HandleTypeDef *hsd, void *Params) +{ + +#if 0 + if (hsd->Instance == SDMMC2) { + } +#endif +} + + + +/** + * @brief Initializes the SD card device. + * @retval SD status + */ +uint8_t SD_Init(void) +{ + uint8_t sd_state = MSD_OK; + + hsd.Instance = SDMMC1; + hsd.Init.ClockEdge = SDMMC_CLOCK_EDGE_RISING; + hsd.Init.ClockPowerSave = SDMMC_CLOCK_POWER_SAVE_ENABLE; + hsd.Init.BusWide = SDMMC_BUS_WIDE_4B; + hsd.Init.HardwareFlowControl = SDMMC_HARDWARE_FLOW_CONTROL_ENABLE; + hsd.Init.ClockDiv = 2; // SDMMC kernel clock / (2 * 2) = 50 MHz + + /* HAL SD initialization */ + sd_state = HAL_SD_Init(&hsd); + + sd_state = HAL_SD_ConfigSpeedBusOperation(&hsd, SDMMC_SPEED_MODE_AUTO); + + + return sd_state; +} + +/** + * @brief DeInitializes the SD card device. + * @retval SD status + */ +uint8_t SD_DeInit(void) +{ + uint8_t sd_state = MSD_OK; + + /* HAL SD deinitialization */ + if (HAL_SD_DeInit(&hsd) != HAL_OK) + { + sd_state = MSD_ERROR; + } + + /* Msp SD deinitialization */ + 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; + + if ((uint32_t)pData & 3) { + __BKPT(0); + } + + /* + the SCB_InvalidateDCache_by_Addr() requires a 32-Byte aligned address, + adjust the address and the D-Cache size to invalidate accordingly. + */ + uint32_t alignedAddr = (uint32_t)pData & ~0x1F; + SCB_InvalidateDCache_by_Addr((uint32_t*)alignedAddr, NumOfBlocks*BLOCKSIZE + ((uint32_t)pData - alignedAddr)); + + /* 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) +{ + // Ensure the data is flushed to main memory + SCB_CleanDCache_by_Addr(pData, NumOfBlocks * 512); // Todo: use real blocksize + + 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(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; + } +} + +/** + * @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; +} + +/** + * @brief SD Abort callbacks + * @param hsd: SD handle + * @retval None + */ +void HAL_SD_AbortCallback(SD_HandleTypeDef *hsd) +{ + //BSP_SD_AbortCallback(); +} + +void HAL_SD_ErrorCallback(SD_HandleTypeDef *hsd) +{ + printf("SD_Error: 0x%x\n", hsd->ErrorCode); +} \ No newline at end of file diff --git a/TARGET_STM/TARGET_STM32H7/sdio_device.h b/TARGET_STM/TARGET_STM32H7/sdio_device.h new file mode 100644 index 0000000..b927e02 --- /dev/null +++ b/TARGET_STM/TARGET_STM32H7/sdio_device.h @@ -0,0 +1,83 @@ +/* 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. + */ + + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __SDIO_DEVICE_H +#define __SDIO_DEVICE_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "stm32h7xx_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 */ +/** + * @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(SD_Cardinfo_t *CardInfo); +#ifdef __cplusplus +} +#endif + +#endif /* __SDIO_DEVICE_H */ From d132129c9ac79fc9e0771aa25a8cbf2f1b33ded1 Mon Sep 17 00:00:00 2001 From: Johannes Stratmann Date: Sun, 18 Feb 2024 20:11:23 +0100 Subject: [PATCH 16/17] change lib type to static --- CMakeLists.txt | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f2d9421..44fe1d3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,34 +1,40 @@ -add_library(component_sdio INTERFACE) -target_include_directories(component_sdio INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) +add_library(mbed-storage-sdio STATIC) list(APPEND SOURCEFILES SDIOBlockDevice.cpp ) +target_include_directories(mbed-storage-sdio INTERFACE .) + if("STM32F4" IN_LIST MBED_TARGET_LABELS) - target_include_directories(component_sdio INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/TARGET_STM/TARGET_STM32F4) + target_include_directories(mbed-storage-sdio PUBLIC ./TARGET_STM/TARGET_STM32F4) list(APPEND SOURCEFILES TARGET_STM/TARGET_STM32F4/sdio_device.c ) endif() if("STM32F7" IN_LIST MBED_TARGET_LABELS) - target_include_directories(component_sdio INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/TARGET_STM/TARGET_STM32F7) + target_include_directories(mbed-storage-sdio PUBLIC ./TARGET_STM/TARGET_STM32F7) list(APPEND SOURCEFILES TARGET_STM/TARGET_STM32F7/sdio_device.c ) endif() if("STM32H7" IN_LIST MBED_TARGET_LABELS) - target_include_directories(component_sdio INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/TARGET_STM/TARGET_STM32H7) + target_include_directories(mbed-storage-sdio PUBLIC ./TARGET_STM/TARGET_STM32H7) list(APPEND SOURCEFILES TARGET_STM/TARGET_STM32H7/sdio_device.c ) endif() +target_link_libraries(mbed-storage-sdio + PUBLIC + mbed-rtos-flags + mbed-storage-blockdevice + ) -target_sources(component_sdio - INTERFACE +target_sources(mbed-storage-sdio + PRIVATE ${SOURCEFILES} -) + ) From e4ea1df9196550687f966c07ecd7fe8d0c7b79f3 Mon Sep 17 00:00:00 2001 From: Johannes Stratmann Date: Sat, 2 Mar 2024 20:56:39 +0100 Subject: [PATCH 17/17] add sleep in wait for data Todo: use event_flags --- SDIOBlockDevice.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/SDIOBlockDevice.cpp b/SDIOBlockDevice.cpp index 33e4ba6..7b05936 100644 --- a/SDIOBlockDevice.cpp +++ b/SDIOBlockDevice.cpp @@ -14,6 +14,7 @@ * limitations under the License. */ +#include "mbed.h" #include #include "platform/mbed_debug.h" #include "platform/mbed_wait_api.h" @@ -58,6 +59,8 @@ namespace mbed #define MBED_CONF_SD_TIMEOUT (30 * 1000) /* ms */ #endif +constexpr auto delayTime = 2ms; + SDIOBlockDevice::SDIOBlockDevice(PinName cardDetect) : _cardDetect(cardDetect), _is_initialized(0), _sectors(0), @@ -196,6 +199,7 @@ int SDIOBlockDevice::read(void *buffer, bd_addr_t addr, bd_size_t size) unlock(); return SD_BLOCK_DEVICE_ERROR_READBLOCKS; } + ThisThread::sleep_for(delayTime); } } @@ -214,6 +218,7 @@ int SDIOBlockDevice::read(void *buffer, bd_addr_t addr, bd_size_t size) unlock(); return SD_BLOCK_DEVICE_ERROR_READBLOCKS; } + ThisThread::sleep_for(delayTime); } // make sure card is ready tickstart = HAL_GetTick(); @@ -225,6 +230,7 @@ int SDIOBlockDevice::read(void *buffer, bd_addr_t addr, bd_size_t size) unlock(); return SD_BLOCK_DEVICE_ERROR_READBLOCKS; } + ThisThread::sleep_for(delayTime); } } else