From 84ad289e0ae8d2bd32cba5c22a27a35132b5c863 Mon Sep 17 00:00:00 2001
From: Lorenz Meier <lm@inf.ethz.ch>
Date: Wed, 15 Jan 2014 17:20:08 +0100
Subject: [PATCH] Improved test suite, now features a MTD device test

---
 src/systemcmds/tests/module.mk    |   3 +-
 src/systemcmds/tests/test_file.c  |   2 +-
 src/systemcmds/tests/test_mtd.c   | 296 ++++++++++++++++++++++++++++++
 src/systemcmds/tests/tests.h      |   1 +
 src/systemcmds/tests/tests_main.c |   1 +
 5 files changed, 301 insertions(+), 2 deletions(-)
 create mode 100644 src/systemcmds/tests/test_mtd.c

diff --git a/src/systemcmds/tests/module.mk b/src/systemcmds/tests/module.mk
index 6a05ac3c61..beb9ad13d3 100644
--- a/src/systemcmds/tests/module.mk
+++ b/src/systemcmds/tests/module.mk
@@ -30,4 +30,5 @@ SRCS			 = test_adc.c \
 			   test_ppm_loopback.c \
 			   test_rc.c \
 			   test_conv.cpp \
-			   test_mount.c
+			   test_mount.c \
+			   test_mtd.c
diff --git a/src/systemcmds/tests/test_file.c b/src/systemcmds/tests/test_file.c
index 83d09dd5e8..96be1e8df5 100644
--- a/src/systemcmds/tests/test_file.c
+++ b/src/systemcmds/tests/test_file.c
@@ -54,7 +54,7 @@
 
 #include "tests.h"
 
