mirror of https://github.com/ARMmbed/mbed-os.git
Removal of SD card driver (SDBlockDevice module) and related test cases (moved into https://github.com/ARMmbed/sd-driver repository).
parent
a79062f876
commit
b8e31c8156
|
@ -1,536 +0,0 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "mbed.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>
|
||||
/* retarget.h is included after errno.h so symbols are mapped to
|
||||
* consistent values for all toolchains */
|
||||
#include "platform/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.
|
||||
* FSFAT_SDCARD_INSTALLTED
|
||||
* 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 uncomment the #define FSFAT_SDCARD_INSTALLED directive for the target.
|
||||
*
|
||||
* Notes
|
||||
* The following 2 lines should be instated to perform the tests in this file:
|
||||
* #define FSFAT_SDCARD_INSTALLED
|
||||
* #define DEVICE_SPI
|
||||
*/
|
||||
#if defined(DEVICE_SPI) && defined(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_MSG_BUF_SIZE 256
|
||||
|
||||
static const char *sd_file_path = "/sd/out.txt";
|
||||
static const char *sd_mount_pt = "sd";
|
||||
const int FSFAT_BASIC_DATA_SIZE = 256;
|
||||
static char fsfat_basic_msg_g[FSFAT_BASIC_MSG_BUF_SIZE];
|
||||
|
||||
|
||||
#if defined(TARGET_KL25Z)
|
||||
SDBlockDevice sd(PTD2, PTD3, PTD1, PTD0);
|
||||
FATFileSystem fs(sd_mount_pt, &sd);
|
||||
|
||||
#elif defined(TARGET_KL46Z) || defined(TARGET_KL43Z)
|
||||
SDBlockDevice sd(PTD6, PTD7, PTD5, PTD4);
|
||||
FATFileSystem fs(sd_mount_pt, &sd);
|
||||
|
||||
#elif defined(TARGET_K64F) || defined(TARGET_K66F)
|
||||
SDBlockDevice sd(PTE3, PTE1, PTE2, PTE4);
|
||||
FATFileSystem fs(sd_mount_pt, &sd);
|
||||
|
||||
#elif defined(TARGET_K22F)
|
||||
SDBlockDevice sd(PTD6, PTD7, PTD5, PTD4);
|
||||
FATFileSystem fs(sd_mount_pt, &sd);
|
||||
|
||||
#elif defined(TARGET_K20D50M)
|
||||
SDBlockDevice sd(PTD2, PTD3, PTD1, PTC2);
|
||||
FATFileSystem fs(sd_mount_pt, &sd);
|
||||
|
||||
#elif defined(TARGET_nRF51822)
|
||||
SDBlockDevice sd(p12, p13, p15, p14);
|
||||
FATFileSystem fs(sd_mount_pt, &sd);
|
||||
|
||||
#elif defined(TARGET_NUCLEO_F030R8) || \
|
||||
defined(TARGET_NUCLEO_F070RB) || \
|
||||
defined(TARGET_NUCLEO_F072RB) || \
|
||||
defined(TARGET_NUCLEO_F091RC) || \
|
||||
defined(TARGET_NUCLEO_F103RB) || \
|
||||
defined(TARGET_NUCLEO_F302R8) || \
|
||||
defined(TARGET_NUCLEO_F303RE) || \
|
||||
defined(TARGET_NUCLEO_F334R8) || \
|
||||
defined(TARGET_NUCLEO_F401RE) || \
|
||||
defined(TARGET_NUCLEO_F410RB) || \
|
||||
defined(TARGET_NUCLEO_F411RE) || \
|
||||
defined(TARGET_NUCLEO_L053R8) || \
|
||||
defined(TARGET_NUCLEO_L073RZ) || \
|
||||
defined(TARGET_NUCLEO_L152RE)
|
||||
SDBlockDevice sd(D11, D12, D13, D10);
|
||||
FATFileSystem fs(sd_mount_pt, &sd);
|
||||
|
||||
#elif defined(TARGET_DISCO_F051R8) || \
|
||||
defined(TARGET_NUCLEO_L031K6)
|
||||
SDBlockDevice sd(SPI_MOSI, SPI_MISO, SPI_SCK, SPI_CS);
|
||||
FATFileSystem fs(sd_mount_pt, &sd);
|
||||
|
||||
#elif defined(TARGET_LPC2368)
|
||||
SDBlockDevice sd(p11, p12, p13, p14);
|
||||
FATFileSystem fs(sd_mount_pt, &sd);
|
||||
|
||||
#elif defined(TARGET_LPC11U68)
|
||||
SDBlockDevice sd(D11, D12, D13, D10);
|
||||
FATFileSystem fs(sd_mount_pt, &sd);
|
||||
|
||||
#elif defined(TARGET_LPC1549)
|
||||
SDBlockDevice sd(D11, D12, D13, D10);
|
||||
FATFileSystem fs(sd_mount_pt, &sd);
|
||||
|
||||
#elif defined(TARGET_RZ_A1H)
|
||||
SDBlockDevice sd(P8_5, P8_6, P8_3, P8_4);
|
||||
FATFileSystem fs(sd_mount_pt, &sd);
|
||||
|
||||
#elif defined(TARGET_LPC11U37H_401)
|
||||
SDBlockDevice sd(SDMOSI, SDMISO, SDSCLK, SDSSEL);
|
||||
FATFileSystem fs(sd_mount_pt, &sd);
|
||||
|
||||
#else
|
||||
#error "[NOT SUPPORTED] Instantiate SDBlockDevice sd(p11, p12, p13, p14) with the correct pin specification for target"
|
||||
#endif
|
||||
|
||||
|
||||
#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__);
|
||||
{
|
||||
printf("SD: Writing ... ");
|
||||
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);
|
||||
}
|
||||
printf("[%s]\r\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
|
||||
{
|
||||
printf("SD: Reading data ... ");
|
||||
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);
|
||||
}
|
||||
printf("[%s]\r\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) {
|
||||
printf("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)
|
||||
{
|
||||
printf("EOF at %u.\n", i);
|
||||
lose = 1;
|
||||
break;
|
||||
}
|
||||
else if (c != hello[i])
|
||||
{
|
||||
printf("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) {
|
||||
printf("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
|
||||
* printf("%s: here1.5. (char = %c, char as int=%d, ret=%d) \n", __func__, replace[i], (int) replace[i], ret);
|
||||
*/
|
||||
}
|
||||
}
|
||||
else if (where == -1L)
|
||||
{
|
||||
printf("ftell got %s (should be at %u).\n",
|
||||
strerror(errno), replace_from);
|
||||
lose = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("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)
|
||||
{
|
||||
printf("fgets got %s.\n", strerror(errno));
|
||||
lose = 1;
|
||||
}
|
||||
else if (strcmp(buf, replace))
|
||||
{
|
||||
printf("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 TOOLCHAIN_ARM_STD
|
||||
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 /* TOOLCHAIN_ARM_STD */
|
||||
}
|
||||
|
||||
/* 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()
|
||||
{
|
||||
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__, 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__, 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__, stderr, fileno(stderr));
|
||||
TEST_ASSERT_MESSAGE(ret == true, fsfat_basic_msg_g);
|
||||
//*/
|
||||
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
|
||||
|
||||
/** @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 /* defined(DEVICE_SPI) && defined(FSFAT_SDCARD_INSTALLED) */
|
||||
|
||||
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),
|
||||
Case("FSFAT_BASIC_TEST_03: tmpnam() test.", FSFAT_BASIC_TEST_03),
|
||||
Case("FSFAT_BASIC_TEST_04: fileno() test.", FSFAT_BASIC_TEST_04),
|
||||
/* 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)
|
||||
*/
|
||||
};
|
||||
|
||||
|
||||
/* Declare your test specification with a custom setup handler */
|
||||
Specification specification(greentea_setup, cases);
|
||||
|
||||
int main()
|
||||
{
|
||||
return !Harness::run(specification);
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -1,312 +0,0 @@
|
|||
# FAT32 Filesystem Support README #
|
||||
|
||||
Simon Hughes
|
||||
|
||||
20170131
|
||||
|
||||
Version 0.03
|
||||
|
||||
|
||||
# Executive Summary
|
||||
|
||||
These notes are intended to help the mbed client team adopt the mbedOS POSIX File API support. The notes cover:
|
||||
|
||||
- Brief notes on how to setup the mbedOS development environment, including links to other resources.
|
||||
- How to build the mbedOS test cases.
|
||||
- How to run the POSIX File API test case.
|
||||
|
||||
Note the following:
|
||||
|
||||
- The mbedOS FAT32/SDCard support implements a POSIX File API for off-chip, persistent file storage.
|
||||
- The FAT32/SDCard support was present in mbedOS 2, but was moved to the "unsupported" area of the source tree in mbedOS 5.
|
||||
This is because there are currently no FAT32/SDCard POSIX API test cases in the public repository, software quality is hence unknown, and the features are therefore unsupported.
|
||||
- The implementation of new test cases is an active development activity. So far, one test binary (basic.cpp) has been implemented and is available on the mbed-os branch called 'feature-storage'. The test case support
|
||||
is being enhanced as a matter of urgency.
|
||||
- The work described here is intended to make the POSIX File API available to the mbed client team before the Christmas holidays.
|
||||
Further test cases will be implemented and when completed, the work will be merged into the public repository master branch. In the meantime,
|
||||
the work is available from feature-storage branch.
|
||||
|
||||
# Getting Started
|
||||
|
||||
This section describes how to build and run the POSIX file API test case. The following steps are covered:
|
||||
|
||||
- [Installing the Tools](#installing-the-tools). This section briefly describes how to setup the mbedos development environment.
|
||||
- [Git Clone the Public mbedOS Repo](#git-clone-the-mbedos-repo). This section describes how to git clone the mbedOS repository containing the FAT32/SDCard and POSIX File API test case of interest.
|
||||
- [Build the mbedOS Test Cases](#build-the-mbedos-test-cases). This section describes how to build the mbedOS test cases.
|
||||
- [Insert a microSD Card Into the K64F](#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 case basic.cpp.
|
||||
|
||||
### <a name="installing-the-tools"></a> Installing the Tools
|
||||
|
||||
The following tools should be installed:
|
||||
|
||||
- arm-none-eabi-gcc. See [mbedOS Development Environment Setup Howto Notes][MBED_DEVENV_NOTES] for guidance.
|
||||
- Python 2.7.9 or later. See [mbedOS Development Environment Setup Howto Notes][MBED_DEVENV_NOTES] for guidance.
|
||||
- mbed Greentea. This is the mbedOS test tool.
|
||||
- Git Bash. See [mbedOS Development Environment Setup Howto Notes][MBED_DEVENV_NOTES] for guidance.
|
||||
- mbed-cli. This is the tool used to make mbedOS application and test builds.
|
||||
|
||||
Using a Git Bash terminal, setup mbed-cli in the following way:
|
||||
|
||||
simhug01@E107851:/d/demo_area$ git clone git@github.com:/armmbed/mbed-cli
|
||||
<trace removed>
|
||||
simhug01@E107851:/d/demo_area$ pushd mbed-cli
|
||||
simhug01@E107851:/d/demo_area/mbed-cli/$ python.exe setup.py install
|
||||
simhug01@E107851:/d/demo_area/mbed-cli/$ popd
|
||||
|
||||
Using a Git Bash terminal, setup Greentea in the following way:
|
||||
|
||||
simhug01@E107851:/d/demo_area$ git clone git@github.com:/armmbed/greentea
|
||||
<trace removed>
|
||||
simhug01@E107851:/d/demo_area$ pushd greentea
|
||||
simhug01@E107851:/d/demo_area/greentea/$ python.exe setup.py install
|
||||
simhug01@E107851:/d/demo_area/greentea/$ popd
|
||||
simhug01@E107851:/d/demo_area/$
|
||||
|
||||
|
||||
### <a name="git-clone-the-mbedos-repo"></a> Git Clone the Public mbedOS Repo
|
||||
|
||||
Get a clone of public mbedOS repository in the following way
|
||||
|
||||
simhug01@E107851:/d/demo_area$ mkdir ex_app1
|
||||
simhug01@E107851:/d/demo_area$ pushd ex_app1
|
||||
simhug01@E107851:/d/demo_area/ex_app1$ git clone git@github.com:/armmbed/mbed-os
|
||||
<trace removed>
|
||||
simhug01@E107851:/d/demo_area/ex_app1$
|
||||
|
||||
|
||||
### <a name="build-the-mbedos-test-cases"></a> Build the mbedOS Test Cases
|
||||
|
||||
Switch to the `feature-storage` branch using the following commands:
|
||||
|
||||
simhug01@E107851:/d/demo_area/ex_app1$ pushd mbed-os
|
||||
simhug01@E107851:/d/demo_area/ex_app1$ git branch
|
||||
* master
|
||||
feature-storage
|
||||
<other branches deleted>
|
||||
simhug01@E107851:/d/demo_area/ex_app1$ git checkout feature-storage
|
||||
Switched to branch 'feature-storage'
|
||||
simhug01@E107851:/d/demo_area/ex_app1$ git branch
|
||||
master
|
||||
* feature-storage
|
||||
<other branches deleted>
|
||||
simhug01@E107851:/d/demo_area/ex_app1$
|
||||
|
||||
Build the test cases for the K64F target using the following commands:
|
||||
|
||||
simhug01@E107851:/d/demo_area/ex_app1$ mbed -v test --compile -t GCC_ARM -m K64F -DFSFAT_SDCARD_INSTALLED 2>&1 | tee build_tests_gcc_20161219_1007.txt
|
||||
<trace removed>
|
||||
simhug01@E107851:/d/demo_area/ex_app1$
|
||||
|
||||
The complete [build log][BUILD-TESTS-GCC-20161219-1007] is available for reference.
|
||||
|
||||
|
||||
### <a name="insert-sdcard-into-k64f"></a> Insert SDCard into K64F
|
||||
|
||||
The test cases have been run on a K64F with the following microSDHC cards:
|
||||
|
||||
- Kingston 2GB mircoSDHC card.
|
||||
- Kingston 8GB mircoSDHC card.
|
||||
- SanDisk 16GB mircoSDHC ultra card.
|
||||
|
||||
If the card requires formatting then the following procedure is known to work:
|
||||
|
||||
- Insert microSD card into SD adapter in USB stick (or similar) so the microSD card can be insert into windows PC.
|
||||
- Within file explorer, right click/Format on the USB drive.
|
||||
- Select FAT32, 4096 cluster size, Quick Format.
|
||||
- Format the drive.
|
||||
|
||||
The microSD card should then be ready for use in the K64F.
|
||||
|
||||
|
||||
### <a name="run-the-posix-file-test-cases"></a> Run the POSIX File Test Case
|
||||
|
||||
To setup for running the test cases, complete the following steps:
|
||||
|
||||
- Insert a micro SDCard into K64F SDCard socket.
|
||||
- Connect the K64F development board to your PC using a suitable USB cable.
|
||||
|
||||
All tests can be run using the following command:
|
||||
|
||||
simhug01@E107851:/d/demo_area/ex_app1$ mbedgt -VS
|
||||
<trace removed>
|
||||
|
||||
However, it's possible to run a particular test case using the following .json file:
|
||||
|
||||
{
|
||||
"builds": {
|
||||
"K64F-GCC_ARM": {
|
||||
"binary_type": "bootable",
|
||||
"tests": {
|
||||
"mbed-os-features-storage-feature_storage-tests-fs-fat-basic": {
|
||||
"binaries": [
|
||||
{
|
||||
"path": "BUILD/tests/K64F/GCC_ARM/mbed-os/features/storage/FEATURE_STORAGE/TESTS/fs-fat/basic/basic.bin"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"toolchain": "GCC_ARM",
|
||||
"base_path": "BUILD/tests/K64F/GCC_ARM",
|
||||
"baud_rate": 9600,
|
||||
"platform": "K64F"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Store the above text in a file called `ex_app1_fat_basic_spec.json` in the ex_app1 directory. The test can be run using the following command:
|
||||
|
||||
simhug01@E107851:/d/demo_area/ex_app1$ mbedgt -VS --test-spec=ex_app1_fat_basic_spec.json 2>&1 | tee run_tests_master_gcc_ex_app2_fat_basic_20161219_1011.txt
|
||||
<trace removed>
|
||||
|
||||
On a successful run, the following table will be shown at the end of the log:
|
||||
|
||||
mbedgt: test suite 'mbed-os-features-storage-feature_storage-tests-fs-fat-basic' ..................... OK in 15.86 sec
|
||||
test case: 'FSFAT_test_00: fopen()/fgetc()/fprintf()/fclose() test.' ......................... OK in 0.90 sec
|
||||
test case: 'FSFAT_test_01: fopen()/fseek()/fclose() test.' ................................... OK in 0.32 sec
|
||||
mbedgt: test case summary: 2 passes, 0 failures
|
||||
mbedgt: all tests finished!
|
||||
mbedgt: shuffle seed: 0.7720862854
|
||||
mbedgt: test suite report:
|
||||
+--------------+---------------+-------------------------------------------------------------+--------+--------------------+-------------+
|
||||
| target | platform_name | test suite | result | elapsed_time (sec) | copy_method |
|
||||
+--------------+---------------+-------------------------------------------------------------+--------+--------------------+-------------+
|
||||
| K64F-GCC_ARM | K64F | mbed-os-features-storage-feature_storage-tests-fs-fat-basic | OK | 15.86 | 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 | mbed-os-features-storage-feature_storage-tests-fs-fat-basic | FSFAT_test_00: fopen()/fgetc()/fprintf()/fclose() test. | 1 | 0 | OK | 0.9 |
|
||||
| K64F-GCC_ARM | K64F | mbed-os-features-storage-feature_storage-tests-fs-fat-basic | FSFAT_test_01: fopen()/fseek()/fclose() test. | 1 | 0 | OK | 0.32 |
|
||||
+--------------+---------------+-------------------------------------------------------------+---------------------------------------------------------+--------+--------+--------+--------------------+
|
||||
mbedgt: test case results: 2 OK
|
||||
mbedgt: completed in 16.53 sec
|
||||
|
||||
|
||||
The full [test output log][RUN-TESTS-GCC-20161219-1011] is available for reference.
|
||||
|
||||
|
||||
# POSIX File API
|
||||
|
||||
mbedOS supports a subset of the POSIX File API, as outlined below:
|
||||
|
||||
- [clearerr()][MAN_CLEARERR].
|
||||
- STATUS: Basic testing implemented. Working.
|
||||
- [fclose()][MAN_FCLOSE].
|
||||
- STATUS: Basic testing implemented. Working.
|
||||
- [ferror()][MAN_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()][MAN_FGETS].
|
||||
- STATUS: Basic testing implemented. Working.
|
||||
- [fgets()][MAN_FGETS].
|
||||
- STATUS: Basic testing implemented. Working.
|
||||
- [fputc()][MAN_FPUTS].
|
||||
- STATUS: Unknown.
|
||||
- [fputs()][MAN_FPUTS].
|
||||
- STATUS: Basic testing implemented. Working.
|
||||
- [fprintf()][MAN_FPRINTF].
|
||||
- STATUS: Basic testing implemented. Working.
|
||||
- [fopen()][MAN_FOPEN].
|
||||
- STATUS: Basic testing implemented. Working.
|
||||
- [freopen()][MAN_FOPEN].
|
||||
- STATUS: This is not tested.
|
||||
- [fread()][MAN_FREAD].
|
||||
- STATUS: Basic testing implemented. Working.
|
||||
- STATUS: n x 25kB stress test working.
|
||||
- [ftell()][MAN_FTELL].
|
||||
- STATUS: Basic testing implemented. Working.
|
||||
- [fwrite()][MAN_FWRITE].
|
||||
- STATUS: Basic testing implemented. Working.
|
||||
- STATUS: n x 25kB stress test working.
|
||||
- [fseek()][MAN_FSEEK]
|
||||
- STATUS: Basic testing implemented. Working.
|
||||
- [getc()][MAN_FGETS].
|
||||
- STATUS: Basic testing implemented. Working.
|
||||
- [gets()][MAN_FGETS].
|
||||
- STATUS: Unknown.
|
||||
- [putc()][MAN_FPUTS].
|
||||
- STATUS: Unknown.
|
||||
- [puts()][MAN_FPUTS].
|
||||
- STATUS: Unknown.
|
||||
- [remove()][MAN_REMOVE]
|
||||
- STATUS: Basic testing implemented. Working.
|
||||
- [rewind()][MAN_REWIND].
|
||||
- STATUS: Basic testing implemented. Working.
|
||||
- [stat()][MAN_STAT]
|
||||
- STATUS: Implemented. Working.
|
||||
- STATUS: Not supported by ARMCC/IAR libc.
|
||||
- tmpfile()
|
||||
- STATUS: Not implemented.
|
||||
- tmpnam()
|
||||
- STATUS: Not implemented.
|
||||
|
||||
Supported directory related operations are as follows:
|
||||
|
||||
- closedir().
|
||||
- STATUS: Implemented. Working.
|
||||
- mkdir().
|
||||
- STATUS: Basic testing implemented. Working.
|
||||
- opendir().
|
||||
- STATUS: Implemented. Working.
|
||||
- readdir().
|
||||
- STATUS: Implemented. Working.
|
||||
- [remove()][MAN_REMOVE]
|
||||
- STATUS: Basic testing implemented. Working.
|
||||
- rename()
|
||||
- STATUS: Implemented. Not tested.
|
||||
- rewinddir().
|
||||
- STATUS: Implemented. Found not to work. Test case not present in repo.
|
||||
- seekdir()
|
||||
- STATUS: Implemented. Found not to work. Test case not present in repo.
|
||||
- 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. This will be extended
|
||||
as further test cases are implemented.
|
||||
|
||||
|
||||
## Miscellaneous Information
|
||||
|
||||
The FAT32/SDCard support is at the following location in the source code tree:
|
||||
|
||||
<mbed-os_src_root>\features\storage\FEATURE_STORAGE\fs
|
||||
|
||||
The FAT32/SDCard test cases are at following locations in the source code tree:
|
||||
|
||||
<mbed-os_src_root>\features\storage\FEATURE_STORAGE\TESTS\filesystem\basic\basic.cpp
|
||||
<mbed-os_src_root>\features\storage\FEATURE_STORAGE\TESTS\filesystem\fopen\fopen.cpp
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# Further Reading
|
||||
|
||||
* The [mbedOS Development Environment Setup Notes][MBED_DEVENV_NOTES].
|
||||
* The example mbedOS build log [BUILD-TESTS-GCC-20161219-1007][BUILD-TESTS-GCC-20161219-1007] for reference.
|
||||
* The example mbedOS test run log [RUN-TESTS-GCC-20161219-1011][RUN-TESTS-GCC-20161219-1011] for reference.
|
||||
|
||||
|
||||
[MBED_DEVENV_NOTES]: https://github.com/ARMmbed/meVo/blob/master/docs/ARM_MBED/TN/ARM_MBED_TN_0017/12-mbed_devenv_setup_how_to_notes.docx
|
||||
[BUILD-TESTS-GCC-20161219-1007]: https://github.com/ARMmbed/meVo/blob/master/docs/ARM_MBED/TN/ARM_MBED_TN_0017/build_tests_gcc_20161219_1007.txt
|
||||
[RUN-TESTS-GCC-20161219-1011]: https://github.com/ARMmbed/meVo/blob/master/docs/ARM_MBED/TN/ARM_MBED_TN_0017/run_tests_master_gcc_ex_app2_fat_basic_20161219_1011.txt
|
||||
|
||||
[MAN_CLEARERR]: https://linux.die.net/man/3/clearerr
|
||||
[MAN_FCLOSE]: https://linux.die.net/man/3/fclose
|
||||
[MAN_FGETS]: https://linux.die.net/man/3/fgets
|
||||
[MAN_FOPEN]: https://linux.die.net/man/3/fopen
|
||||
[MAN_FPRINTF]: https://linux.die.net/man/3/fprintf
|
||||
[MAN_FPUTS]: https://linux.die.net/man/3/fputs
|
||||
[MAN_FREAD]: https://linux.die.net/man/3/fread
|
||||
[MAN_FSEEK]: https://linux.die.net/man/3/fseek
|
||||
[MAN_FWRITE]: https://linux.die.net/man/3/fwrite
|
||||
[MAN_REMOVE]: https://linux.die.net/man/3/remove
|
||||
[MAN_REWIND]: https://linux.die.net/man/3/rewind
|
||||
[MAN_STAT]: https://linux.die.net/man/2/stat
|
||||
[MAN_FTELL]: https://linux.die.net/man/3/ftell
|
|
@ -1,592 +0,0 @@
|
|||
/* mbed Microcontroller Library
|
||||
* Copyright (c) 2006-2012 ARM Limited
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
/* Introduction
|
||||
* ------------
|
||||
* SD and MMC cards support a number of interfaces, but common to them all
|
||||
* is one based on SPI. This is the one I'm implmenting because it means
|
||||
* it is much more portable even though not so performant, and we already
|
||||
* have the mbed SPI Interface!
|
||||
*
|
||||
* The main reference I'm using is Chapter 7, "SPI Mode" of:
|
||||
* http://www.sdcard.org/developers/tech/sdcard/pls/Simplified_Physical_Layer_Spec.pdf
|
||||
*
|
||||
* SPI Startup
|
||||
* -----------
|
||||
* The SD card powers up in SD mode. The SPI interface mode is selected by
|
||||
* asserting CS low and sending the reset command (CMD0). The card will
|
||||
* respond with a (R1) response.
|
||||
*
|
||||
* CMD8 is optionally sent to determine the voltage range supported, and
|
||||
* indirectly determine whether it is a version 1.x SD/non-SD card or
|
||||
* version 2.x. I'll just ignore this for now.
|
||||
*
|
||||
* ACMD41 is repeatedly issued to initialise the card, until "in idle"
|
||||
* (bit 0) of the R1 response goes to '0', indicating it is initialised.
|
||||
*
|
||||
* You should also indicate whether the host supports High Capicity cards,
|
||||
* and check whether the card is high capacity - i'll also ignore this
|
||||
*
|
||||
* SPI Protocol
|
||||
* ------------
|
||||
* The SD SPI protocol is based on transactions made up of 8-bit words, with
|
||||
* the host starting every bus transaction by asserting the CS signal low. The
|
||||
* card always responds to commands, data blocks and errors.
|
||||
*
|
||||
* The protocol supports a CRC, but by default it is off (except for the
|
||||
* first reset CMD0, where the CRC can just be pre-calculated, and CMD8)
|
||||
* I'll leave the CRC off I think!
|
||||
*
|
||||
* Standard capacity cards have variable data block sizes, whereas High
|
||||
* Capacity cards fix the size of data block to 512 bytes. I'll therefore
|
||||
* just always use the Standard Capacity cards with a block size of 512 bytes.
|
||||
* This is set with CMD16.
|
||||
*
|
||||
* You can read and write single blocks (CMD17, CMD25) or multiple blocks
|
||||
* (CMD18, CMD25). For simplicity, I'll just use single block accesses. When
|
||||
* the card gets a read command, it responds with a response token, and then
|
||||
* a data token or an error.
|
||||
*
|
||||
* SPI Command Format
|
||||
* ------------------
|
||||
* Commands are 6-bytes long, containing the command, 32-bit argument, and CRC.
|
||||
*
|
||||
* +---------------+------------+------------+-----------+----------+--------------+
|
||||
* | 01 | cmd[5:0] | arg[31:24] | arg[23:16] | arg[15:8] | arg[7:0] | crc[6:0] | 1 |
|
||||
* +---------------+------------+------------+-----------+----------+--------------+
|
||||
*
|
||||
* As I'm not using CRC, I can fix that byte to what is needed for CMD0 (0x95)
|
||||
*
|
||||
* All Application Specific commands shall be preceded with APP_CMD (CMD55).
|
||||
*
|
||||
* SPI Response Format
|
||||
* -------------------
|
||||
* The main response format (R1) is a status byte (normally zero). Key flags:
|
||||
* idle - 1 if the card is in an idle state/initialising
|
||||
* cmd - 1 if an illegal command code was detected
|
||||
*
|
||||
* +-------------------------------------------------+
|
||||
* R1 | 0 | arg | addr | seq | crc | cmd | erase | idle |
|
||||
* +-------------------------------------------------+
|
||||
*
|
||||
* R1b is the same, except it is followed by a busy signal (zeros) until
|
||||
* the first non-zero byte when it is ready again.
|
||||
*
|
||||
* Data Response Token
|
||||
* -------------------
|
||||
* Every data block written to the card is acknowledged by a byte
|
||||
* response token
|
||||
*
|
||||
* +----------------------+
|
||||
* | xxx | 0 | status | 1 |
|
||||
* +----------------------+
|
||||
* 010 - OK!
|
||||
* 101 - CRC Error
|
||||
* 110 - Write Error
|
||||
*
|
||||
* Single Block Read and Write
|
||||
* ---------------------------
|
||||
*
|
||||
* Block transfers have a byte header, followed by the data, followed
|
||||
* by a 16-bit CRC. In our case, the data will always be 512 bytes.
|
||||
*
|
||||
* +------+---------+---------+- - - -+---------+-----------+----------+
|
||||
* | 0xFE | data[0] | data[1] | | data[n] | crc[15:8] | crc[7:0] |
|
||||
* +------+---------+---------+- - - -+---------+-----------+----------+
|
||||
*/
|
||||
|
||||
/* If the target has no SPI support then SDCard is not supported */
|
||||
#ifdef DEVICE_SPI
|
||||
|
||||
#include "SDBlockDevice.h"
|
||||
#include "mbed_debug.h"
|
||||
|
||||
#define SD_COMMAND_TIMEOUT 5000
|
||||
|
||||
#define SD_DBG 0
|
||||
|
||||
SDBlockDevice::SDBlockDevice(PinName mosi, PinName miso, PinName sclk, PinName cs)
|
||||
: _spi(mosi, miso, sclk), _cs(cs), _is_initialized(0)
|
||||
{
|
||||
_cs = 1;
|
||||
|
||||
// Set default to 100kHz for initialisation and 1MHz for data transfer
|
||||
_init_sck = 100000;
|
||||
_transfer_sck = 1000000;
|
||||
}
|
||||
|
||||
SDBlockDevice::~SDBlockDevice()
|
||||
{
|
||||
if (_is_initialized) {
|
||||
deinit();
|
||||
}
|
||||
}
|
||||
|
||||
#define R1_IDLE_STATE (1 << 0)
|
||||
#define R1_ERASE_RESET (1 << 1)
|
||||
#define R1_ILLEGAL_COMMAND (1 << 2)
|
||||
#define R1_COM_CRC_ERROR (1 << 3)
|
||||
#define R1_ERASE_SEQUENCE_ERROR (1 << 4)
|
||||
#define R1_ADDRESS_ERROR (1 << 5)
|
||||
#define R1_PARAMETER_ERROR (1 << 6)
|
||||
|
||||
// Types
|
||||
// - v1.x Standard Capacity
|
||||
// - v2.x Standard Capacity
|
||||
// - v2.x High Capacity
|
||||
// - Not recognised as an SD Card
|
||||
#define SDCARD_FAIL 0
|
||||
#define SDCARD_V1 1
|
||||
#define SDCARD_V2 2
|
||||
#define SDCARD_V2HC 3
|
||||
|
||||
bd_error_t SDBlockDevice::_initialise_card()
|
||||
{
|
||||
_dbg = SD_DBG;
|
||||
// Set to SCK for initialisation, and clock card with cs = 1
|
||||
_spi.lock();
|
||||
_spi.frequency(_init_sck);
|
||||
_cs = 1;
|
||||
for (int i = 0; i < 16; i++) {
|
||||
_spi.write(0xFF);
|
||||
}
|
||||
_spi.unlock();
|
||||
|
||||
// send CMD0, should return with all zeros except IDLE STATE set (bit 0)
|
||||
if (_cmd(0, 0) != R1_IDLE_STATE) {
|
||||
debug_if(_dbg, "No disk, or could not put SD card in to SPI idle state\n");
|
||||
return BD_ERROR_NO_DEVICE;
|
||||
}
|
||||
|
||||
// send CMD8 to determine whther it is ver 2.x
|
||||
int r = _cmd8();
|
||||
if (r == R1_IDLE_STATE) {
|
||||
return _initialise_card_v2();
|
||||
} else if (r == (R1_IDLE_STATE | R1_ILLEGAL_COMMAND)) {
|
||||
return _initialise_card_v1();
|
||||
} else {
|
||||
debug_if(_dbg, "Not in idle state after sending CMD8 (not an SD card?)\n");
|
||||
return BD_ERROR_DEVICE_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
bd_error_t SDBlockDevice::_initialise_card_v1()
|
||||
{
|
||||
for (int i = 0; i < SD_COMMAND_TIMEOUT; i++) {
|
||||
_cmd(55, 0);
|
||||
if (_cmd(41, 0) == 0) {
|
||||
_block_size = 512;
|
||||
debug_if(_dbg, "\n\rInit: SEDCARD_V1\n\r");
|
||||
return BD_ERROR_OK;
|
||||
}
|
||||
}
|
||||
|
||||
debug_if(_dbg, "Timeout waiting for v1.x card\n");
|
||||
return BD_ERROR_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
bd_error_t SDBlockDevice::_initialise_card_v2()
|
||||
{
|
||||
for (int i = 0; i < SD_COMMAND_TIMEOUT; i++) {
|
||||
wait_ms(50);
|
||||
_cmd58();
|
||||
_cmd(55, 0);
|
||||
if (_cmd(41, 0x40000000) == 0) {
|
||||
_cmd58();
|
||||
debug_if(_dbg, "\n\rInit: SDCARD_V2\n\r");
|
||||
_block_size = 1;
|
||||
return BD_ERROR_OK;
|
||||
}
|
||||
}
|
||||
|
||||
debug_if(_dbg, "Timeout waiting for v2.x card\n");
|
||||
return BD_ERROR_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
bd_error_t SDBlockDevice::init()
|
||||
{
|
||||
_lock.lock();
|
||||
bd_error_t err = _initialise_card();
|
||||
_is_initialized = (err == BD_ERROR_OK);
|
||||
if (!_is_initialized) {
|
||||
debug_if(_dbg, "Fail to initialize card\n");
|
||||
_lock.unlock();
|
||||
return err;
|
||||
}
|
||||
debug_if(_dbg, "init card = %d\n", _is_initialized);
|
||||
_sectors = _sd_sectors();
|
||||
|
||||
// Set block length to 512 (CMD16)
|
||||
if (_cmd(16, 512) != 0) {
|
||||
debug_if(_dbg, "Set 512-byte block timed out\n");
|
||||
_lock.unlock();
|
||||
return BD_ERROR_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
// Set SCK for data transfer
|
||||
_spi.frequency(_transfer_sck);
|
||||
_lock.unlock();
|
||||
return BD_ERROR_OK;
|
||||
}
|
||||
|
||||
bd_error_t SDBlockDevice::deinit()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
bd_error_t SDBlockDevice::program(const void *b, bd_addr_t addr, bd_size_t size)
|
||||
{
|
||||
if (!is_valid_program(addr, size)) {
|
||||
return BD_ERROR_PARAMETER;
|
||||
}
|
||||
|
||||
_lock.lock();
|
||||
if (!_is_initialized) {
|
||||
_lock.unlock();
|
||||
return BD_ERROR_NO_INIT;
|
||||
}
|
||||
|
||||
const uint8_t *buffer = static_cast<const uint8_t*>(b);
|
||||
while (size > 0) {
|
||||
bd_addr_t block = addr / 512;
|
||||
// set write address for single block (CMD24)
|
||||
if (_cmd(24, block * _block_size) != 0) {
|
||||
_lock.unlock();
|
||||
return BD_ERROR_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
// send the data block
|
||||
_write(buffer, 512);
|
||||
buffer += 512;
|
||||
addr += 512;
|
||||
size -= 512;
|
||||
}
|
||||
_lock.unlock();
|
||||
return 0;
|
||||
}
|
||||
|
||||
bd_error_t SDBlockDevice::read(void *b, bd_addr_t addr, bd_size_t size)
|
||||
{
|
||||
if (!is_valid_read(addr, size)) {
|
||||
return BD_ERROR_PARAMETER;
|
||||
}
|
||||
|
||||
_lock.lock();
|
||||
if (!_is_initialized) {
|
||||
_lock.unlock();
|
||||
return BD_ERROR_PARAMETER;
|
||||
}
|
||||
|
||||
uint8_t *buffer = static_cast<uint8_t *>(b);
|
||||
while (size > 0) {
|
||||
bd_addr_t block = addr / 512;
|
||||
// set read address for single block (CMD17)
|
||||
if (_cmd(17, block * _block_size) != 0) {
|
||||
_lock.unlock();
|
||||
return BD_ERROR_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
// receive the data
|
||||
_read(buffer, 512);
|
||||
buffer += 512;
|
||||
addr += 512;
|
||||
size -= 512;
|
||||
}
|
||||
_lock.unlock();
|
||||
return 0;
|
||||
}
|
||||
|
||||
bd_error_t SDBlockDevice::erase(bd_addr_t addr, bd_size_t size)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
bd_size_t SDBlockDevice::get_read_size()
|
||||
{
|
||||
return 512;
|
||||
}
|
||||
|
||||
bd_size_t SDBlockDevice::get_program_size()
|
||||
{
|
||||
return 512;
|
||||
}
|
||||
|
||||
bd_size_t SDBlockDevice::get_erase_size()
|
||||
{
|
||||
return 512;
|
||||
}
|
||||
|
||||
bd_size_t SDBlockDevice::size()
|
||||
{
|
||||
_lock.lock();
|
||||
bd_size_t sectors = _sectors;
|
||||
_lock.unlock();
|
||||
return 512*sectors;
|
||||
}
|
||||
|
||||
void SDBlockDevice::debug(bool dbg)
|
||||
{
|
||||
_dbg = dbg;
|
||||
}
|
||||
|
||||
|
||||
// PRIVATE FUNCTIONS
|
||||
int SDBlockDevice::_cmd(int cmd, int arg) {
|
||||
_spi.lock();
|
||||
_cs = 0;
|
||||
|
||||
// send a command
|
||||
_spi.write(0x40 | cmd);
|
||||
_spi.write(arg >> 24);
|
||||
_spi.write(arg >> 16);
|
||||
_spi.write(arg >> 8);
|
||||
_spi.write(arg >> 0);
|
||||
_spi.write(0x95);
|
||||
|
||||
// wait for the repsonse (response[7] == 0)
|
||||
for (int i = 0; i < SD_COMMAND_TIMEOUT; i++) {
|
||||
int response = _spi.write(0xFF);
|
||||
if (!(response & 0x80)) {
|
||||
_cs = 1;
|
||||
_spi.write(0xFF);
|
||||
_spi.unlock();
|
||||
return response;
|
||||
}
|
||||
}
|
||||
_cs = 1;
|
||||
_spi.write(0xFF);
|
||||
_spi.unlock();
|
||||
return -1; // timeout
|
||||
}
|
||||
int SDBlockDevice::_cmdx(int cmd, int arg) {
|
||||
_spi.lock();
|
||||
_cs = 0;
|
||||
|
||||
// send a command
|
||||
_spi.write(0x40 | cmd);
|
||||
_spi.write(arg >> 24);
|
||||
_spi.write(arg >> 16);
|
||||
_spi.write(arg >> 8);
|
||||
_spi.write(arg >> 0);
|
||||
_spi.write(0x95);
|
||||
|
||||
// wait for the repsonse (response[7] == 0)
|
||||
for (int i = 0; i < SD_COMMAND_TIMEOUT; i++) {
|
||||
int response = _spi.write(0xFF);
|
||||
if (!(response & 0x80)) {
|
||||
_cs = 1;
|
||||
_spi.unlock();
|
||||
return response;
|
||||
}
|
||||
}
|
||||
_cs = 1;
|
||||
_spi.write(0xFF);
|
||||
_spi.unlock();
|
||||
return -1; // timeout
|
||||
}
|
||||
|
||||
|
||||
int SDBlockDevice::_cmd58() {
|
||||
_spi.lock();
|
||||
_cs = 0;
|
||||
int arg = 0;
|
||||
|
||||
// send a command
|
||||
_spi.write(0x40 | 58);
|
||||
_spi.write(arg >> 24);
|
||||
_spi.write(arg >> 16);
|
||||
_spi.write(arg >> 8);
|
||||
_spi.write(arg >> 0);
|
||||
_spi.write(0x95);
|
||||
|
||||
// wait for the repsonse (response[7] == 0)
|
||||
for (int i = 0; i < SD_COMMAND_TIMEOUT; i++) {
|
||||
int response = _spi.write(0xFF);
|
||||
if (!(response & 0x80)) {
|
||||
int ocr = _spi.write(0xFF) << 24;
|
||||
ocr |= _spi.write(0xFF) << 16;
|
||||
ocr |= _spi.write(0xFF) << 8;
|
||||
ocr |= _spi.write(0xFF) << 0;
|
||||
_cs = 1;
|
||||
_spi.write(0xFF);
|
||||
_spi.unlock();
|
||||
return response;
|
||||
}
|
||||
}
|
||||
_cs = 1;
|
||||
_spi.write(0xFF);
|
||||
_spi.unlock();
|
||||
return -1; // timeout
|
||||
}
|
||||
|
||||
int SDBlockDevice::_cmd8() {
|
||||
_spi.lock();
|
||||
_cs = 0;
|
||||
|
||||
// send a command
|
||||
_spi.write(0x40 | 8); // CMD8
|
||||
_spi.write(0x00); // reserved
|
||||
_spi.write(0x00); // reserved
|
||||
_spi.write(0x01); // 3.3v
|
||||
_spi.write(0xAA); // check pattern
|
||||
_spi.write(0x87); // crc
|
||||
|
||||
// wait for the repsonse (response[7] == 0)
|
||||
for (int i = 0; i < SD_COMMAND_TIMEOUT * 1000; i++) {
|
||||
char response[5];
|
||||
response[0] = _spi.write(0xFF);
|
||||
if (!(response[0] & 0x80)) {
|
||||
for (int j = 1; j < 5; j++) {
|
||||
response[i] = _spi.write(0xFF);
|
||||
}
|
||||
_cs = 1;
|
||||
_spi.write(0xFF);
|
||||
_spi.unlock();
|
||||
return response[0];
|
||||
}
|
||||
}
|
||||
_cs = 1;
|
||||
_spi.write(0xFF);
|
||||
_spi.unlock();
|
||||
return -1; // timeout
|
||||
}
|
||||
|
||||
int SDBlockDevice::_read(uint8_t *buffer, uint32_t length) {
|
||||
_spi.lock();
|
||||
_cs = 0;
|
||||
|
||||
// read until start byte (0xFF)
|
||||
while (_spi.write(0xFF) != 0xFE);
|
||||
|
||||
// read data
|
||||
for (uint32_t i = 0; i < length; i++) {
|
||||
buffer[i] = _spi.write(0xFF);
|
||||
}
|
||||
_spi.write(0xFF); // checksum
|
||||
_spi.write(0xFF);
|
||||
|
||||
_cs = 1;
|
||||
_spi.write(0xFF);
|
||||
_spi.unlock();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SDBlockDevice::_write(const uint8_t*buffer, uint32_t length) {
|
||||
_spi.lock();
|
||||
_cs = 0;
|
||||
|
||||
// indicate start of block
|
||||
_spi.write(0xFE);
|
||||
|
||||
// write the data
|
||||
for (uint32_t i = 0; i < length; i++) {
|
||||
_spi.write(buffer[i]);
|
||||
}
|
||||
|
||||
// write the checksum
|
||||
_spi.write(0xFF);
|
||||
_spi.write(0xFF);
|
||||
|
||||
// check the response token
|
||||
if ((_spi.write(0xFF) & 0x1F) != 0x05) {
|
||||
_cs = 1;
|
||||
_spi.write(0xFF);
|
||||
_spi.unlock();
|
||||
return 1;
|
||||
}
|
||||
|
||||
// wait for write to finish
|
||||
while (_spi.write(0xFF) == 0);
|
||||
|
||||
_cs = 1;
|
||||
_spi.write(0xFF);
|
||||
_spi.unlock();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint32_t ext_bits(unsigned char *data, int msb, int lsb) {
|
||||
uint32_t bits = 0;
|
||||
uint32_t size = 1 + msb - lsb;
|
||||
for (uint32_t i = 0; i < size; i++) {
|
||||
uint32_t position = lsb + i;
|
||||
uint32_t byte = 15 - (position >> 3);
|
||||
uint32_t bit = position & 0x7;
|
||||
uint32_t value = (data[byte] >> bit) & 1;
|
||||
bits |= value << i;
|
||||
}
|
||||
return bits;
|
||||
}
|
||||
|
||||
uint32_t SDBlockDevice::_sd_sectors() {
|
||||
uint32_t c_size, c_size_mult, read_bl_len;
|
||||
uint32_t block_len, mult, blocknr, capacity;
|
||||
uint32_t hc_c_size;
|
||||
uint32_t blocks;
|
||||
|
||||
// CMD9, Response R2 (R1 byte + 16-byte block read)
|
||||
if (_cmdx(9, 0) != 0) {
|
||||
debug_if(_dbg, "Didn't get a response from the disk\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t csd[16];
|
||||
if (_read(csd, 16) != 0) {
|
||||
debug_if(_dbg, "Couldn't read csd response from disk\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// csd_structure : csd[127:126]
|
||||
// c_size : csd[73:62]
|
||||
// c_size_mult : csd[49:47]
|
||||
// read_bl_len : csd[83:80] - the *maximum* read block length
|
||||
|
||||
int csd_structure = ext_bits(csd, 127, 126);
|
||||
|
||||
switch (csd_structure) {
|
||||
case 0:
|
||||
_block_size = 512;
|
||||
c_size = ext_bits(csd, 73, 62);
|
||||
c_size_mult = ext_bits(csd, 49, 47);
|
||||
read_bl_len = ext_bits(csd, 83, 80);
|
||||
|
||||
block_len = 1 << read_bl_len;
|
||||
mult = 1 << (c_size_mult + 2);
|
||||
blocknr = (c_size + 1) * mult;
|
||||
capacity = blocknr * block_len;
|
||||
blocks = capacity / 512;
|
||||
debug_if(_dbg, "\n\rSDBlockDevice\n\rc_size: %d \n\rcapacity: %ld \n\rsectors: %lld\n\r", c_size, capacity, blocks);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
_block_size = 1;
|
||||
hc_c_size = ext_bits(csd, 63, 48);
|
||||
blocks = (hc_c_size+1)*1024;
|
||||
debug_if(_dbg, "\n\rSDHC Card \n\rhc_c_size: %d\n\rcapacity: %lld \n\rsectors: %lld\n\r", hc_c_size, blocks*512, blocks);
|
||||
break;
|
||||
|
||||
default:
|
||||
debug_if(_dbg, "CSD struct unsupported\r\n");
|
||||
return 0;
|
||||
};
|
||||
return blocks;
|
||||
}
|
||||
|
||||
#endif /* DEVICE_SPI */
|
|
@ -1,158 +0,0 @@
|
|||
/* mbed Microcontroller Library
|
||||
* Copyright (c) 2006-2012 ARM Limited
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
#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"
|
||||
|
||||
|
||||
/** 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);
|
||||
virtual ~SDBlockDevice();
|
||||
|
||||
/** Initialize a block device
|
||||
*
|
||||
* @return 0 on success or a negative error code on failure
|
||||
*/
|
||||
virtual bd_error_t init();
|
||||
|
||||
/** Deinitialize a block device
|
||||
*
|
||||
* @return 0 on success or a negative error code on failure
|
||||
*/
|
||||
virtual bd_error_t 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 bd_error_t 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 bd_error_t program(const void *buffer, bd_addr_t addr, bd_size_t size);
|
||||
|
||||
/** Erase blocks on a block device
|
||||
*
|
||||
* The state of an erased block is undefined until it has been programmed
|
||||
*
|
||||
* @param addr Address of block to begin erasing
|
||||
* @param size Size to erase in bytes, must be a multiple of erase block size
|
||||
* @return 0 on success, negative error code on failure
|
||||
*/
|
||||
virtual bd_error_t erase(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();
|
||||
|
||||
/** 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();
|
||||
|
||||
/** Get the size of a eraseable block
|
||||
*
|
||||
* @return Size of a eraseable block in bytes
|
||||
* @note Must be a multiple of the program size
|
||||
*/
|
||||
virtual bd_size_t get_erase_size();
|
||||
|
||||
/** Get the total size of the underlying device
|
||||
*
|
||||
* @return Size of the underlying device in bytes
|
||||
*/
|
||||
virtual bd_size_t size();
|
||||
|
||||
/** Enable or disable debugging
|
||||
*
|
||||
* @param State of debugging
|
||||
*/
|
||||
virtual void debug(bool dbg);
|
||||
|
||||
private:
|
||||
int _cmd(int cmd, int arg);
|
||||
int _cmdx(int cmd, int arg);
|
||||
int _cmd8();
|
||||
int _cmd58();
|
||||
bd_error_t _initialise_card();
|
||||
bd_error_t _initialise_card_v1();
|
||||
bd_error_t _initialise_card_v2();
|
||||
|
||||
int _read(uint8_t * buffer, uint32_t length);
|
||||
int _write(const uint8_t *buffer, uint32_t length);
|
||||
uint32_t _sd_sectors();
|
||||
uint32_t _sectors;
|
||||
|
||||
uint32_t _init_sck;
|
||||
uint32_t _transfer_sck;
|
||||
|
||||
SPI _spi;
|
||||
DigitalOut _cs;
|
||||
unsigned _block_size;
|
||||
bool _is_initialized;
|
||||
bool _dbg;
|
||||
Mutex _lock;
|
||||
};
|
||||
|
||||
|
||||
#endif /* DEVICE_SPI */
|
||||
|
||||
#endif /* MBED_SD_BLOCK_DEVICE_H */
|
|
@ -1,93 +0,0 @@
|
|||
/* mbed Microcontroller Library
|
||||
* Copyright (c) 2017 ARM Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#include "mbed.h"
|
||||
#include "greentea-client/test_env.h"
|
||||
#include "unity.h"
|
||||
#include "utest.h"
|
||||
|
||||
#include "SDBlockDevice.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
using namespace utest::v1;
|
||||
|
||||
#ifndef SD_INSTALLED
|
||||
#define SD_INSTALLED false
|
||||
#endif
|
||||
|
||||
#ifndef SD_PINS
|
||||
#if defined(TARGET_K64F)
|
||||
#define SD_PINS PTE3, PTE1, PTE2, PTE4
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !SD_INSTALLED
|
||||
#error [NOT_SUPPORTED] SD card required
|
||||
#endif
|
||||
|
||||
#define BLOCK_SIZE 512
|
||||
uint8_t write_block[BLOCK_SIZE];
|
||||
uint8_t read_block[BLOCK_SIZE];
|
||||
|
||||
// Simple test which read/writes a block
|
||||
void test_read_write() {
|
||||
SDBlockDevice bd(SD_PINS);
|
||||
|
||||
int err = bd.init();
|
||||
TEST_ASSERT_EQUAL(0, err);
|
||||
|
||||
printf("read size: %llu\r\n", bd.get_read_size());
|
||||
printf("program size: %llu\r\n", bd.get_program_size());
|
||||
printf("erase size: %llu\r\n", bd.get_erase_size());
|
||||
|
||||
// Fill with random sequence
|
||||
srand(1);
|
||||
for (int i = 0; i < BLOCK_SIZE; i++) {
|
||||
write_block[i] = 0xff & rand();
|
||||
}
|
||||
|
||||
// Write, sync, and read the block
|
||||
err = bd.write(write_block, 0, BLOCK_SIZE);
|
||||
TEST_ASSERT_EQUAL(0, err);
|
||||
|
||||
err = bd.read(read_block, 0, BLOCK_SIZE);
|
||||
TEST_ASSERT_EQUAL(0, err);
|
||||
|
||||
// Check that the data was unmodified
|
||||
srand(1);
|
||||
for (int i = 0; i < BLOCK_SIZE; i++) {
|
||||
TEST_ASSERT_EQUAL(0xff & rand(), read_block[i]);
|
||||
}
|
||||
|
||||
err = bd.deinit();
|
||||
TEST_ASSERT_EQUAL(0, err);
|
||||
}
|
||||
|
||||
|
||||
// Test setup
|
||||
utest::v1::status_t test_setup(const size_t number_of_cases) {
|
||||
GREENTEA_SETUP(10, "default_auto");
|
||||
return verbose_test_setup_handler(number_of_cases);
|
||||
}
|
||||
|
||||
Case cases[] = {
|
||||
Case("Testing read write of a block", test_read_write),
|
||||
};
|
||||
|
||||
Specification specification(test_setup, cases);
|
||||
|
||||
int main() {
|
||||
return !Harness::run(specification);
|
||||
}
|
|
@ -1,88 +0,0 @@
|
|||
/** @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*/
|
|
@ -1,117 +0,0 @@
|
|||
/* @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;
|
||||
}
|
||||
|
|
@ -1,74 +0,0 @@
|
|||
/** @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 */
|
Loading…
Reference in New Issue