Add 'components/storage/blockdevice/COMPONENT_SD/' from commit 'd791229918b261ae8a5ea0cbc5cac1238d65179b'

git-subtree-dir: components/storage/blockdevice/COMPONENT_SD
git-subtree-mainline: 2e081dc7d0
git-subtree-split: d791229918
pull/7774/head
Yossi Levy 2018-08-29 11:47:01 +03:00
commit 90866170ea
17 changed files with 6858 additions and 0 deletions

View File

@ -0,0 +1,24 @@
script:
# Check that examples compile
- sed -n '/``` cpp/,${/```$/q;/```/d;p}' README.md > main.cpp &&
PYTHONPATH=mbed-os python mbed-os/tools/make.py -t GCC_ARM -m K64F
--source=. --build=BUILD/K64F/GCC_ARM -j0 &&
rm main.cpp
# Check that tests compile
- rm -rf BUILD && PYTHONPATH=mbed-os python mbed-os/tools/test.py
-t GCC_ARM -m K64F --source=. --build=BUILD/TESTS/K64F/GCC_ARM -j0
-n tests*
python:
- "2.7"
install:
# Get arm-none-eabi-gcc
- sudo add-apt-repository -y ppa:terry.guo/gcc-arm-embedded
- sudo apt-get update -qq
- sudo apt-get install -qq gcc-arm-none-eabi --force-yes
# Get dependencies
- git clone https://github.com/armmbed/mbed-os.git
# Install python dependencies
- pip install --user -r mbed-os/requirements.txt

View File