-int check_user_abort(int fd);
+static int check_user_abort(int fd);
 
 int check_user_abort(int fd) {
 	/* check if user wants to abort */
diff --git a/src/systemcmds/tests/test_mtd.c b/src/systemcmds/tests/test_mtd.c
new file mode 100644
index 0000000000..bcd24e5c90
--- /dev/null
+++ b/src/systemcmds/tests/test_mtd.c
@@ -0,0 +1,296 @@
+/****************************************************************************
+ *
+ *   Copyright (c) 2012-2014 PX4 Development Team. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ * 3. Neither the name PX4 nor the names of its contributors may be
+ *    used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/**
+ * @file test_mtd.c
+ *
+ * Param storage / file test.
+ *
+ * @author Lorenz Meier <lm@inf.ethz.ch>
+ */
+
+#include <sys/stat.h>
+#include <poll.h>
+#include <dirent.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <systemlib/err.h>
+#include <systemlib/perf_counter.h>
+#include <string.h>
+
+#include <drivers/drv_hrt.h>
+
+#include "tests.h"
+
+#define PARAM_FILE_NAME "/fs/mtd_params"
+
+static int check_user_abort(int fd);
+
+int check_user_abort(int fd) {
+	/* check if user wants to abort */
+	char c;
+
+	struct pollfd fds;
+	int ret;
+	fds.fd = 0; /* stdin */
+	fds.events = POLLIN;
+	ret = poll(&fds, 1, 0);
+
+	if (ret > 0) {
+
+		read(0, &c, 1);
+
+		switch (c) {
+		case 0x03: // ctrl-c
+		case 0x1b: // esc
+		case 'c':
+		case 'q':
+		{
+			warnx("Test aborted.");
+			fsync(fd);
+			close(fd);
+			return OK;
+			/* not reached */
+			}
+		}
+	}
+
+	return 1;
+}
+
+int
+test_mtd(int argc, char *argv[])
+{
+	unsigned iterations= 0;
+
+	/* check if microSD card is mounted */
+	struct stat buffer;
+	if (stat(PARAM_FILE_NAME, &buffer)) {
+		warnx("file %s not found, aborting MTD test", PARAM_FILE_NAME);
+		return 1;
+	}
+
+	// XXX get real storage space here
+	unsigned file_size = 4096;
+
+	/* perform tests for a range of chunk sizes */
+	unsigned chunk_sizes[] = {256, 512, 4096};
+
+	for (unsigned c = 0; c < (sizeof(chunk_sizes) / sizeof(chunk_sizes[0])); c++) {
+
+		printf("\n====== FILE TEST: %u bytes chunks ======\n", chunk_sizes[c]);
+
+		uint8_t write_buf[chunk_sizes[c]] __attribute__((aligned(64)));
+
+		/* fill write buffer with known values */
+		for (int i = 0; i < sizeof(write_buf); i++) {
+			/* this will wrap, but we just need a known value with spacing */
+			write_buf[i] = i+11;
+		}
+
+		uint8_t read_buf[chunk_sizes[c]] __attribute__((aligned(64)));
+		hrt_abstime start, end;
+
+		int fd = open(PARAM_FILE_NAME, O_WRONLY);
+
+		warnx("testing unaligned writes - please wait..");
+
+		iterations = file_size / chunk_sizes[c];
+
+		start = hrt_absolute_time();
+		for (unsigned i = 0; i < iterations; i++) {
+			int wret = write(fd, write_buf, chunk_sizes[c]);
+
+			if (wret != chunk_sizes[c]) {
+				warn("WRITE ERROR!");
+
+				return 1;
+			}
+
+			fsync(fd);
+
+			if (!check_user_abort(fd))
+				return OK;
+
+		}
+		end = hrt_absolute_time();
+
+		close(fd);
+		fd = open(PARAM_FILE_NAME, O_RDONLY);
+
+		/* read back data for validation */
+		for (unsigned i = 0; i < iterations; i++) {
+			int rret = read(fd, read_buf, chunk_sizes[c]);
+
+			if (rret != chunk_sizes[c]) {
+				warnx("READ ERROR!");
+				return 1;
+			}
+			
+			/* compare value */
+			bool compare_ok = true;
+
+			for (int j = 0; j < chunk_sizes[c]; j++) {
+				if (read_buf[j] != write_buf[j]) {
+					warnx("COMPARISON ERROR: byte %d", j);
+					compare_ok = false;
+					break;
+				}
+			}
+
+			if (!compare_ok) {
+				warnx("ABORTING FURTHER COMPARISON DUE TO ERROR");
+				return 1;
+			}
+
+			if (!check_user_abort(fd))
+				return OK;
+
+		}
+
+		close(fd);
+
+		printf("RESULT: OK! No readback errors.\n\n");
+
+		// /*
+		//  * ALIGNED WRITES AND UNALIGNED READS
+		//  */
+
+		
+		// fd = open(PARAM_FILE_NAME, O_WRONLY);
+
+		// warnx("testing aligned writes - please wait.. (CTRL^C to abort)");
+
+		// start = hrt_absolute_time();
+		// for (unsigned i = 0; i < iterations; i++) {
+		// 	int wret = write(fd, write_buf, chunk_sizes[c]);
+
+		// 	if (wret != chunk_sizes[c]) {
+		// 		warnx("WRITE ERROR!");
+		// 		return 1;
+		// 	}
+
+		// 	if (!check_user_abort(fd))
+		// 		return OK;
+
+		// }
+
+		// fsync(fd);
+
+		// warnx("reading data aligned..");
+
+		// close(fd);
+		// fd = open(PARAM_FILE_NAME, O_RDONLY);
+
+		// bool align_read_ok = true;
+
+		// /* read back data unaligned */
+		// for (unsigned i = 0; i < iterations; i++) {
+		// 	int rret = read(fd, read_buf, chunk_sizes[c]);
+
+		// 	if (rret != chunk_sizes[c]) {
+		// 		warnx("READ ERROR!");
+		// 		return 1;
+		// 	}
+			
+		// 	/* compare value */
+		// 	bool compare_ok = true;
+
+		// 	for (int j = 0; j < chunk_sizes[c]; j++) {
+		// 		if (read_buf[j] != write_buf[j]) {
+		// 			warnx("COMPARISON ERROR: byte %d: %u != %u", j, (unsigned int)read_buf[j], (unsigned int)write_buf[j]);
+		// 			align_read_ok = false;
+		// 			break;
+		// 		}
+
+		// 		if (!check_user_abort(fd))
+		// 			return OK;
+		// 	}
+
+		// 	if (!align_read_ok) {
+		// 		warnx("ABORTING FURTHER COMPARISON DUE TO ERROR");
+		// 		return 1;
+		// 	}
+
+		// }
+
+		// warnx("align read result: %s\n", (align_read_ok) ? "OK" : "ERROR");
+
+		// warnx("reading data unaligned..");
+
+		// close(fd);
+		// fd = open(PARAM_FILE_NAME, O_RDONLY);
+
+		// bool unalign_read_ok = true;
+		// int unalign_read_err_count = 0;
+
+		// memset(read_buf, 0, sizeof(read_buf));
+
+		// /* read back data unaligned */
+		// for (unsigned i = 0; i < iterations; i++) {
+		// 	int rret = read(fd, read_buf + a, chunk_sizes[c]);
+
+		// 	if (rret != chunk_sizes[c]) {
+		// 		warnx("READ ERROR!");
+		// 		return 1;
+		// 	}
+
+		// 	for (int j = 0; j < chunk_sizes[c]; j++) {
+
+		// 		if ((read_buf + a)[j] != write_buf[j]) {
+		// 			warnx("COMPARISON ERROR: byte %d, align shift: %d: %u != %u", j, a, (unsigned int)read_buf[j + a], (unsigned int)write_buf[j]);
+		// 			unalign_read_ok = false;
+		// 			unalign_read_err_count++;
+					
+		// 			if (unalign_read_err_count > 10)
+		// 				break;
+		// 		}
+
+		// 		if (!check_user_abort(fd))
+		// 			return OK;
+		// 	}
+
+		// 	if (!unalign_read_ok) {
+		// 		warnx("ABORTING FURTHER COMPARISON DUE TO ERROR");
+		// 		return 1;
+		// 	}
+
+		// }
+
+		// close(fd);
+	}
+
+	return 0;
+}
diff --git a/src/systemcmds/tests/tests.h b/src/systemcmds/tests/tests.h
index ff05cc322d..223edc14a9 100644
--- a/src/systemcmds/tests/tests.h
+++ b/src/systemcmds/tests/tests.h
@@ -111,6 +111,7 @@ extern int	test_mixer(int argc, char *argv[]);
 extern int	test_rc(int argc, char *argv[]);
 extern int	test_conv(int argc, char *argv[]);
 extern int	test_mount(int argc, char *argv[]);
+extern int	test_mtd(int argc, char *argv[]);
 
 __END_DECLS
 
diff --git a/src/systemcmds/tests/tests_main.c b/src/systemcmds/tests/tests_main.c
index 0d3dabc00e..77a4df618b 100644
--- a/src/systemcmds/tests/tests_main.c
+++ b/src/systemcmds/tests/tests_main.c
@@ -108,6 +108,7 @@ const struct {
 	{"rc",			test_rc,	OPT_NOJIGTEST | OPT_NOALLTEST},
 	{"conv",		test_conv,	OPT_NOJIGTEST | OPT_NOALLTEST},
 	{"mount",		test_mount,	OPT_NOJIGTEST | OPT_NOALLTEST},
+	{"mtd",			test_mtd,	0},
 	{"help",		test_help,	OPT_NOALLTEST | OPT_NOHELP | OPT_NOJIGTEST},
 	{NULL,			NULL, 		0}
 };
-- 
GitLab