@ -0,0 +1,165 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction, and
distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by the copyright
owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all other entities
that control, are controlled by, or are under common control with that entity.
For the purposes of this definition, "control" means (i) the power, direct or
indirect, to cause the direction or management of such entity, whether by
contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity exercising
permissions granted by this License.
"Source" form shall mean the preferred form for making modifications, including
but not limited to software source code, documentation source, and configuration
files.
"Object" form shall mean any form resulting from mechanical transformation or
translation of a Source form, including but not limited to compiled object code,
generated documentation, and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or Object form, made
available under the License, as indicated by a copyright notice that is included
in or attached to the work (an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object form, that
is based on (or derived from) the Work and for which the editorial revisions,
annotations, elaborations, or other modifications represent, as a whole, an
original work of authorship. For the purposes of this License, Derivative Works
shall not include works that remain separable from, or merely link (or bind by
name) to the interfaces of, the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including the original version
of the Work and any modifications or additions to that Work or Derivative Works
thereof, that is intentionally submitted to Licensor for inclusion in the Work
by the copyright owner or by an individual or Legal Entity authorized to submit
on behalf of the copyright owner. For the purposes of this definition,
"submitted" means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems, and
issue tracking systems that are managed by, or on behalf of, the Licensor for
the purpose of discussing and improving the Work, but excluding communication
that is conspicuously marked or otherwise designated in writing by the copyright
owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity on behalf
of whom a Contribution has been received by Licensor and subsequently
incorporated within the Work.
2. Grant of Copyright License.
Subject to the terms and conditions of this License, each Contributor hereby
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
irrevocable copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the Work and such
Derivative Works in Source or Object form.
3. Grant of Patent License.
Subject to the terms and conditions of this License, each Contributor hereby
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
irrevocable (except as stated in this section) patent license to make, have
made, use, offer to sell, sell, import, and otherwise transfer the Work, where
such license applies only to those patent claims licensable by such Contributor
that are necessarily infringed by their Contribution(s) alone or by combination
of their Contribution(s) with the Work to which such Contribution(s) was
submitted. If You institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work or a
Contribution incorporated within the Work constitutes direct or contributory
patent infringement, then any patent licenses granted to You under this License
for that Work shall terminate as of the date such litigation is filed.
4. Redistribution.
You may reproduce and distribute copies of the Work or Derivative Works thereof
in any medium, with or without modifications, and in Source or Object form,
provided that You meet the following conditions:
You must give any other recipients of the Work or Derivative Works a copy of
this License; and
You must cause any modified files to carry prominent notices stating that You
changed the files; and
You must retain, in the Source form of any Derivative Works that You distribute,
all copyright, patent, trademark, and attribution notices from the Source form
of the Work, excluding those notices that do not pertain to any part of the
Derivative Works; and
If the Work includes a "NOTICE" text file as part of its distribution, then any
Derivative Works that You distribute must include a readable copy of the
attribution notices contained within such NOTICE file, excluding those notices
that do not pertain to any part of the Derivative Works, in at least one of the
following places: within a NOTICE text file distributed as part of the
Derivative Works; within the Source form or documentation, if provided along
with the Derivative Works; or, within a display generated by the Derivative
Works, if and wherever such third-party notices normally appear. The contents of
the NOTICE file are for informational purposes only and do not modify the
License. You may add Your own attribution notices within Derivative Works that
You distribute, alongside or as an addendum to the NOTICE text from the Work,
provided that such additional attribution notices cannot be construed as
modifying the License.
You may add Your own copyright statement to Your modifications and may provide
additional or different license terms and conditions for use, reproduction, or
distribution of Your modifications, or for any such Derivative Works as a whole,
provided Your use, reproduction, and distribution of the Work otherwise complies
with the conditions stated in this License.
5. Submission of Contributions.
Unless You explicitly state otherwise, any Contribution intentionally submitted
for inclusion in the Work by You to the Licensor shall be under the terms and
conditions of this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify the terms of
any separate license agreement you may have executed with Licensor regarding
such Contributions.
6. Trademarks.
This License does not grant permission to use the trade names, trademarks,
service marks, or product names of the Licensor, except as required for
reasonable and customary use in describing the origin of the Work and
reproducing the content of the NOTICE file.
7. Disclaimer of Warranty.
Unless required by applicable law or agreed to in writing, Licensor provides the
Work (and each Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
including, without limitation, any warranties or conditions of TITLE,
NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are
solely responsible for determining the appropriateness of using or
redistributing the Work and assume any risks associated with Your exercise of
permissions under this License.
8. Limitation of Liability.
In no event and under no legal theory, whether in tort (including negligence),
contract, or otherwise, unless required by applicable law (such as deliberate
and grossly negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special, incidental,
or consequential damages of any character arising as a result of this License or
out of the use or inability to use the Work (including but not limited to
damages for loss of goodwill, work stoppage, computer failure or malfunction, or
any and all other commercial damages or losses), even if such Contributor has
been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability.
While redistributing the Work or Derivative Works thereof, You may choose to
offer, and charge a fee for, acceptance of support, warranty, indemnity, or
other liability obligations and/or rights consistent with this License. However,
in accepting such obligations, You may act only on Your own behalf and on Your
sole responsibility, not on behalf of any other Contributor, and only if You
agree to indemnify, defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason of your
accepting any such warranty or additional liability.

View File

@ -0,0 +1,618 @@
# mbed OS SDCard Driver (sd-driver) for FAT32 Filesystem Support
Simon Hughes
20170329
Version 0.1.2
# Executive Summary
The purpose of this document is to describe how to use the mbed OS SDCard
driver (sd-driver) so applications can read/write
data to flash storage cards using the standard POSIX File API
programming interface. The sd-driver uses the SDCard SPI-mode of operation
which is a subset of possible SDCard functionality.
This repository contains the mbed-os SDCard driver for generic SPI
SDCard support and other resources, as outlined below:
- `SDBlockDevice.h` and `SDBlockDevice.cpp`. This is the SDCard driver module presenting
a Block Device API (derived from BlockDevice) to the underlying SDCard.
- POSIX File API test cases for testing the FAT32 filesystem on SDCard.
- basic.cpp, a basic set of functional test cases.
- fopen.cpp, more functional tests reading/writing greater volumes of data to SDCard, for example.
- `mbed_lib.json` mbed-os application configuration file with SPI pin configurations and overrides for specific targets.
This file allows the SPI pins to be specified for the target without having to edit the implementation files.
- This README which includes [Summary of POSIX File API Documentation](#summary-posix-api-documentation)
including detailed instruction on how to use the FAT filesystem and SDBlockDevice driver.
The SDCard driver is maintained in this repository as a component separate from the main mbed OS repository.
Hence the 2 repositories (mbed-os and sd-driver) have to be used together
to deliver the FAT32 Filesystem/SDCard support. This document explains how to do this.
# Introduction
### Overview
The scope of this document is to describe how applications use the FAT filesystem and sd-driver
components to persistently store data on SDCards. The document is intended to help developers adopt the
mbed OS POSIX File API support, and in particular to help explain:
- How the software components work together to deliver the storage functionality.
- How to work with the sd-driver and mbed OS to build the examples. The example code can easily
be copied into your new application code.
- How to work with the CI Test Shield, which adds an SDCard slot to those targets that do not have already have one.
- How to run the POSIX File API mbed Greentea test cases, which provide further example code of how to use
the POSIX File API.
Section 1 provides an Executive Summary, describing the purpose of the sd-driver, the supporting
software, examples, test cases and documentation.
Section 2 provides an an overview of the material covered including descriptions of the major sections.
Section 3 provides an overview of the mbed OS filesystem software components,
including the inter-relationships between the application, POSIX file API, the standard c-library,
the mbed OS filesystem and the SDCard driver (sd-driver).
Section 4 describes how to build and run an example application for reading
and writing data to an SDCard using the POSIX File API. The example begins by describing
the procedure for building and testing on the K64F target. The final sub-sections
describe how to use the test shield to add an SDCard slot to any mbed target,
and hence enable the persistent storage of data on any supported target.
Section 5 describes an example application which uses the raw
BlockDevice API to read and write data to the SDCard.
Section 6 describes how to build and run the SDCard POSIX File API mbed Greentea test cases.
There are a number of functional test cases demonstrating how to use the
mbed OS POSIX File API.
Section 7 describes the POSIX File API and provides links to useful API documentation web pages.
### Known mbed-os and sd-driver Compatible Versions
The following versions of the mbed-os and sd-driver repositories are known to work together:
- {mbed-os, sd-driver} = {mbed-os-5.4.0-rc2, sd-driver-0.0.1-mbed-os-5.4.0-rc2}.
`K64F`, `NUCLEO_F429ZI` and `UBLOX_EVK_ODIN_W2` fopen and basic filesystem tests working.
- {mbed-os, sd-driver} = {mbed-os-5.4.0, sd-driver-0.0.2-mbed-os-5.4.0}.
`K64F`, `NUCLEO_F429ZI` and `UBLOX_EVK_ODIN_W2` fopen and basic filesystem tests working.
- {mbed-os, sd-driver} = {mbed-os-5.4.1, sd-driver-0.0.3-mbed-os-5.4.1}.
- {mbed-os, sd-driver} = {mbed-os-5.5.1, sd-driver-0.1.0-mbed-os-5.5.1}.
- {mbed-os, sd-driver} = {mbed-os-5.5.4, sd-driver-0.1.1-mbed-os-5.5.4}.
- {mbed-os, sd-driver} = {mbed-os-5.6.1, sd-driver-0.1.2-mbed-os-5.6.1}.
- {mbed-os, sd-driver} = {mbed-os-5.8.0, sd-driver-0.1.3-mbed-os-5.8.0}.
To find the latest compatible versions, use the following command to see the messages attached to the tags
in the sd-driver repository:
ex_app7/$ cd sd-driver
ex_app7/sd-driver$ git tag -n
sd-driver-0.0.1-mbed-os-5.3.4 Version compatible with mbed-os-5.3.4, and private_mbedos_filesystems-0.0.1-mbed-os-5.3.4.
sd-driver-0.0.2-mbed-os-5.4.0 Updated README.md to include worked exmaples and restructuring of information.
sd-driver-0.0.3-mbed-os-5.4.1 Version compatible with mbed-os-5.4.1.
sd-driver-0.1.1-mbed-os-5.5.4 Version compatible with mbed-os-5.5.4
sd-driver-0.1.2-mbed-os-5.6.1 Version compatible with mbed-os-5.6.1
sd-driver-0.1.3-mbed-os-5.8.0 Version compatible with mbed-os-5.8.0
### Known Issues With This Document
There are no known issues with this document.
# Overview of mbed OS Filesystem Software Component Stack
------------------------
| |
| Application | // This application uses the POSIX File API
| | // to read/write data to persistent storage backends.
------------------------
------------------------ // POSIX File API (ISO).
------------------------
| |
| libc | // The standard c library implementation
| | // e.g. newlib.
------------------------
------------------------ // sys_xxx equivalent API.
------------------------
| |
| mbed_retarget.cpp | // Target specific mapping layer.
| |
------------------------
------------------------ // Filesystem Upper Edge API.
------------------------
| |
| File System | // File system wrappers and implementation.
| |
------------------------
------------------------ // FS Lower Edge API (Block Store Interface).
------------------------
| Block API |
| Device Driver | // The SDCard driver, for example.
| e.g. sd-driver |
------------------------
------------------------ // SPI.h interface.
------------------------
| |
| SPI | // SPI subsystem (C++ classes and C-HAL implementation).
| |
------------------------
Figure 1. mbedOS generic architecture of filesystem software stack.
The figure above shows the mbed OS software component stack used for data
storage on SDCard:
- At the top level is the application component which uses the standard POSIX File API
to read and write application data to persistent storage.
- The newlib standard library (libc) stdio.h interface (POSIX File API)
implementation is used as it's optimised for resource limited embedded systems.
- mbed_retarget.cpp implements the libc back-end file OS handlers and maps them
to the FileSystem.
- The File System code (hosted in mbed-os) is composed of 2 parts:
- The mbed OS file system wrapper classes (e.g. FileSystem, File, FileBase classes)
which are used to present a consistent API to the retarget module for different
(third-party) file system implementations.
- The FAT filesystem implementation code.
The [FATFS: Generic FAT File System Module](http://elm-chan.org/fsw/ff/00index_e.html)
(ChanFS) has been integrated within mbed-os.
- The Block API Device Driver. The SDCard driver is an example of a persistent storage driver.
It's maintained as a separate component from the mbed OS repository (in this repository).
- The SPI module provides the mbed OS generic SPI API. This functionality is maintained in
mbed OS.
# SDCard POSIX File API Example App for Reading/Writing Data
Refer to [SD driver Example](https://github.com/ARMmbed/mbed-os-example-sd-driver)
### <a name="testing-with-an-sdcard-on-target-xyx"></a> Testing with an SDCard on Target XYZ
The standard way to test is with the mbed CI Test Shield plugged into the
target board. This pin mapping for this configuration is parameterised in
the `mbed_lib.json` file.
The following is an example of the `mbed_lib.json` file available in the repository:
{
"config": {
"SPI_CS": "NC",
"SPI_MOSI": "NC",
"SPI_MISO": "NC",
"SPI_CLK": "NC",
"DEVICE_SPI": 1,
"FSFAT_SDCARD_INSTALLED": 1
},
"target_overrides": {
"DISCO_F051R8": {
"SPI_MOSI": "SPI_MOSI",
"SPI_MISO": "SPI_MISO",
"SPI_CLK": "SPI_SCK",
"SPI_CS": "SPI_CS"
},
"KL46Z": {
"SPI_MOSI": "PTD6",
"SPI_MISO": "PTD7",
"SPI_CLK": "PTD5",
"SPI_CS": "PTD4"
},
"K64F": {
"SPI_MOSI": "PTE3",
"SPI_MISO": "PTE1",
"SPI_CLK": "PTE2",
"SPI_CS": "PTE4"
}
}
Note the following things about the `mbed_lib.json` file:
- The `mbed_lib.json` file is used to define target specific symbols for the SPI pins connecting the SDCard slot to the target MCU:
- "SPI\_CS". This is the Chip Select line.
- "SPI\_MOSI". This is the Master Out Slave In data line.
- "SPI\_MISO". This is the Master In Slave Out data line.
- "SPI\_CLK". This is the serial Clock line.
- The default configuration defined in the "config" section **is not valid for any platform** (will error at runtime).
The "config" section defines a dictionary mapping functional names to target board pins:
- "SPI\_CS" causes the MBED\_CONF\_APP\_SPI\_CS symbol to be defined in mbed\_config.h, which is used in the filesystem test implementation.
- "SPI\_MOSI" causes the MBED\_CONF\_APP\_SPI\_MOSI symbol to be defined in mbed\_config.h.
- "SPI\_MISO" causes the MBED\_CONF\_APP\_SPI\_MISO symbol to be defined in mbed\_config.h.
- "SPI\_CLK" causes the MBED\_CONF\_APP\_SPI\_CLK symbol to be defined in mbed\_config.h.
- The `"target_overrides"` section is used to override the "SPI\_xxx" symbols for specific target boards, which may have an SDCard slot, for example.
This is the case for the K64F, where the "SPI\_xxx" are mapped to the pin names for the on-board SDCard.
```
"K64F": {
"SPI_MOSI": "PTE3",
"SPI_MISO": "PTE1",
"SPI_CLK": "PTE2",
"SPI_CS": "PTE4"
}
```
- Thus, in the absence of any target specific definitions in the `"target_overrides"` section, all boards will default to
using the invalid configuration (will error at runtime). For those platforms with a `"target_overrides"` section then this configuration
will be used in preference.
- Hence in the case that you want to test a platform with an SDCard inserted into a
fitted CI test shield (rather than the on-board SDCard slot)
and there is a `"target_overrides"` section present in the `mbed_lib.json` file, you must provide the correct Arduino pins in the `"target_overrides"`
section before building. This will result in the default configuration being used (suitable for the CI
Test Shield). The correct pins for the CI test shield are as follows:
"<your platform name>": {
"SPI_MOSI": "D11",
"SPI_MISO": "D12",
"SPI_CLK": "D13",
"SPI_CS": "D10"
}
- Note when inserting the v1.0.0 CI Test Shield into the Arduino header of the target platform, the shield pins D0 and
D1 should be bent to be parallel to the shield PCB so they are not inserted into the Arduino header. This is because
some boards use the same UART on DAPLINK and D0/D1, which means the serial debug channel breaks and hence the mbed greentea
test suite will not work correctly. This is mainly on older ST boards and should not be a problem on
`K64F`, `NUCLEO_F429ZI` and `UBLOX_EVK_ODIN_W2`. Note also that the v2.0.0 CI Test Shield doesn't suffer from this
problem and the pins don't need to be bent.
- When inserting the SDCard into the card slot on the CI test shield, make sure the card is fully inserted.
On insertion, there should be a small clicking sound when the card registers, and the back edge of the card
should protrude no more than ~1mm over the edge of the CI test shield PCB. If the SDCard fails to register,
try gently pushing the metal flexible strip in the shape of a spade at the top edge of the SDCard metal slot
casing with a pair of tweezers, bending it a little to lower it into the slot casing. This helps with the
insertion mechanism.
### Wiring instructions for target NUCLEO_F429ZI with CI Test Shield
![alt text](docs/pics/NUCLEO_F429ZI_wiring_with_ci_test_shield.png "unseen title text")
**Figure 3. The figure shows how to connect the NUCLEO_F429ZI platform with the CI shield.**
The above figure shows how to connect the NUCLEO_F429ZI with the v1.0.0 CI test shield. Note:
- To get the SD Card to work with this platform the CI test shield cannot be connected directly to this board, instead follow the instructions above.
- Any SD-card adapter will work as long as you connect all the relevant pins (MOSI, MISO, SCLK, CS, 3.3V and GND) as illustrated in figure 3.
- The SDCard is fully inserted into the slot and overhangs the PCB by ~1mm.
# SDBlockDevice Example Application
The following sample code illustrates how to use the sd-driver Block Device API:
``` cpp
#include "mbed.h"
#include "SDBlockDevice.h"
// Instantiate the SDBlockDevice by specifying the SPI pins connected to the SDCard
// socket. The PINS are:
// MOSI (Master Out Slave In)
// MISO (Master In Slave Out)
// SCLK (Serial Clock)
// CS (Chip Select)
SDBlockDevice sd(MBED_CONF_SD_SPI_MOSI, MBED_CONF_SD_SPI_MISO, MBED_CONF_SD_SPI_CLK, MBED_CONF_SD_SPI_CS);
uint8_t block[512] = "Hello World!\n";
int main()
{
// call the SDBlockDevice instance initialisation method.
if ( 0 != sd.init()) {
printf("Init failed \n");
return -1;
}
printf("sd size: %llu\n", sd.size());
printf("sd read size: %llu\n", sd.get_read_size());
printf("sd program size: %llu\n", sd.get_program_size());
printf("sd erase size: %llu\n", sd.get_erase_size());
// set the frequency
if ( 0 != sd.frequency(5000000)) {
printf("Error setting frequency \n");
}
if ( 0 != sd.erase(0, sd.get_erase_size())) {
printf("Error Erasing block \n");
}
// Write some the data block to the device
if ( 0 == sd.program(block, 0, 512)) {
// read the data block from the device
if ( 0 == sd.read(block, 0, 512)) {
// print the contents of the block
printf("%s", block);
}
}
// call the SDBlockDevice instance de-initialisation method.
sd.deinit();
}
```
# SDCard POSIX File API mbed Greentea Test Cases
This section describes how to build and run the POSIX file API test cases.
The following steps are covered:
- [Create the FAT/SDCard Application Project](#create-fat-sdcard-application-project).
This section describes how to git clone the mbed OS and sd-driver repositories containing the
code and test cases of interest.
- [Build the mbed OS Test Cases](#build-the-mbedos-test-cases). This section
describes how to build the mbed OS test cases.
- [Insert a microSD Card Into the K64F for Greentea Testing](#greentea-insert-sdcard-into-k64f).This section
describes how to format (if required) a microSD card prior to running the tests.
- [Run the POSIX File Test Case](#run-the-posix-file-test-cases).This section
describes how to run the POSIX file test cases.
### <a name="create-fat-sdcard-application-project"></a> Create the FAT/SDCard Application Project
This section describes how to create an application project combining the mbed-os and
sd-driver repositories into a single project.
In summary the following steps will be covered in this section:
- A top level application project directory is created. The directory name is ex_app1.
- In the ex_app1 directory, the mbed-os repository is cloned.
- In the ex_app1 directory at the same level as the mbed-os directory, the sd-driver repository is cloned.
- The `mbed_lib.json` file is copied from the `sd-driver/config/mbed_lib.json` to the ex_app1 directory.
First create the top level application directory ex_app1 and move into it:
shell:/d/demo_area$ mkdir ex_app1
shell:/d/demo_area$ pushd ex_app1
Next, get a clone of public mbed OS repository in the following way:
shell:/d/demo_area/ex_app1$ git clone git@github.com:/armmbed/mbed-os
<trace removed>
shell:/d/demo_area/ex_app1$
Next, get a clone of the sd-driver repository:
shell:/d/demo_area/ex_app1$ git clone git@github.com:/armmbed/sd-driver
<trace removed>
shell:/d/demo_area/ex_app1$
Note: The `mbed_lib.json` file specifies the SPI bus pin configuration for different targets,
and is discussed in the [Testing with an SDCard on Target XYZ](#testing-with-an-sdcard-on-target-xyx) section.
### <a name="build-the-mbedos-test-cases"></a> Build the mbed OS Test Cases
Build the test cases for the K64F target using the following command:
shell:/d/demo_area/ex_app1$ mbed -v test --compile -t GCC_ARM -m K64F
<trace removed>
shell:/d/demo_area/ex_app1$
The build trace is quite extensive but on a successful build you should see the following output at the end of the log:
Build successes:
* K64F::GCC_ARM::MBED-BUILD
* K64F::GCC_ARM::MBED-OS-FEATURES-FEATURE_LWIP-TESTS-MBEDMICRO-NET-CONNECTIVITY
<trace removed>
* K64F::GCC_ARM::MBED-OS-FEATURES-TESTS-FILESYSTEM-FAT_FILE_SYSTEM
* K64F::GCC_ARM::MBED-OS-FEATURES-TESTS-FILESYSTEM-HEAP_BLOCK_DEVICE
* K64F::GCC_ARM::MBED-OS-FEATURES-TESTS-FILESYSTEM-UTIL_BLOCK_DEVICE
<trace removed>
* K64F::GCC_ARM::SD-DRIVER-TESTS-BLOCK_DEVICE-BASIC
* K64F::GCC_ARM::SD-DRIVER-TESTS-FILESYSTEM-BASIC
* K64F::GCC_ARM::SD-DRIVER-TESTS-FILESYSTEM-DIRS
* K64F::GCC_ARM::SD-DRIVER-TESTS-FILESYSTEM-FILES
* K64F::GCC_ARM::SD-DRIVER-TESTS-FILESYSTEM-FOPEN
* K64F::GCC_ARM::SD-DRIVER-TESTS-FILESYSTEM-PARALLEL
* K64F::GCC_ARM::SD-DRIVER-TESTS-FILESYSTEM-SEEK
Build skips:
* K64F::GCC_ARM::MBED-OS-FEATURES-FEATURE_LWIP-TESTS-MBEDMICRO-NET-TCP_PACKET_PRESSURE
<trace removed>
Notice the following tests in the sd-driver tree are listed above:
- `SD-DRIVER-TESTS-BLOCK_DEVICE-BASIC`
- `SD-DRIVER-TESTS-FILESYSTEM-BASIC`
- `SD-DRIVER-TESTS-FILESYSTEM-DIRS`
- `SD-DRIVER-TESTS-FILESYSTEM-FILES`
- `SD-DRIVER-TESTS-FILESYSTEM-FOPEN`
- `SD-DRIVER-TESTS-FILESYSTEM-PARALLEL`
- `SD-DRIVER-TESTS-FILESYSTEM-SEEK`
The FAT32/SDCard test cases are at following locations in the source code tree:
/d/demo_area/ex_app1/sd-driver/TESTS/filesystem/basic/basic.cpp
/d/demo_area/ex_app1/sd-driver/TESTS/filesystem/fopen/fopen.cpp
/d/demo_area/ex_app1/sd-driver/TESTS/block_device/basic/basic.cpp
/d/demo_area/ex_app1/sd-driver/TESTS/filesystem/dirs/main.cpp
/d/demo_area/ex_app1/sd-driver/TESTS/filesystem/files/main.cpp
/d/demo_area/ex_app1/sd-driver/TESTS/filesystem/parallel/main.cpp
/d/demo_area/ex_app1/sd-driver/TESTS/filesystem/seek/main.cpp
#### <a name="settting-repos-to-compatible-versions"></a> Setting mbed-os/sd-driver Repositories To Compatible Versions
The sd-driver master HEAD and the mbed-os master HEAD should be compatible
with one another and therefore no specific tagged versions need to be checked out.
However, in the case that you experience problems building, checkout out the compatible
tagged version of each repository, as shown below:
shell:/d/demo_area/ex_app1$ pushd mbed-os
shell:/d/demo_area/ex_app1$ git checkout tags/mbed-os-5.4.0
shell:/d/demo_area/ex_app1$ popd
shell:/d/demo_area/ex_app1$ pushd sd-driver
shell:/d/demo_area/ex_app1$ git checkout tags/sd-driver-0.0.2-mbed-os-5.4.0
shell:/d/demo_area/ex_app1$ popd
In the above:
- `mbed-os-5.4.0` should be replaced with the latest mbed-os release tag.
- For an mbed-os release tag `mbed-os-x.y.z`, use the equivalent sd-driver tag `sd-driver-a.b.c-mbed-os-x.y.z`
where `a.b.c` is the latest version code for the `mbed-os-x.y.z` tag.
### <a name="greentea-insert-sdcard-into-k64f"></a> Insert SDCard into K64F for Greentea Testing
See the previous section for [Insert SDCard into K64F](#insert-sdcard-into-k64f) for details.
### <a name="run-the-posix-file-test-cases"></a> Run the POSIX File Test Case
To setup for running the test cases, connect the K64F development board to your
PC using a suitable USB cable.
All tests can be run using the following command:
shell:/d/demo_area/ex_app1$ mbedgt -VS
<trace removed>
However, it's possible to run a particular test case using the following form of the mbedgt command:
shell:/d/demo_area/ex_app1$ mbedgt -VS --test-by-names=<test-name>
The names of the tests can be listed using:
shell:/d/demo_area/ex_app1$ mbedgt -VS --list
For example, to run the basic test use:
shell:/d/demo_area/ex_app1$ mbedgt -VS --test-by-names=sd-driver-tests-filesystem-basic
To run the fopen test use:
shell:/d/demo_area/ex_app1$ mbedgt -VS --test-by-names=sd-driver-tests-filesystem-fopen
On a successful run, results similar to the following will be shown:
mbedgt: test suite report:
+--------------+---------------+-------------------------------------------+--------+--------------------+-------------+
| target | platform_name | test suite | result | elapsed_time (sec) | copy_method |
+--------------+---------------+-------------------------------------------+--------+--------------------+-------------+
| K64F-GCC_ARM | K64F | sd-driver-features-tests-filesystem-fopen | OK | 151.46 | shell |
+--------------+---------------+-------------------------------------------+--------+--------------------+-------------+
mbedgt: test suite results: 1 OK
mbedgt: test case report:
+--------------+---------------+------------------------------------+----------------------------------------------------------------------------------------+--------+--------+--------+--------------------+
| target | platform_name | test suite | test case | passed | failed | result | elapsed_time (sec) |
+--------------+---------------+------------------------------------+----------------------------------------------------------------------------------------+--------+--------+--------+--------------------+
| K64F-GCC_ARM | K64F | sd-driver-tests-filesystem-fopen | FSFAT_FOPEN_TEST_01: fopen()/fwrite()/fclose() directories/file in multi-dir filepath. | 1 | 0 | OK | 7.57 |
| K64F-GCC_ARM | K64F | sd-driver-tests-filesystem-fopen | FSFAT_FOPEN_TEST_02: fopen(r) pre-existing file try to write it. | 1 | 0 | OK | 0.2 |
| K64F-GCC_ARM | K64F | sd-driver-tests-filesystem-fopen | FSFAT_FOPEN_TEST_03: fopen(w+) pre-existing file try to write it. | 1 | 0 | OK | 0.41 |
| K64F-GCC_ARM | K64F | sd-driver-tests-filesystem-fopen | FSFAT_FOPEN_TEST_04: fopen() with a filename exceeding the maximum length. | 1 | 0 | OK | 0.11 |
| K64F-GCC_ARM | K64F | sd-driver-tests-filesystem-fopen | FSFAT_FOPEN_TEST_06: fopen() with bad filenames (minimal). | 1 | 0 | OK | 0.1 |
| K64F-GCC_ARM | K64F | sd-driver-tests-filesystem-fopen | FSFAT_FOPEN_TEST_07: fopen()/errno handling. | 1 | 0 | OK | 0.07 |
| K64F-GCC_ARM | K64F | sd-driver-tests-filesystem-fopen | FSFAT_FOPEN_TEST_08: ferror()/clearerr()/errno handling. | 1 | 0 | OK | 0.1 |
| K64F-GCC_ARM | K64F | sd-driver-tests-filesystem-fopen | FSFAT_FOPEN_TEST_09: ftell() handling. | 1 | 0 | OK | 0.17 |
| K64F-GCC_ARM | K64F | sd-driver-tests-filesystem-fopen | FSFAT_FOPEN_TEST_10: remove() test. | 1 | 0 | OK | 1.28 |
| K64F-GCC_ARM | K64F | sd-driver-tests-filesystem-fopen | FSFAT_FOPEN_TEST_11: rename(). | 1 | 0 | OK | 2.3 |
| K64F-GCC_ARM | K64F | sd-driver-tests-filesystem-fopen | FSFAT_FOPEN_TEST_12: opendir(), readdir(), closedir() test. | 1 | 0 | OK | 3.57 |
| K64F-GCC_ARM | K64F | sd-driver-tests-filesystem-fopen | FSFAT_FOPEN_TEST_13: mkdir() test. | 1 | 0 | OK | 1.21 |
| K64F-GCC_ARM | K64F | sd-driver-tests-filesystem-fopen | FSFAT_FOPEN_TEST_14: stat() test. | 1 | 0 | OK | 1.47 |
| K64F-GCC_ARM | K64F | sd-driver-tests-filesystem-fopen | FSFAT_FOPEN_TEST_15: format() test. | 1 | 0 | OK | 26.12 |
| K64F-GCC_ARM | K64F | sd-driver-tests-filesystem-fopen | FSFAT_FOPEN_TEST_16: write/check n x 25kB data files. | 1 | 0 | OK | 87.11 |
+--------------+---------------+------------------------------------+----------------------------------------------------------------------------------------+--------+--------+--------+--------------------+
mbedgt: test case results: 15 OK
mbedgt: completed in 152.35 sec
# <a name="summary-posix-api-documentation"></a> Summary of POSIX File API Documentation
### POSIX File API
mbed OS supports a subset of the POSIX File API, as outlined below:
- [clearerr()](https://linux.die.net/man/3/clearerr).
- STATUS: Basic testing implemented. Working.
- [fclose()](https://linux.die.net/man/3/fclose).
- STATUS: Basic testing implemented. Working.
- [ferror()](https://linux.die.net/man/3/clearerr).
- STATUS: Basic testing implemented.
- STATUS: GCC_ARM: Working.
- STATUS: ARMCC: ARMCC has problem with ferror(filep) where filep is NULL. Appears to work for non-NULL pointer.
- [fgetc()](https://linux.die.net/man/3/fgets).
- STATUS: Basic testing implemented. Working.
- [fgets()](https://linux.die.net/man/3/fgets).
- STATUS: Basic testing implemented. Working.
- [fputc()](https://linux.die.net/man/3/fputs).
- STATUS: Unknown.
- [fputs()](https://linux.die.net/man/3/fputs).
- STATUS: Basic testing implemented. Working.
- [fprintf()](https://linux.die.net/man/3/fprintf).
- STATUS: Basic testing implemented. Working.
- [fopen()](https://linux.die.net/man/3/fopen).
- STATUS: Basic testing implemented. Working.
- [freopen()](https://linux.die.net/man/3/fopen).
- STATUS: This is not tested.
- [fread()](https://linux.die.net/man/3/fread).
- STATUS: Basic testing implemented. Working.
- STATUS: n x 25kB stress test working.
- [ftell()](https://linux.die.net/man/3/ftell).
- STATUS: Basic testing implemented. Working.
- [fwrite()](https://linux.die.net/man/3/fwrite).
- STATUS: Basic testing implemented. Working.
- STATUS: n x 25kB stress test working.
- [fseek()](https://linux.die.net/man/3/fseek)
- STATUS: Basic testing implemented. Working.
- [getc()](https://linux.die.net/man/3/fgets).
- STATUS: Basic testing implemented. Working.
- [gets()](https://linux.die.net/man/3/fgets).
- STATUS: Unknown.
- [putc()](https://linux.die.net/man/3/fputs).
- STATUS: Unknown.
- [puts()](https://linux.die.net/man/3/fputs).
- STATUS: Unknown.
- [remove()](https://linux.die.net/man/3/remove)
- STATUS: Basic testing implemented. Working.
- [rewind()](https://linux.die.net/man/3/rewind).
- STATUS: Basic testing implemented. Working.
- [stat()](https://linux.die.net/man/2/stat)
- STATUS: Implemented. Working.
- STATUS: Not supported by ARMCC/IAR libc.
- [tmpfile()](https://linux.die.net/man/3/tmpfile).
- STATUS: Not implemented.
- [tmpnam()](https://linux.die.net/man/3/tmpnam).
- STATUS: Not implemented.
Supported directory related operations are as follows:
- [closedir()](https://linux.die.net/man/3/closedir).
- STATUS: Implemented. Working.
- [mkdir()](https://linux.die.net/man/3/mkdir).
- STATUS: Basic testing implemented. Working.
- [opendir()](https://linux.die.net/man/3/opendir).
- STATUS: Implemented. Working.
- [readdir()](https://linux.die.net/man/3/readdir).
- STATUS: Implemented. Working.
- [remove()](https://linux.die.net/man/3/remove).
- STATUS: Basic testing implemented. Working.
- [rename()](https://linux.die.net/man/3/rename).
- STATUS: Implemented. Not tested.
- [rewinddir()](https://linux.die.net/man/3/rewinddir).
- STATUS: Implemented. Found not to work. Test case not present in repo.
- [seekdir()](https://linux.die.net/man/3/seekdir).
- STATUS: Implemented. Found not to work. Test case not present in repo.
- [telldir()](https://linux.die.net/man/3/telldir).
- STATUS: Implemented. Found not to work. Test case not present in repo.
### errno
Basic errno reporting is supported, tested and known to be working.
# Related Projects Resources
The following are related mbed storage projects and useful resources:
- The [mbed-os](https://github.com/ARMmbed/mbed-os) main repository.
- The [mbed-os-example-fat-filesystem](https://github.com/ARMmbed/mbed-os-example-fat-filesystem) repository.
This is an example project for the mbed OS FAT filesystem.
- The [spiflash-driver](https://github.com/armmbed/spiflash-driver) repository.
- The [i2ceeprom-driver](https://github.com/ARMmbed/i2ceeprom-driver.git) repository.
- The [ci-test-shield](https://github.com/ARMmbed/ci-test-shield) repository. This is the project describing
the mbed-os Continuous Integration test shield, together with standard tests.
- The [mbed-HDK](https://github.com/ARMmbed/mbed-HDK) repository containing Hardware Development Kit resources
including the schematics for the CI test shield.
- [POSIX File Interface ISO/IEC 9899:TC2 Documentation](http://www.eng.utah.edu/~cs5785/slides-f10/n1124.pdf).
- [FATFS: Generic FAT File System Module used in mbed OS](http://elm-chan.org/fsw/ff/00index_e.html)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,237 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2013 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_SD_BLOCK_DEVICE_H
#define MBED_SD_BLOCK_DEVICE_H
/* If the target has no SPI support then SDCard is not supported */
#ifdef DEVICE_SPI
#include "BlockDevice.h"
#include "mbed.h"
#include "platform/PlatformMutex.h"
/** Access an SD Card using SPI
*
* @code
* #include "mbed.h"
* #include "SDBlockDevice.h"
*
* SDBlockDevice sd(p5, p6, p7, p12); // mosi, miso, sclk, cs
* uint8_t block[512] = "Hello World!\n";
*
* int main() {
* sd.init();
* sd.write(block, 0, 512);
* sd.read(block, 0, 512);
* printf("%s", block);
* sd.deinit();
* }
*/
class SDBlockDevice : public BlockDevice {
public:
/** Lifetime of an SD card
*/
SDBlockDevice(PinName mosi, PinName miso, PinName sclk, PinName cs, uint64_t hz=1000000, bool crc_on=0);
virtual ~SDBlockDevice();
/** 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 State of debugging
*/
virtual void debug(bool dbg);
/** Set the transfer frequency
*
* @param Transfer frequency
* @note Max frequency supported is 25MHZ
*/
virtual int frequency(uint64_t freq);
private:
/* Commands : Listed below are commands supported
* in SPI mode for SD card : Only Mandatory ones
*/
enum cmdSupported {
CMD_NOT_SUPPORTED = -1, /**< Command not supported error */
CMD0_GO_IDLE_STATE = 0, /**< Resets the SD Memory Card */
CMD1_SEND_OP_COND = 1, /**< Sends host capacity support */
CMD6_SWITCH_FUNC = 6, /**< Check and Switches card function */
CMD8_SEND_IF_COND = 8, /**< Supply voltage info */
CMD9_SEND_CSD = 9, /**< Provides Card Specific data */
CMD10_SEND_CID = 10, /**< Provides Card Identification */
CMD12_STOP_TRANSMISSION = 12, /**< Forces the card to stop transmission */
CMD13_SEND_STATUS = 13, /**< Card responds with status */
CMD16_SET_BLOCKLEN = 16, /**< Length for SC card is set */
CMD17_READ_SINGLE_BLOCK = 17, /**< Read single block of data */
CMD18_READ_MULTIPLE_BLOCK = 18, /**< Card transfers data blocks to host until interrupted
by a STOP_TRANSMISSION command */
CMD24_WRITE_BLOCK = 24, /**< Write single block of data */
CMD25_WRITE_MULTIPLE_BLOCK = 25, /**< Continuously writes blocks of data until
'Stop Tran' token is sent */
CMD27_PROGRAM_CSD = 27, /**< Programming bits of CSD */
CMD32_ERASE_WR_BLK_START_ADDR = 32, /**< Sets the address of the first write
block to be erased. */
CMD33_ERASE_WR_BLK_END_ADDR = 33, /**< Sets the address of the last write
block of the continuous range to be erased.*/
CMD38_ERASE = 38, /**< Erases all previously selected write blocks */
CMD55_APP_CMD = 55, /**< Extend to Applications specific commands */
CMD56_GEN_CMD = 56, /**< General Purpose Command */
CMD58_READ_OCR = 58, /**< Read OCR register of card */
CMD59_CRC_ON_OFF = 59, /**< Turns the CRC option on or off*/
// App Commands
ACMD6_SET_BUS_WIDTH = 6,
ACMD13_SD_STATUS = 13,
ACMD22_SEND_NUM_WR_BLOCKS = 22,
ACMD23_SET_WR_BLK_ERASE_COUNT = 23,
ACMD41_SD_SEND_OP_COND = 41,
ACMD42_SET_CLR_CARD_DETECT = 42,
ACMD51_SEND_SCR = 51,
};
uint8_t _card_type;
int _cmd(SDBlockDevice::cmdSupported cmd, uint32_t arg, bool isAcmd=0, uint32_t *resp=NULL);
int _cmd8();
/* Move the SDCard into the SPI Mode idle state
*
* The card is transitioned from SDCard mode to SPI mode by sending the
* CMD0 (GO_IDLE_STATE) command with CS asserted. See the notes in the
* "SPI Startup" section of the comments at the head of the
* implementation file for further details and specification references.
*
* @return Response form the card. R1_IDLE_STATE (0x1), the successful
* response from CMD0. R1_XXX_XXX for more response
*/
uint32_t _go_idle_state();
int _initialise_card();
bd_size_t _sectors;
bd_size_t _sd_sectors();
bool _is_valid_trim(bd_addr_t addr, bd_size_t size);
/* SPI functions */
Timer _spi_timer; /**< Timer Class object used for busy wait */
uint32_t _init_sck; /**< Intial SPI frequency */
uint32_t _transfer_sck; /**< SPI frequency during data transfer/after initialization */
SPI _spi; /**< SPI Class object */
/* SPI initialization function */
void _spi_init();
uint8_t _cmd_spi(SDBlockDevice::cmdSupported cmd, uint32_t arg);
void _spi_wait(uint8_t count);
bool _wait_token(uint8_t token); /**< Wait for token */
bool _wait_ready(uint16_t ms=300); /**< 300ms default wait for card to be ready */
int _read(uint8_t * buffer, uint32_t length);
int _read_bytes(uint8_t * buffer, uint32_t length);
uint8_t _write(const uint8_t *buffer,uint8_t token, uint32_t length);
int _freq(void);
/* Chip Select and SPI mode select */
DigitalOut _cs;
void _select();
void _deselect();
virtual void lock() {
_mutex.lock();
}
virtual void unlock() {
_mutex.unlock();
}
PlatformMutex _mutex;
bd_size_t _block_size;
bd_size_t _erase_size;
bool _is_initialized;
bool _dbg;
bool _crc_on;
uint32_t _init_ref_count;
MbedCRC<POLY_7BIT_SD, 7> _crc7;
MbedCRC<POLY_16BIT_CCITT, 16> _crc16;
};
#endif /* DEVICE_SPI */
#endif /* MBED_SD_BLOCK_DEVICE_H */

View File

@ -0,0 +1,179 @@
/*
* 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.
*
*/
/* The following copyright notice is reproduced from the glibc project
* REF_LICENCE_GLIBC
*
* Copyright (C) 1991, 1992 Free Software Foundation, Inc.
* This file is part of the GNU C Library.
*
* The GNU C Library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* The GNU C Library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with the GNU C Library; see the file COPYING.LIB. If
* not, write to the Free Software Foundation, Inc., 675 Mass Ave,
* Cambridge, MA 02139, USA.
*/
/** @file main.cpp Basic SD Driver Test
*/
#include "mbed.h"
#include "greentea-client/test_env.h"
#include "unity.h"
#include "utest.h"
#include "SDBlockDevice.h"
#include <stdlib.h>
using namespace utest::v1;
#define TEST_BLOCK_COUNT 10
#define TEST_ERROR_MASK 16
#define TEST_BLOCK_SIZE 2048
const struct {
const char *name;
bd_size_t (BlockDevice::*method)() const;
} ATTRS[] = {
{"read size", &BlockDevice::get_read_size},
{"program size", &BlockDevice::get_program_size},
{"erase size", &BlockDevice::get_erase_size},
{"total size", &BlockDevice::size},
};
void test_read_write() {
SDBlockDevice sd(MBED_CONF_SD_SPI_MOSI, MBED_CONF_SD_SPI_MISO, MBED_CONF_SD_SPI_CLK, MBED_CONF_SD_SPI_CS);
int err = sd.init();
TEST_ASSERT_EQUAL(0, err);
err = sd.frequency(8000000);
TEST_ASSERT_EQUAL(0, err);
for (unsigned a = 0; a < sizeof(ATTRS)/sizeof(ATTRS[0]); a++) {
static const char *prefixes[] = {"", "k", "M", "G"};
for (int i = 3; i >= 0; i--) {
bd_size_t size = (sd.*ATTRS[a].method)();
if (size >= (1ULL << 10*i)) {
printf("%s: %llu%sbytes (%llubytes)\n",
ATTRS[a].name, size >> 10*i, prefixes[i], size);
break;
}
}
}
bd_size_t erase_size = sd.get_erase_size();
bd_size_t block_size = erase_size > TEST_BLOCK_SIZE ? erase_size : TEST_BLOCK_SIZE;
uint8_t *write_block = new uint8_t[block_size];
uint8_t *read_block = new uint8_t[block_size];
uint8_t *error_mask = new uint8_t[TEST_ERROR_MASK];
unsigned addrwidth = ceil(log(float(sd.size()-1)) / log(float(16)))+1;
for (int b = 0; b < TEST_BLOCK_COUNT; b++) {
// Find a random block
bd_addr_t block = (rand()*block_size) % sd.size();
// Use next random number as temporary seed to keep
// the address progressing in the pseudorandom sequence
unsigned seed = rand();
// Fill with random sequence
srand(seed);
for (bd_size_t i = 0; i < block_size; i++) {
write_block[i] = 0xff & rand();
}
// Write, sync, and read the block
printf("test %0*llx:%llu...\n", addrwidth, block, block_size);
err = sd.trim(block, block_size);
TEST_ASSERT_EQUAL(0, err);
err = sd.program(write_block, block, block_size);
TEST_ASSERT_EQUAL(0, err);
printf("write %0*llx:%llu ", addrwidth, block, block_size);
for (int i = 0; i < 16; i++) {
printf("%02x", write_block[i]);
}
printf("...\n");
err = sd.read(read_block, block, block_size);
TEST_ASSERT_EQUAL(0, err);
printf("read %0*llx:%llu ", addrwidth, block, block_size);
for (int i = 0; i < 16; i++) {
printf("%02x", read_block[i]);
}
printf("...\n");
// Find error mask for debugging
memset(error_mask, 0, TEST_ERROR_MASK);
bd_size_t error_scale = block_size / (TEST_ERROR_MASK*8);
srand(seed);
for (bd_size_t i = 0; i < TEST_ERROR_MASK*8; i++) {
for (bd_size_t j = 0; j < error_scale; j++) {
if ((0xff & rand()) != read_block[i*error_scale + j]) {
error_mask[i/8] |= 1 << (i%8);
}
}
}
printf("error %0*llx:%llu ", addrwidth, block, block_size);
for (int i = 0; i < 16; i++) {
printf("%02x", error_mask[i]);
}
printf("\n");
// Check that the data was unmodified
srand(seed);
for (bd_size_t i = 0; i < block_size; i++) {
TEST_ASSERT_EQUAL(0xff & rand(), read_block[i]);
}
}
err = sd.deinit();
TEST_ASSERT_EQUAL(0, err);
}
// Test setup
utest::v1::status_t test_setup(const size_t number_of_cases) {
GREENTEA_SETUP(120, "default_auto");
return verbose_test_setup_handler(number_of_cases);
}
Case cases[] = {
Case("Testing read write random blocks", test_read_write),
};
Specification specification(test_setup, cases);
int main() {
return !Harness::run(specification);
}

View File

@ -0,0 +1,933 @@
/*
* 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.
*
*/
/* The following copyright notice is reproduced from the glibc project
* REF_LICENCE_GLIBC
*
* Copyright (C) 1991, 1992 Free Software Foundation, Inc.
* This file is part of the GNU C Library.
*
* The GNU C Library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* The GNU C Library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with the GNU C Library; see the file COPYING.LIB. If
* not, write to the Free Software Foundation, Inc., 675 Mass Ave,
* Cambridge, MA 02139, USA.
*/
/** @file basic.cpp POSIX File API (stdio) test cases
*
* Consult the documentation under the test-case functions for
* a description of the individual test case.
*
* this file includes ports for the mbed 2 test cases from the following locations:
* - https://github.com:/armmbed/mbed-os/features/unsupported/tests/mbed/dir_sd/main.cpp.
* - https://github.com:/armmbed/mbed-os/features/unsupported/tests/mbed/file/main.cpp.
* - https://github.com:/armmbed/mbed-os/features/unsupported/tests/mbed/sd/main.cpp
* - https://github.com:/armmbed/mbed-os/features/unsupported/tests/mbed/sd_perf_handle/main.cpp
* - https://github.com:/armmbed/mbed-os/features/unsupported/tests/mbed/sd_perf_stdio/main.cpp.
*/
#include "mbed.h"
#include "mbed_config.h"
#include "FATFileSystem.h"
#include "SDBlockDevice.h"
#include "test_env.h"
#include "fsfat_debug.h"
#include "fsfat_test.h"
#include "utest/utest.h"
#include "unity/unity.h"
#include "greentea-client/test_env.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <algorithm>
/* 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;
/* 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,
* "MBED_CONF_APP_FSFAT_SDCARD_INSTALLED": 1
* },
* <<< lines removed >>>
*/
#if defined(DEVICE_SPI) && ( defined(MBED_CONF_APP_FSFAT_SDCARD_INSTALLED) || (MBED_CONF_SD_FSFAT_SDCARD_INSTALLED))
#define FSFAT_BASIC_TEST_00 fsfat_basic_test_00
#define FSFAT_BASIC_TEST_01 fsfat_basic_test_01
#define FSFAT_BASIC_TEST_02 fsfat_basic_test_02
#define FSFAT_BASIC_TEST_03 fsfat_basic_test_03
#define FSFAT_BASIC_TEST_04 fsfat_basic_test_04
#define FSFAT_BASIC_TEST_05 fsfat_basic_test_05
#define FSFAT_BASIC_TEST_06 fsfat_basic_test_06
#define FSFAT_BASIC_TEST_07 fsfat_basic_test_07
#define FSFAT_BASIC_TEST_08 fsfat_basic_test_08
#define FSFAT_BASIC_TEST_09 fsfat_basic_test_09
#define FSFAT_BASIC_TEST_10 fsfat_basic_test_10
#define FSFAT_BASIC_MSG_BUF_SIZE 256
#define FSFAT_BASIC_TEST_05_TEST_STRING "Hello World!"
static const char *sd_file_path = "/sd/out.txt";
static const char *sd_mount_pt = "sd";
static const int FSFAT_BASIC_DATA_SIZE = 256;
static char fsfat_basic_msg_g[FSFAT_BASIC_MSG_BUF_SIZE];
static char fsfat_basic_buffer[1024];
static const int FSFAT_BASIC_KIB_RW = 128;
static Timer fsfat_basic_timer;
static const char *fsfat_basic_bin_filename = "/sd/testfile.bin";
static const char *fsfat_basic_bin_filename_test_08 = "testfile.bin";
static const char *fsfat_basic_bin_filename_test_10 = "0:testfile.bin";
SDBlockDevice sd(MBED_CONF_SD_SPI_MOSI, MBED_CONF_SD_SPI_MISO, MBED_CONF_SD_SPI_CLK, MBED_CONF_SD_SPI_CS);
FATFileSystem fs(sd_mount_pt, &sd);
#define FSFAT_BASIC_MSG(_buf, _max_len, _fmt, ...) \
do \
{ \
snprintf((_buf), (_max_len), (_fmt), __VA_ARGS__); \
}while(0);
/** @brief fopen test case
*
* - open a file
* - generate random data items, write the item to the file and store a coy in a buffer for later use.
* - close the file.
* - open the file.
* - read the data items from the file and check they are the same as write.
* - close the file.
*
* @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
*/
static control_t fsfat_basic_test_00()
{
uint8_t data_written[FSFAT_BASIC_DATA_SIZE] = { 0 };
bool read_result = false;
bool write_result = false;
// Fill data_written buffer with random data
// Write these data into the file
FSFAT_FENTRYLOG("%s:entered\n", __func__);
{
FSFAT_DBGLOG("%s:SD: Writing ... ", __func__);
FILE *f = fopen(sd_file_path, "w");
if (f) {
for (int i = 0; i < FSFAT_BASIC_DATA_SIZE; i++) {
data_written[i] = rand() % 0XFF;
fprintf(f, "%c", data_written[i]);
}
write_result = true;
fclose(f);
}
FSFAT_DBGLOG("[%s]\n", write_result ? "OK" : "FAIL");
}
TEST_ASSERT_MESSAGE(write_result == true, "Error: write_result is set to false.");
// Read back the data from the file and store them in data_read
{
FSFAT_DBGLOG("%s:SD: Reading data ... ", __func__);
FILE *f = fopen(sd_file_path, "r");
if (f) {
read_result = true;
for (int i = 0; i < FSFAT_BASIC_DATA_SIZE; i++) {
uint8_t data = fgetc(f);
if (data != data_written[i]) {
read_result = false;
break;
}
}
fclose(f);
}
FSFAT_DBGLOG("[%s]\n", read_result ? "OK" : "FAIL");
}
TEST_ASSERT_MESSAGE(read_result == true, "Error: read_result is set to false.");
return CaseNext;
}
/** @brief test-fseek.c test ported from glibc project. See the licence at REF_LICENCE_GLIBC.
*
* @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
*/
static control_t fsfat_basic_test_01()
{
FILE *fp, *fp1;
int i, j;
int ret = 0;
FSFAT_FENTRYLOG("%s:entered\n", __func__);
fp = fopen (sd_file_path, "w+");
if (fp == NULL) {
FSFAT_DBGLOG("errno=%d\n", errno);
TEST_ASSERT_MESSAGE(false, "error");
return CaseNext;
}
for (i = 0; i < 256; i++) {
putc (i, fp);
}
/* FIXME: freopen() should open the specified file closing the first stream. As can be seen from the
* code below, the old file descriptor fp can still be used, and this should not happen.
*/
fp1 = freopen (sd_file_path, "r", fp);
TEST_ASSERT_MESSAGE(fp1 == fp, "Error: cannot open file for reading");
for (i = 1; i <= 255; i++) {
ret = fseek (fp, (long) -i, SEEK_END);
FSFAT_BASIC_MSG(fsfat_basic_msg_g, FSFAT_BASIC_MSG_BUF_SIZE, "%s:Error: fseek() failed (ret=%d).\n", __func__, (int) ret);
TEST_ASSERT_MESSAGE(ret == 0, fsfat_basic_msg_g);
if ((j = getc (fp)) != 256 - i) {
FSFAT_BASIC_MSG(fsfat_basic_msg_g, FSFAT_BASIC_MSG_BUF_SIZE, "%s: Error: SEEK_END failed (j=%d)\n", __func__, j);
TEST_ASSERT_MESSAGE(false, fsfat_basic_msg_g);
}
ret = fseek (fp, (long) i, SEEK_SET);
FSFAT_BASIC_MSG(fsfat_basic_msg_g, FSFAT_BASIC_MSG_BUF_SIZE, "%s: Error: Cannot SEEK_SET (ret=%d).\n", __func__, (int) ret);
TEST_ASSERT_MESSAGE(ret == 0, fsfat_basic_msg_g);
if ((j = getc (fp)) != i) {
FSFAT_BASIC_MSG(fsfat_basic_msg_g, FSFAT_BASIC_MSG_BUF_SIZE, "%s: Error: Cannot SEEK_SET (j=%d).\n", __func__, j);
TEST_ASSERT_MESSAGE(ret == 0, fsfat_basic_msg_g);
}
if ((ret = fseek (fp, (long) i, SEEK_SET))) {
FSFAT_BASIC_MSG(fsfat_basic_msg_g, FSFAT_BASIC_MSG_BUF_SIZE, "%s: Error: Cannot SEEK_SET (ret=%d).\n", __func__, (int) ret);
TEST_ASSERT_MESSAGE(ret == 0, fsfat_basic_msg_g);
}
if ((ret = fseek (fp, (long) (i >= 128 ? -128 : 128), SEEK_CUR))) {
FSFAT_BASIC_MSG(fsfat_basic_msg_g, FSFAT_BASIC_MSG_BUF_SIZE, "%s: Error: Cannot SEEK_CUR (ret=%d).\n", __func__, (int) ret);
TEST_ASSERT_MESSAGE(ret == 0, fsfat_basic_msg_g);
}
if ((j = getc (fp)) != (i >= 128 ? i - 128 : i + 128)) {
FSFAT_BASIC_MSG(fsfat_basic_msg_g, FSFAT_BASIC_MSG_BUF_SIZE, "%s: Error: Cannot SEEK_CUR (j=%d).\n", __func__, j);
TEST_ASSERT_MESSAGE(ret == 0, fsfat_basic_msg_g);
}
}
fclose (fp);
remove(sd_file_path);
return CaseNext;
}
/** @brief test_rdwr.c test ported from glibc project. See the licence at REF_LICENCE_GLIBC.
*
* WARNING: this test does not currently work. See WARNING comments below.
*
* @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
*/
static control_t fsfat_basic_test_02()
{
static const char hello[] = "Hello, world.\n";
static const char replace[] = "Hewwo, world.\n";
static const size_t replace_from = 2, replace_to = 4;
const char *filename = sd_file_path;
char buf[BUFSIZ];
FILE *f;
int lose = 0;
int32_t ret = 0;
char *rets = NULL;
FSFAT_FENTRYLOG("%s:entered\n", __func__);
f = fopen(filename, "w+");
if (f == NULL) {
FSFAT_BASIC_MSG(fsfat_basic_msg_g, FSFAT_BASIC_MSG_BUF_SIZE, "%s: Error: Cannot open file for writing (filename=%s).\n", __func__, filename);
TEST_ASSERT_MESSAGE(false, fsfat_basic_msg_g);
}
ret = fputs(hello, f);
if (ret == EOF) {
FSFAT_BASIC_MSG(fsfat_basic_msg_g, FSFAT_BASIC_MSG_BUF_SIZE, "%s: Error: fputs() failed to write string to file (filename=%s, string=%s).\n", __func__, filename, hello);
TEST_ASSERT_MESSAGE(false, fsfat_basic_msg_g);
}
rewind(f);
rets = fgets(buf, sizeof(buf), f);
if (rets == NULL) {
FSFAT_BASIC_MSG(fsfat_basic_msg_g, FSFAT_BASIC_MSG_BUF_SIZE, "%s: Error: fgets() failed to get string from file (filename=%s).\n", __func__, filename);
TEST_ASSERT_MESSAGE(false, fsfat_basic_msg_g);
}
rets = NULL;
rewind(f);
ret = fputs(buf, f);
if (ret == EOF) {
FSFAT_BASIC_MSG(fsfat_basic_msg_g, FSFAT_BASIC_MSG_BUF_SIZE, "%s: Error: fputs() failed to write string to file (filename=%s, string=%s).\n", __func__, filename, buf);
TEST_ASSERT_MESSAGE(false, fsfat_basic_msg_g);
}
rewind(f);
{
register size_t i;
for (i = 0; i < replace_from; ++i)
{
int c = getc(f);
if (c == EOF)
{
FSFAT_DBGLOG("EOF at %u.\n", i);
lose = 1;
break;
}
else if (c != hello[i])
{
FSFAT_DBGLOG("Got '%c' instead of '%c' at %u.\n",
(unsigned char) c, hello[i], i);
lose = 1;
break;
}
}
}
/* WARNING: printf("%s: here1. (lose = %d)\n", __func__, lose); */
{
long int where = ftell(f);
if (where == replace_from)
{
register size_t i;
for (i = replace_from; i < replace_to; ++i) {
if (putc(replace[i], f) == EOF) {
FSFAT_DBGLOG("putc('%c') got %s at %u.\n",
replace[i], strerror(errno), i);
lose = 1;
break;
}
/* WARNING: The problem seems to be that putc() is not writing the 'w' chars into the file
* FSFAT_DBGLOG("%s: here1.5. (char = %c, char as int=%d, ret=%d) \n", __func__, replace[i], (int) replace[i], ret);
*/
}
}
else if (where == -1L)
{
FSFAT_DBGLOG("ftell got %s (should be at %u).\n",
strerror(errno), replace_from);
lose = 1;
}
else
{
FSFAT_DBGLOG("ftell returns %ld; should be %u.\n", where, replace_from);
lose = 1;
}
}
if (!lose)
{
rewind(f);
memset(buf, 0, BUFSIZ);
if (fgets(buf, sizeof(buf), f) == NULL)
{
FSFAT_DBGLOG("fgets got %s.\n", strerror(errno));
lose = 1;
}
else if (strcmp(buf, replace))
{
FSFAT_DBGLOG("Read \"%s\" instead of \"%s\".\n", buf, replace);
lose = 1;
}
}
if (lose) {
FSFAT_BASIC_MSG(fsfat_basic_msg_g, FSFAT_BASIC_MSG_BUF_SIZE, "%s: Error: Test Failed. Losing file (filename=%s).\n", __func__, filename);
TEST_ASSERT_MESSAGE(false, fsfat_basic_msg_g);
}
remove(filename);
return CaseNext;
}
/** @brief temptest.c test ported from glibc project. See the licence at REF_LICENCE_GLIBC.
*
* tmpnam() is currently not implemented
*
* @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
*/
static control_t fsfat_basic_test_03()
{
char *fn = NULL;
FSFAT_FENTRYLOG("%s:entered\n", __func__);
fn = tmpnam((char *) NULL);
FSFAT_BASIC_MSG(fsfat_basic_msg_g, FSFAT_BASIC_MSG_BUF_SIZE, "%s: Error: appeared to generate a filename when function is not implemented.\n", __func__);
TEST_ASSERT_MESSAGE(fn == NULL, fsfat_basic_msg_g);
return CaseNext;
}
static bool fsfat_basic_fileno_check(const char *name, FILE *stream, int fd)
{
/* ARMCC stdio.h currently does not define fileno() */
#ifndef __ARMCC_VERSION
int sfd = fileno (stream);
FSFAT_DBGLOG("(fileno (%s) = %d) %c= %d\n", name, sfd, sfd == fd ? '=' : '!', fd);
if (sfd == fd) {
return true;
} else {
return false;
}
#else
/* For ARMCC behave as though test had passed. */
return true;
#endif /* __ARMCC_VERSION */
}
/* defines for next test case */
#ifndef STDIN_FILENO
#define STDIN_FILENO 0
#endif
#ifndef STDOUT_FILENO
#define STDOUT_FILENO 1
#endif
#ifndef STDERR_FILENO
#define STDERR_FILENO 2
#endif
/** @brief tst-fileno.c test ported from glibc project. See the licence at REF_LICENCE_GLIBC.
*
* WARNING: this test does not currently work. See WARNING comments below.
*
*
* @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
*/
static control_t fsfat_basic_test_04()
{
/* ARMCC stdio.h currently does not define fileno() */
#ifndef __ARMCC_VERSION
int ret = -1;
ret = fsfat_basic_fileno_check("stdin", stdin, STDIN_FILENO);
FSFAT_BASIC_MSG(fsfat_basic_msg_g, FSFAT_BASIC_MSG_BUF_SIZE, "%s: Error: stdin does not have expected file number (expected=%d, fileno=%d.\n", __func__, (int) stdin, fileno(stdin));
TEST_ASSERT_MESSAGE(ret == true, fsfat_basic_msg_g);
ret = fsfat_basic_fileno_check("stdout", stdout, STDOUT_FILENO);
FSFAT_BASIC_MSG(fsfat_basic_msg_g, FSFAT_BASIC_MSG_BUF_SIZE, "%s: Error: stdout does not have expected file number (expected=%d, fileno=%d.\n", __func__, (int) stdout, fileno(stdout));
TEST_ASSERT_MESSAGE(ret == true, fsfat_basic_msg_g);
ret = fsfat_basic_fileno_check("stderr", stderr, STDERR_FILENO);
FSFAT_BASIC_MSG(fsfat_basic_msg_g, FSFAT_BASIC_MSG_BUF_SIZE, "%s: Error: stderr does not have expected file number (expected=%d, fileno=%d.\n", __func__, (int) stderr, fileno(stderr));
TEST_ASSERT_MESSAGE(ret == true, fsfat_basic_msg_g);
#endif /* __ARMCC_VERSION */
return CaseNext;
}
/** @brief basic test to opendir() on a directory.
*
* This test has been ported from armmbed/mbed-os/features/unsupported/tests/mbed/dir_sd/main.cpp.
*
* @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
*/
static control_t fsfat_basic_test_05()
{
FILE *f;
const char *str = FSFAT_BASIC_TEST_05_TEST_STRING;
int ret = 0;
FSFAT_DBGLOG("%s:Write files\n", __func__);
char filename[32];
for (int i = 0; i < 10; i++) {
sprintf(filename, "/sd/test_%d.txt", i);
FSFAT_DBGLOG("Creating file: %s\n", filename);
f = fopen(filename, "w");
FSFAT_BASIC_MSG(fsfat_basic_msg_g, FSFAT_BASIC_MSG_BUF_SIZE, "%s: Error: fopen() failed.\n", __func__);
TEST_ASSERT_MESSAGE(f != NULL, fsfat_basic_msg_g);
ret = fprintf(f, str);
FSFAT_BASIC_MSG(fsfat_basic_msg_g, FSFAT_BASIC_MSG_BUF_SIZE, "%s: Error: writing file.\n", __func__);
TEST_ASSERT_MESSAGE(ret == (int) strlen(str), fsfat_basic_msg_g);
ret = fclose(f);
FSFAT_BASIC_MSG(fsfat_basic_msg_g, FSFAT_BASIC_MSG_BUF_SIZE, "%s: Error: fclose() failed.\n", __func__);
TEST_ASSERT_MESSAGE(ret == 0, fsfat_basic_msg_g);
}
FSFAT_DBGLOG("%s:List files:\n", __func__);
DIR *d = opendir("/sd");
FSFAT_BASIC_MSG(fsfat_basic_msg_g, FSFAT_BASIC_MSG_BUF_SIZE, "%s: Error: opendir() failed.\n", __func__);
TEST_ASSERT_MESSAGE(d != NULL, fsfat_basic_msg_g);
struct dirent *p;
while ((p = readdir(d)) != NULL)
FSFAT_DBGLOG("%s\n", p->d_name);
closedir(d);
return CaseNext;
}
/** @brief basic test to write a file to sd card, and read it back again
*
* This test has been ported from armmbed/mbed-os/features/unsupported/tests/mbed/file/main.cpp.
*
* @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
*/
static control_t fsfat_basic_test_06()
{
int ret = -1;
char mac[16];
mbed_mac_address(mac);
FSFAT_DBGLOG("mac address: %02x,%02x,%02x,%02x,%02x,%02x\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
FILE *f;
const char *str = FSFAT_BASIC_TEST_05_TEST_STRING;
int str_len = strlen(FSFAT_BASIC_TEST_05_TEST_STRING);
f = fopen(sd_file_path, "w");
FSFAT_BASIC_MSG(fsfat_basic_msg_g, FSFAT_BASIC_MSG_BUF_SIZE, "%s: Error: fopen() failed.\n", __func__);
TEST_ASSERT_MESSAGE(f != NULL, fsfat_basic_msg_g);
ret = fprintf(f, str);
FSFAT_BASIC_MSG(fsfat_basic_msg_g, FSFAT_BASIC_MSG_BUF_SIZE, "%s: Error: writing file.\n", __func__);
TEST_ASSERT_MESSAGE(ret == (int) strlen(str), fsfat_basic_msg_g);
ret = fclose(f);
FSFAT_BASIC_MSG(fsfat_basic_msg_g, FSFAT_BASIC_MSG_BUF_SIZE, "%s: Error: fclose() failed.\n", __func__);
TEST_ASSERT_MESSAGE(ret == 0, fsfat_basic_msg_g);
// Read
f = fopen(sd_file_path, "r");
FSFAT_BASIC_MSG(fsfat_basic_msg_g, FSFAT_BASIC_MSG_BUF_SIZE, "%s: Error: fopen() failed.\n", __func__);
TEST_ASSERT_MESSAGE(f != NULL, fsfat_basic_msg_g);
int n = fread(fsfat_basic_buffer, sizeof(unsigned char), str_len, f);
FSFAT_BASIC_MSG(fsfat_basic_msg_g, FSFAT_BASIC_MSG_BUF_SIZE, "%s: Error: fread() failed.\n", __func__);
TEST_ASSERT_MESSAGE(n == str_len, fsfat_basic_msg_g);
ret = fclose(f);
FSFAT_BASIC_MSG(fsfat_basic_msg_g, FSFAT_BASIC_MSG_BUF_SIZE, "%s: Error: fclose() failed.\n", __func__);
TEST_ASSERT_MESSAGE(ret == 0, fsfat_basic_msg_g);
return CaseNext;
}
/** @brief basic test to write a file to sd card.
*
* This test has been ported from armmbed/mbed-os/features/unsupported/tests/mbed/sd/main.cpp.
*
* @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
*/
static control_t fsfat_basic_test_07()
{
uint8_t data_written[FSFAT_BASIC_DATA_SIZE] = { 0 };
// Fill data_written buffer with random data
// Write these data into the file
bool write_result = false;
{
FSFAT_DBGLOG("%s:SD: Writing ... ", __func__);
FILE *f = fopen(sd_file_path, "w");
if (f) {
for (int i = 0; i < FSFAT_BASIC_DATA_SIZE; i++) {
data_written[i] = rand() % 0XFF;
fprintf(f, "%c", data_written[i]);
}
write_result = true;
fclose(f);
}
FSFAT_DBGLOG("[%s]\n", write_result ? "OK" : "FAIL");
FSFAT_BASIC_MSG(fsfat_basic_msg_g, FSFAT_BASIC_MSG_BUF_SIZE, "%s: Error: unexpected write failure.\n", __func__);
TEST_ASSERT_MESSAGE(write_result == true, fsfat_basic_msg_g);
}
// Read back the data from the file and store them in data_read
bool read_result = false;
{
FSFAT_DBGLOG("%s:SD: Reading data ... ", __func__);
FILE *f = fopen(sd_file_path, "r");
if (f) {
read_result = true;
for (int i = 0; i < FSFAT_BASIC_DATA_SIZE; i++) {
uint8_t data = fgetc(f);
if (data != data_written[i]) {
read_result = false;
break;
}
}
fclose(f);
}
FSFAT_DBGLOG("[%s]\n", read_result ? "OK" : "FAIL");
FSFAT_BASIC_MSG(fsfat_basic_msg_g, FSFAT_BASIC_MSG_BUF_SIZE, "%s: Error: unexpected read failure.\n", __func__);
TEST_ASSERT_MESSAGE(read_result == true, fsfat_basic_msg_g);
}
return CaseNext;
}
static bool fsfat_basic_test_file_write_fhandle(const char *filename, const int kib_rw)
{
int ret = -1;
File file;
ret = file.open(&fs, filename, O_WRONLY | O_CREAT | O_TRUNC);
FSFAT_BASIC_MSG(fsfat_basic_msg_g, FSFAT_BASIC_MSG_BUF_SIZE, "%s: Error: failed to open file.\n", __func__);
TEST_ASSERT_MESSAGE(ret == 0, fsfat_basic_msg_g);
int byte_write = 0;
fsfat_basic_timer.start();
for (int i = 0; i < kib_rw; i++) {
ret = file.write(fsfat_basic_buffer, sizeof(fsfat_basic_buffer));
FSFAT_BASIC_MSG(fsfat_basic_msg_g, FSFAT_BASIC_MSG_BUF_SIZE, "%s: Error: failed to write to file.\n", __func__);
TEST_ASSERT_MESSAGE(ret == sizeof(fsfat_basic_buffer), fsfat_basic_msg_g);
byte_write++;
}
fsfat_basic_timer.stop();
file.close();
#ifdef FSFAT_DEBUG
double test_time_sec = fsfat_basic_timer.read_us() / 1000000.0;
double speed = kib_rw / test_time_sec;
FSFAT_DBGLOG("%d KiB write in %.3f sec with speed of %.4f KiB/s\n", byte_write, test_time_sec, speed);
#endif
fsfat_basic_timer.reset();
return true;
}
static bool fsfat_basic_test_file_read_fhandle(const char *filename, const int kib_rw)
{
int ret = -1;
File file;
ret = file.open(&fs, filename, O_RDONLY);
FSFAT_BASIC_MSG(fsfat_basic_msg_g, FSFAT_BASIC_MSG_BUF_SIZE, "%s: Error: failed to open file.\n", __func__);
TEST_ASSERT_MESSAGE(ret == 0, fsfat_basic_msg_g);
fsfat_basic_timer.start();
int byte_read = 0;
while (file.read(fsfat_basic_buffer, sizeof(fsfat_basic_buffer)) == sizeof(fsfat_basic_buffer)) {
byte_read++;
}
fsfat_basic_timer.stop();
file.close();
#ifdef FSFAT_DEBUG
double test_time_sec = fsfat_basic_timer.read_us() / 1000000.0;
double speed = kib_rw / test_time_sec;
FSFAT_DBGLOG("%d KiB read in %.3f sec with speed of %.4f KiB/s\n", byte_read, test_time_sec, speed);
#endif
fsfat_basic_timer.reset();
return true;
}
static char fsfat_basic_test_random_char()
{
return rand() % 100;
}
/** @brief basic sd card performance test
*
* This test has been ported from armmbed/mbed-os/features/unsupported/tests/mbed/sd_perf_handle/main.cpp.
*
* @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
*/
static control_t fsfat_basic_test_08()
{
// Test header
FSFAT_DBGLOG("\n%s:SD Card FileHandle Performance Test\n", __func__);
FSFAT_DBGLOG("File name: %s\n", fsfat_basic_bin_filename);
FSFAT_DBGLOG("Buffer size: %d KiB\n", (FSFAT_BASIC_KIB_RW * sizeof(fsfat_basic_buffer)) / 1024);
// Initialize buffer
srand(0);
char *buffer_end = fsfat_basic_buffer + sizeof(fsfat_basic_buffer);
std::generate (fsfat_basic_buffer, buffer_end, fsfat_basic_test_random_char);
bool result = true;
for (;;) {
FSFAT_DBGLOG("%s:Write test...\n", __func__);
if (fsfat_basic_test_file_write_fhandle(fsfat_basic_bin_filename_test_08, FSFAT_BASIC_KIB_RW) == false) {
result = false;
break;
}
FSFAT_DBGLOG("%s:Read test...\n", __func__);
if (fsfat_basic_test_file_read_fhandle(fsfat_basic_bin_filename_test_08, FSFAT_BASIC_KIB_RW) == false) {
result = false;
break;
}
break;
}
TEST_ASSERT_MESSAGE(result == true, "something went wrong");
return CaseNext;
}
bool fsfat_basic_test_sf_file_write_stdio(const char *filename, const int kib_rw)
{
int ret = -1;
FILE* file = fopen(filename, "w");
FSFAT_BASIC_MSG(fsfat_basic_msg_g, FSFAT_BASIC_MSG_BUF_SIZE, "%s: Error: failed to open file.\n", __func__);
TEST_ASSERT_MESSAGE(file != NULL, fsfat_basic_msg_g);
int byte_write = 0;
fsfat_basic_timer.start();
for (int i = 0; i < kib_rw; i++) {
ret = fwrite(fsfat_basic_buffer, sizeof(char), sizeof(fsfat_basic_buffer), file);
FSFAT_BASIC_MSG(fsfat_basic_msg_g, FSFAT_BASIC_MSG_BUF_SIZE, "%s: Error: failed to write to file.\n", __func__);
TEST_ASSERT_MESSAGE(ret == sizeof(fsfat_basic_buffer), fsfat_basic_msg_g);
byte_write++;
}
fsfat_basic_timer.stop();
fclose(file);
#ifdef FSFAT_DEBUG
double test_time_sec = fsfat_basic_timer.read_us() / 1000000.0;
double speed = kib_rw / test_time_sec;
FSFAT_DBGLOG("%d KiB write in %.3f sec with speed of %.4f KiB/s\n", byte_write, test_time_sec, speed);
#endif
fsfat_basic_timer.reset();
return true;
}
bool fsfat_basic_test_sf_file_read_stdio(const char *filename, const int kib_rw)
{
FILE* file = fopen(filename, "r");
FSFAT_BASIC_MSG(fsfat_basic_msg_g, FSFAT_BASIC_MSG_BUF_SIZE, "%s: Error: failed to open file.\n", __func__);
TEST_ASSERT_MESSAGE(file != NULL, fsfat_basic_msg_g);
fsfat_basic_timer.start();
int byte_read = 0;
while (fread(fsfat_basic_buffer, sizeof(char), sizeof(fsfat_basic_buffer), file) == sizeof(fsfat_basic_buffer)) {
byte_read++;
}
fsfat_basic_timer.stop();
fclose(file);
#ifdef FSFAT_DEBUG
double test_time_sec = fsfat_basic_timer.read_us() / 1000000.0;
double speed = kib_rw / test_time_sec;
FSFAT_DBGLOG("%d KiB read in %.3f sec with speed of %.4f KiB/s\n", byte_read, test_time_sec, speed);
#endif
fsfat_basic_timer.reset();
return true;
}
/** @brief basic test to write a file to sd card.
*
* This test has been ported from armmbed/mbed-os/features/unsupported/tests/mbed/sd_perf_stdio/main.cpp.
*
* @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
*/
static control_t fsfat_basic_test_09()
{
// Test header
FSFAT_DBGLOG("\n%s:SD Card Stdio Performance Test\n", __func__);
FSFAT_DBGLOG("File name: %s\n", fsfat_basic_bin_filename);
FSFAT_DBGLOG("Buffer size: %d KiB\n", (FSFAT_BASIC_KIB_RW * sizeof(fsfat_basic_buffer)) / 1024);
// Initialize buffer
srand(0);
char *buffer_end = fsfat_basic_buffer + sizeof(fsfat_basic_buffer);
std::generate (fsfat_basic_buffer, buffer_end, fsfat_basic_test_random_char);
bool result = true;
for (;;) {
FSFAT_DBGLOG("%s:Write test...\n", __func__);
if (fsfat_basic_test_sf_file_write_stdio(fsfat_basic_bin_filename, FSFAT_BASIC_KIB_RW) == false) {
result = false;
break;
}
FSFAT_DBGLOG("%s:Read test...\n", __func__);
if (fsfat_basic_test_sf_file_read_stdio(fsfat_basic_bin_filename, FSFAT_BASIC_KIB_RW) == false) {
result = false;
break;
}
break;
}
TEST_ASSERT_MESSAGE(result == true, "Expected true result not found");
return CaseNext;
}
bool fsfat_basic_test_file_write_fatfs(const char *filename, const int kib_rw)
{
FIL file;
FRESULT res = f_open(&file, filename, FA_WRITE | FA_CREATE_ALWAYS);
FSFAT_BASIC_MSG(fsfat_basic_msg_g, FSFAT_BASIC_MSG_BUF_SIZE, "%s: Error: failed to open file.\n", __func__);
TEST_ASSERT_MESSAGE(res == FR_OK, fsfat_basic_msg_g);
int byte_write = 0;
unsigned int bytes = 0;
fsfat_basic_timer.start();
for (int i = 0; i < kib_rw; i++) {
res = f_write(&file, fsfat_basic_buffer, sizeof(fsfat_basic_buffer), &bytes);
FSFAT_BASIC_MSG(fsfat_basic_msg_g, FSFAT_BASIC_MSG_BUF_SIZE, "%s: Error: failed to write to file.\n", __func__);
TEST_ASSERT_MESSAGE(res == FR_OK, fsfat_basic_msg_g);
byte_write++;
}
fsfat_basic_timer.stop();
f_close(&file);
#ifdef FSFAT_DEBUG
double test_time_sec = fsfat_basic_timer.read_us() / 1000000.0;
double speed = kib_rw / test_time_sec;
FSFAT_DBGLOG("%d KiB write in %.3f sec with speed of %.4f KiB/s\n", byte_write, test_time_sec, speed);
#endif
fsfat_basic_timer.reset();
return true;
}
bool fsfat_basic_test_file_read_fatfs(const char *filename, const int kib_rw)
{
FIL file;
FRESULT res = f_open(&file, filename, FA_READ | FA_OPEN_EXISTING);
FSFAT_BASIC_MSG(fsfat_basic_msg_g, FSFAT_BASIC_MSG_BUF_SIZE, "%s: Error: failed to open file.\n", __func__);
TEST_ASSERT_MESSAGE(res == FR_OK, fsfat_basic_msg_g);
fsfat_basic_timer.start();
int byte_read = 0;
unsigned int bytes = 0;
do {
res = f_read(&file, fsfat_basic_buffer, sizeof(fsfat_basic_buffer), &bytes);
byte_read++;
} while (res == FR_OK && bytes == sizeof(fsfat_basic_buffer));
fsfat_basic_timer.stop();
f_close(&file);
#ifdef FSFAT_DEBUG
double test_time_sec = fsfat_basic_timer.read_us() / 1000000.0;
double speed = kib_rw / test_time_sec;
FSFAT_DBGLOG("%d KiB read in %.3f sec with speed of %.4f KiB/s\n", byte_read, test_time_sec, speed);
#endif
fsfat_basic_timer.reset();
return true;
}
/** @brief basic test to write a file to sd card.
*
* This test has been ported from armmbed/mbed-os/features/unsupported/tests/mbed/sd_perf_stdio/main.cpp.
*
* @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
*/
static control_t fsfat_basic_test_10()
{
// Test header
FSFAT_DBGLOG("\n%sSD Card FatFS Performance Test\n", __func__);
FSFAT_DBGLOG("File name: %s\n", fsfat_basic_bin_filename_test_10);
FSFAT_DBGLOG("Buffer size: %d KiB\n", (FSFAT_BASIC_KIB_RW * sizeof(fsfat_basic_buffer)) / 1024);
// Initialize buffer
srand(1);
char *buffer_end = fsfat_basic_buffer + sizeof(fsfat_basic_buffer);
std::generate (fsfat_basic_buffer, buffer_end, fsfat_basic_test_random_char);
bool result = true;
for (;;) {
FSFAT_DBGLOG("%s:Write test...\n", __func__);
if (fsfat_basic_test_file_write_fatfs(fsfat_basic_bin_filename_test_10, FSFAT_BASIC_KIB_RW) == false) {
result = false;
break;
}
FSFAT_DBGLOG("%s:Read test...\n", __func__);
if (fsfat_basic_test_file_read_fatfs(fsfat_basic_bin_filename_test_10, FSFAT_BASIC_KIB_RW) == false) {
result = false;
break;
}
break;
}
TEST_ASSERT_MESSAGE(result == true, "Expected true result not found");
return CaseNext;
}
#else
#define FSFAT_BASIC_TEST_00 fsfat_basic_test_dummy
#define FSFAT_BASIC_TEST_01 fsfat_basic_test_dummy
#define FSFAT_BASIC_TEST_02 fsfat_basic_test_dummy
#define FSFAT_BASIC_TEST_03 fsfat_basic_test_dummy
#define FSFAT_BASIC_TEST_04 fsfat_basic_test_dummy
#define FSFAT_BASIC_TEST_05 fsfat_basic_test_dummy
#define FSFAT_BASIC_TEST_06 fsfat_basic_test_dummy
#define FSFAT_BASIC_TEST_07 fsfat_basic_test_dummy
#define FSFAT_BASIC_TEST_08 fsfat_basic_test_dummy
#define FSFAT_BASIC_TEST_09 fsfat_basic_test_dummy
#define FSFAT_BASIC_TEST_10 fsfat_basic_test_dummy
/** @brief fsfat_basic_test_dummy Dummy test case for testing when platform doesnt have an SDCard installed.
*
* @return success always
*/
static control_t fsfat_basic_test_dummy()
{
printf("Null test\n");
return CaseNext;
}
#endif
utest::v1::status_t greentea_setup(const size_t number_of_cases)
{
GREENTEA_SETUP(300, "default_auto");
return greentea_test_setup_handler(number_of_cases);
}
Case cases[] = {
/* 1 2 3 4 5 6 7 */
/* 1234567890123456789012345678901234567890123456789012345678901234567890 */
Case("FSFAT_BASIC_TEST_00: fopen()/fgetc()/fprintf()/fclose() test.", FSFAT_BASIC_TEST_00),
Case("FSFAT_BASIC_TEST_01: fopen()/fseek()/fclose() test.", FSFAT_BASIC_TEST_01),
/* WARNING: Test case not working but currently not required for PAL support
* Case("FSFAT_BASIC_TEST_02: fopen()/fgets()/fputs()/ftell()/rewind()/remove() test.", FSFAT_BASIC_TEST_02) */
Case("FSFAT_BASIC_TEST_03: tmpnam() test.", FSFAT_BASIC_TEST_03),
Case("FSFAT_BASIC_TEST_04: fileno() test.", FSFAT_BASIC_TEST_04),
Case("FSFAT_BASIC_TEST_05: opendir() basic test.", FSFAT_BASIC_TEST_05),
Case("FSFAT_BASIC_TEST_06: fread()/fwrite() file to sdcard.", FSFAT_BASIC_TEST_06),
Case("FSFAT_BASIC_TEST_07: sdcard fwrite() file test.", FSFAT_BASIC_TEST_07),
Case("FSFAT_BASIC_TEST_08: FATFileSystem::read()/write() test.", FSFAT_BASIC_TEST_08),
Case("FSFAT_BASIC_TEST_09: POSIX FILE API fread()/fwrite() test.", FSFAT_BASIC_TEST_09),
Case("FSFAT_BASIC_TEST_10: ChanFS read()/write()) test.", FSFAT_BASIC_TEST_10),
};
/* Declare your test specification with a custom setup handler */
Specification specification(greentea_setup, cases);
int main()
{
return !Harness::run(specification);
}

View File

@ -0,0 +1,472 @@
#include "mbed.h"
#include "greentea-client/test_env.h"
#include "unity.h"
#include "utest.h"
#include <stdlib.h>
#include <errno.h>
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 SDBlockDevice
#define MBED_TEST_BLOCKDEVICE_DECL SDBlockDevice bd(MBED_CONF_SD_SPI_MOSI, MBED_CONF_SD_SPI_MISO, MBED_CONF_SD_SPI_CLK, MBED_CONF_SD_SPI_CS);
#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);
}

View File

@ -0,0 +1,314 @@
#include "mbed.h"
#include "greentea-client/test_env.h"
#include "unity.h"
#include "utest.h"
#include <stdlib.h>
#include <errno.h>
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 SDBlockDevice
#define MBED_TEST_BLOCKDEVICE_DECL SDBlockDevice bd(MBED_CONF_SD_SPI_MOSI, MBED_CONF_SD_SPI_MISO, MBED_CONF_SD_SPI_CLK, MBED_CONF_SD_SPI_CS);
#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 <int file_size, int write_size, int read_size>
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);
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,184 @@
#include "mbed.h"
#include "greentea-client/test_env.h"
#include "unity.h"
#include "utest.h"
#include <stdlib.h>
#include <errno.h>
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 SDBlockDevice
#define MBED_TEST_BLOCKDEVICE_DECL SDBlockDevice bd(MBED_CONF_SD_SPI_MOSI, MBED_CONF_SD_SPI_MISO, MBED_CONF_SD_SPI_CLK, MBED_CONF_SD_SPI_CS);
#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() {
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);
}

View File

@ -0,0 +1,629 @@
#include "mbed.h"
#include "greentea-client/test_env.h"
#include "unity.h"
#include "utest.h"
#include <stdlib.h>
#include <errno.h>
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 SDBlockDevice
#define MBED_TEST_BLOCKDEVICE_DECL SDBlockDevice bd(MBED_CONF_SD_SPI_MOSI, MBED_CONF_SD_SPI_MISO, MBED_CONF_SD_SPI_CLK, MBED_CONF_SD_SPI_CS);
#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);
}

View File

@ -0,0 +1,214 @@
{
"name": "sd",
"config": {
"SPI_CS": "NC",
"SPI_MOSI": "NC",
"SPI_MISO": "NC",
"SPI_CLK": "NC",
"DEVICE_SPI": 1,
"FSFAT_SDCARD_INSTALLED": 1,
"CMD_TIMEOUT": 10000,
"CMD0_IDLE_STATE_RETRIES": 5,
"SD_INIT_FREQUENCY": 100000
},
"target_overrides": {
"DISCO_F051R8": {
"SPI_MOSI": "SPI_MOSI",
"SPI_MISO": "SPI_MISO",
"SPI_CLK": "SPI_SCK",
"SPI_CS": "SPI_CS"
},
"DISCO_L475VG_IOT01A": {
"SPI_MOSI": "SPI_MOSI",
"SPI_MISO": "SPI_MISO",
"SPI_CLK": "SPI_SCK",
"SPI_CS": "SPI_CS"
},
"DISCO_L476VG": {
"SPI_MOSI": "PE_15",
"SPI_MISO": "PE_14",
"SPI_CLK": "PE_13",
"SPI_CS": "PE_12"
},
"K20D50M": {
"SPI_MOSI": "PTD2",
"SPI_MISO": "PTD3",
"SPI_CLK": "PTD1",
"SPI_CS": "PTC2"
},
"KL22F": {
"SPI_MOSI": "PTD6",
"SPI_MISO": "PTD7",
"SPI_CLK": "PTD5",
"SPI_CS": "PTD4"
},
"KL25Z": {
"SPI_MOSI": "PTD2",
"SPI_MISO": "PTD3",
"SPI_CLK": "PTD1",
"SPI_CS": "PTD0"
},
"KL43Z": {
"SPI_MOSI": "PTD6",
"SPI_MISO": "PTD7",
"SPI_CLK": "PTD5",
"SPI_CS": "PTD4"
},
"KL46Z": {
"SPI_MOSI": "PTD6",
"SPI_MISO": "PTD7",
"SPI_CLK": "PTD5",
"SPI_CS": "PTD4"
},
"K64F": {
"SPI_MOSI": "PTE3",
"SPI_MISO": "PTE1",
"SPI_CLK": "PTE2",
"SPI_CS": "PTE4"
},
"K66F": {
"SPI_MOSI": "PTE3",
"SPI_MISO": "PTE1",
"SPI_CLK": "PTE2",
"SPI_CS": "PTE4"
},
"LPC11U37H_401": {
"SPI_MOSI": "SDMOSI",
"SPI_MISO": "SDMISO",
"SPI_CLK": "SDSCLK",
"SPI_CS": "SDSSEL"
},
"LPC2368": {
"SPI_MOSI": "p11",
"SPI_MISO": "p12",
"SPI_CLK": "p13",
"SPI_CS": "p14"
},
"NUCLEO_F411RE": {
"SPI_MOSI": "PC_3",
"SPI_MISO": "PC_2",
"SPI_CLK": "PC_7",
"SPI_CS": "PB_9"
},
"NUCLEO_F429ZI": {
"SPI_MOSI": "PC_12",
"SPI_MISO": "PC_11",
"SPI_CLK": "PC_10",
"SPI_CS": "PA_15"
},
"DISCO_F429ZI": {
"SPI_MOSI": "PC_12",
"SPI_MISO": "PC_11",
"SPI_CLK": "PC_10",
"SPI_CS": "PA_15"
},
"NUCLEO_F746ZG": {
"SPI_MOSI": "PC_12",
"SPI_MISO": "PC_11",
"SPI_CLK": "PC_10",
"SPI_CS": "PA_15"
},
"NUCLEO_F767ZI": {
"SPI_MOSI": "PC_12",
"SPI_MISO": "PC_11",
"SPI_CLK": "PC_10",
"SPI_CS": "PA_15"
},
"NUCLEO_L031K6": {
"SPI_MOSI": "SPI_MOSI",
"SPI_MISO": "SPI_MISO",
"SPI_CLK": "SPI_SCK",
"SPI_CS": "SPI_CS"
},
"NUCLEO_L476RG": {
"SPI_MOSI": "SPI_MOSI",
"SPI_MISO": "SPI_MISO",
"SPI_CLK": "SPI_SCK",
"SPI_CS": "SPI_CS"
},
"NUMAKER_PFM_M453": {
"SPI_MOSI": "PD_13",
"SPI_MISO": "PD_14",
"SPI_CLK": "PD_15",
"SPI_CS": "PD_12"
},
"NUMAKER_PFM_M487": {
"SPI_MOSI": "D11",
"SPI_MISO": "D12",
"SPI_CLK": "D13",
"SPI_CS": "D10"
},
"NUMAKER_PFM_NUC472": {
"SPI_MOSI": "PF_0",
"SPI_MISO": "PD_15",
"SPI_CLK": "PD_14",
"SPI_CS": "PD_13"
},
"nRF51822": {
"SPI_MOSI": "p12",
"SPI_MISO": "p13",
"SPI_CLK": "p15",
"SPI_CS": "p14"
},
"UBLOX_C030_U201": {
"SPI_MOSI": "D11",
"SPI_MISO": "D12",
"SPI_CLK": "D13",
"SPI_CS": "D10"
},
"UBLOX_EVK_ODIN_W2": {
"SPI_CS": "D9",
"SPI_MOSI": "D11",
"SPI_MISO": "D12",
"SPI_CLK": "D13"
},
"MTB_UBLOX_ODIN_W2": {
"SPI_CS": "PG_4",
"SPI_MOSI": "PE_14",
"SPI_MISO": "PE_13",
"SPI_CLK": "PE_12"
},
"RZ_A1H": {
"SPI_MOSI": "P8_5",
"SPI_MISO": "P8_6",
"SPI_CLK": "P8_3",
"SPI_CS": "P8_4"
},
"GR_LYCHEE": {
"SPI_MOSI": "P5_6",
"SPI_MISO": "P5_7",
"SPI_CLK": "P5_4",
"SPI_CS": "P5_5"
},
"HEXIWEAR": {
"SPI_MOSI": "PTE3",
"SPI_MISO": "PTE1",
"SPI_CLK": "PTE2",
"SPI_CS": "PTE4"
},
"MTB_MTS_DRAGONFLY": {
"SPI_MOSI": "SPI2_MOSI",
"SPI_MISO": "SPI2_MISO",
"SPI_CLK": "SPI2_SCK",
"SPI_CS": "SPI_CS2"
},
"TB_SENSE_12": {
"SPI_MOSI": "PC6",
"SPI_MISO": "PC7",
"SPI_CLK": "PC8",
"SPI_CS": "PC9"
},
"LPC1768": {
"SPI_MOSI": "p5",
"SPI_MISO": "p6",
"SPI_CLK": "p7",
"SPI_CS": "p8"
},
"REALTEK_RTL8195AM": {
"SPI_MOSI": "D11",
"SPI_MISO": "D12",
"SPI_CLK": "D13",
"SPI_CS": "D9"
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 502 KiB

View File

@ -0,0 +1,88 @@
/** @file fsfat_debug.h
*
* component debug header file.
*/
#ifndef __FSFAT_DEBUG
#define __FSFAT_DEBUG
#include <stdint.h>
#include <assert.h>
#include <stdio.h>
/* 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 <core-util/assert.h>
#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*/

View File

@ -0,0 +1,117 @@
/* @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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <inttypes.h>
#include <ctype.h>
#ifdef FSFAT_DEBUG
uint32_t fsfat_optDebug_g = 1;
uint32_t fsfat_optLogLevel_g = FSFAT_LOG_NONE; /*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;
}

View File

@ -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 <stdint.h>
#include <stdlib.h>
#include <stdbool.h>
#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 */