aboutsummaryrefslogtreecommitdiffstats
path: root/test
diff options
context:
space:
mode:
authorGiovanni Di Sirio <gdisirio@gmail.com>2017-11-14 12:50:52 +0000
committerGiovanni Di Sirio <gdisirio@gmail.com>2017-11-14 12:50:52 +0000
commit1935d28be9747aac18d9338fb1444514d257a51a (patch)
treebc96f9442b6bf4613fd9bbde357b1a5198e9ec24 /test
parentbc113301c744fc311f0cd2f2af102218eac7bb44 (diff)
downloadChibiOS-1935d28be9747aac18d9338fb1444514d257a51a.tar.gz
ChibiOS-1935d28be9747aac18d9338fb1444514d257a51a.tar.bz2
ChibiOS-1935d28be9747aac18d9338fb1444514d257a51a.zip
git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@10997 35acf78f-673a-0410-8e92-d51de3d6d3f4
Diffstat (limited to 'test')
-rw-r--r--test/mfs/.cproject57
-rw-r--r--test/mfs/.project32
-rw-r--r--test/mfs/.spc5project4
-rw-r--r--test/mfs/config.fmpp15
-rw-r--r--test/mfs/configuration.xml862
-rw-r--r--test/mfs/nil_test.mk9
-rw-r--r--test/mfs/patch.xml5
7 files changed, 984 insertions, 0 deletions
diff --git a/test/mfs/.cproject b/test/mfs/.cproject
new file mode 100644
index 000000000..896066e66
--- /dev/null
+++ b/test/mfs/.cproject
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<?fileVersion 4.0.0?><cproject storage_type_id="org.eclipse.cdt.core.XmlProjectDescriptionStorage">
+ <storageModule moduleId="org.eclipse.cdt.core.settings">
+ <cconfiguration id="com.st.tools.spc5.configuration.default">
+ <storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="com.st.tools.spc5.configuration.default" moduleId="org.eclipse.cdt.core.settings" name="Default">
+ <externalSettings/>
+ <extensions>
+ <extension id="org.eclipse.cdt.core.GASErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+ <extension id="org.eclipse.cdt.core.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+ <extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+ <extension id="org.eclipse.cdt.core.VCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+ <extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/>
+ <extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+ </extensions>
+ </storageModule>
+ <storageModule moduleId="cdtBuildSystem" version="4.0.0">
+ <configuration artifactName="${ProjName}" buildProperties="" description="" id="com.st.tools.spc5.configuration.default" name="Default" parent="org.eclipse.cdt.build.core.prefbase.cfg">
+ <folderInfo id="com.st.tools.spc5.configuration.default." name="/" resourcePath="">
+ <toolChain id="org.eclipse.cdt.build.core.prefbase.toolchain.1601604545" name="No ToolChain" resourceTypeBasedDiscovery="false" superClass="org.eclipse.cdt.build.core.prefbase.toolchain">
+ <targetPlatform id="org.eclipse.cdt.build.core.prefbase.toolchain.1601604545.979430051" name=""/>
+ <builder id="org.eclipse.cdt.build.core.settings.default.builder.1252703125" keepEnvironmentInBuildfile="false" managedBuildOn="true" name="Gnu Make Builder" superClass="org.eclipse.cdt.build.core.settings.default.builder">
+ <outputEntries>
+ <entry flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="outputPath" name=""/>
+ </outputEntries>
+ </builder>
+ <tool id="org.eclipse.cdt.build.core.settings.holder.libs.758143064" name="holder for library settings" superClass="org.eclipse.cdt.build.core.settings.holder.libs"/>
+ <tool id="org.eclipse.cdt.build.core.settings.holder.466800556" name="Assembly" superClass="org.eclipse.cdt.build.core.settings.holder">
+ <inputType id="org.eclipse.cdt.build.core.settings.holder.inType.276542087" languageId="org.eclipse.cdt.core.assembly" languageName="Assembly" sourceContentType="org.eclipse.cdt.core.asmSource" superClass="org.eclipse.cdt.build.core.settings.holder.inType"/>
+ </tool>
+ <tool id="org.eclipse.cdt.build.core.settings.holder.1590093401" name="GNU C++" superClass="org.eclipse.cdt.build.core.settings.holder">
+ <inputType id="org.eclipse.cdt.build.core.settings.holder.inType.1021209563" languageId="org.eclipse.cdt.core.g++" languageName="GNU C++" sourceContentType="org.eclipse.cdt.core.cxxSource,org.eclipse.cdt.core.cxxHeader" superClass="org.eclipse.cdt.build.core.settings.holder.inType"/>
+ </tool>
+ <tool id="org.eclipse.cdt.build.core.settings.holder.1880457386" name="GNU C" superClass="org.eclipse.cdt.build.core.settings.holder">
+ <inputType id="org.eclipse.cdt.build.core.settings.holder.inType.1710576459" languageId="org.eclipse.cdt.core.gcc" languageName="GNU C" sourceContentType="org.eclipse.cdt.core.cSource,org.eclipse.cdt.core.cHeader" superClass="org.eclipse.cdt.build.core.settings.holder.inType"/>
+ </tool>
+ </toolChain>
+ </folderInfo>
+ <sourceEntries>
+ <entry flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name="source"/>
+ <entry flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name="components"/>
+ </sourceEntries>
+ </configuration>
+ </storageModule>
+ <storageModule moduleId="org.eclipse.cdt.core.externalSettings"/>
+ </cconfiguration>
+ </storageModule>
+ <storageModule moduleId="cdtBuildSystem" version="4.0.0">
+ <project id="MFS Tests Generator.null.1740439042" name="MFS Tests Generator"/>
+ </storageModule>
+ <storageModule moduleId="scannerConfiguration">
+ <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
+ <scannerConfigBuildInfo instanceId="com.st.tools.spc5.configuration.default">
+ <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
+ </scannerConfigBuildInfo>
+ </storageModule>
+ <storageModule moduleId="org.eclipse.cdt.core.LanguageSettingsProviders"/>
+</cproject>
diff --git a/test/mfs/.project b/test/mfs/.project
new file mode 100644
index 000000000..6485f730e
--- /dev/null
+++ b/test/mfs/.project
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>MFS Tests Generator</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.cdt.managedbuilder.core.genmakebuilder</name>
+ <triggers>clean,full,incremental,</triggers>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder</name>
+ <triggers>full,incremental,</triggers>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>com.st.tools.spc5.spc5StudioPatchBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.cdt.core.cnature</nature>
+ <nature>org.eclipse.cdt.managedbuilder.core.managedBuildNature</nature>
+ <nature>org.eclipse.cdt.managedbuilder.core.ScannerConfigNature</nature>
+ <nature>com.st.tools.spc5.spc5StudioNature</nature>
+ </natures>
+</projectDescription>
diff --git a/test/mfs/.spc5project b/test/mfs/.spc5project
new file mode 100644
index 000000000..104c5aa76
--- /dev/null
+++ b/test/mfs/.spc5project
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<SPC5StudioProject>
+ <Properties />
+</SPC5StudioProject>
diff --git a/test/mfs/config.fmpp b/test/mfs/config.fmpp
new file mode 100644
index 000000000..62a3641e2
--- /dev/null
+++ b/test/mfs/config.fmpp
@@ -0,0 +1,15 @@
+sourceRoot: ../../tools/ftl/processors/unittest
+outputRoot: source
+dataRoot: .
+
+freemarkerLinks: {
+ ftllibs: ../../tools/ftl/libs
+}
+
+data : {
+ xml:xml (
+ configuration.xml
+ {
+ }
+ )
+}
diff --git a/test/mfs/configuration.xml b/test/mfs/configuration.xml
new file mode 100644
index 000000000..e51d568f4
--- /dev/null
+++ b/test/mfs/configuration.xml
@@ -0,0 +1,862 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<SPC5-Config version="1.0.0">
+ <application name="ChibiOS/NIL Test Suite" version="1.0.0" standalone="true" locked="false">
+ <description>Test Specification for ChibiOS/HAL MFS Complex Driver.</description>
+ <component id="org.chibios.spc5.components.portable.generic_startup">
+ <component id="org.chibios.spc5.components.portable.chibios_unitary_tests_engine" />
+ </component>
+ <instances>
+ <instance locked="false" id="org.chibios.spc5.components.portable.generic_startup" />
+ <instance locked="false" id="org.chibios.spc5.components.portable.chibios_unitary_tests_engine">
+ <description>
+ <brief>
+ <value>ChibiOS/HAL MFS Test Suite.</value>
+ </brief>
+ <copyright>
+ <value><![CDATA[/*
+ ChibiOS - Copyright (C) 2006..2017 Giovanni Di Sirio
+
+ 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.
+*/]]></value>
+ </copyright>
+ <introduction>
+ <value>Test suite for ChibiOS/HAL MFS. The purpose of this suite is to perform unit tests on the MFS module and to converge to 100% code coverage through successive improvements.</value>
+ </introduction>
+ </description>
+ <global_data_and_code>
+ <code_prefix>
+ <value>nil_</value>
+ </code_prefix>
+ <global_definitions>
+ <value><![CDATA[#define TEST_SUITE_NAME "ChibiOS/NIL Test Suite"
+
+#define TEST_REPORT_HOOK_HEADER test_print_port_info();
+
+extern semaphore_t gsem1, gsem2;
+extern thread_reference_t gtr1;
+extern THD_WORKING_AREA(wa_test_support, 128);
+
+void test_print_port_info(void);
+THD_FUNCTION(test_support, arg);]]></value>
+ </global_definitions>
+ <global_code>
+ <value><![CDATA[void test_print_port_info(void) {
+
+#ifdef PORT_COMPILER_NAME
+ test_print("*** Compiler: ");
+ test_println(PORT_COMPILER_NAME);
+#endif
+ test_print("*** Architecture: ");
+ test_println(PORT_ARCHITECTURE_NAME);
+#ifdef PORT_CORE_VARIANT_NAME
+ test_print("*** Core Variant: ");
+ test_println(PORT_CORE_VARIANT_NAME);
+#endif
+#ifdef PORT_INFO
+ test_print("*** Port Info: ");
+ test_println(PORT_INFO);
+#endif
+}
+
+semaphore_t gsem1, gsem2;
+thread_reference_t gtr1;
+
+/*
+ * Support thread.
+ */
+THD_WORKING_AREA(wa_test_support, 128);
+THD_FUNCTION(test_support, arg) {
+#if CH_CFG_USE_EVENTS == TRUE
+ thread_t *tp = (thread_t *)arg;
+#else
+ (void)arg;
+#endif
+
+ /* Initializing global resources.*/
+ chSemObjectInit(&gsem1, 0);
+ chSemObjectInit(&gsem2, 0);
+
+ while (true) {
+ chSysLock();
+ if (chSemGetCounterI(&gsem1) < 0)
+ chSemSignalI(&gsem1);
+ chSemResetI(&gsem2, 0);
+ chThdResumeI(&gtr1, MSG_OK);
+#if CH_CFG_USE_EVENTS == TRUE
+ chEvtSignalI(tp, 0x55);
+#endif
+ chSchRescheduleS();
+ chSysUnlock();
+
+ chThdSleepMilliseconds(250);
+ }
+}]]></value>
+ </global_code>
+ </global_data_and_code>
+ <sequences>
+ <sequence>
+ <type index="0">
+ <value>Internal Tests</value>
+ </type>
+ <brief>
+ <value>Functional tests.</value>
+ </brief>
+ <description>
+ <value>The APIs are tested for functionality, correct cases and expected error cases are tested.</value>
+ </description>
+ <shared_code>
+ <value><![CDATA[#include <string.h>
+#include "key_storage.h"
+
+static const uint8_t pattern1[] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
+};
+
+static const uint8_t pattern2[] = {
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47
+};
+
+static const uint8_t pattern3[] = {
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57
+};
+
+static const uint8_t pattern512[] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63
+};]]></value>
+ </shared_code>
+ <cases>
+ <case>
+ <brief>
+ <value>Testing ksInit() behavior.</value>
+ </brief>
+ <description>
+ <value>The initialization function is tested. This function can fail only in case of Flash Array failures or in case of unexpected internal errors.</value>
+ </description>
+ <condition>
+ <value />
+ </condition>
+ <various_code>
+ <setup_code>
+ <value />
+ </setup_code>
+ <teardown_code>
+ <value><![CDATA[ksDeinit();]]></value>
+ </teardown_code>
+ <local_variables>
+ <value />
+ </local_variables>
+ </various_code>
+ <steps>
+ <step>
+ <description>
+ <value>Erasing the flash array using a low level function.</value>
+ </description>
+ <tags>
+ <value />
+ </tags>
+ <code>
+ <value><![CDATA[bool result;
+
+ks_lld_init();
+result = ks_lld_block_erase(KS_BLOCK0);
+test_assert(!result, "Block 0 erase failure");
+result = ks_lld_block_erase(KS_BLOCK1);
+test_assert(!result, "Block 1 erase failure");]]></value>
+ </code>
+ </step>
+ <step>
+ <description>
+ <value>Calling ksInit() on an uninitialized flash array, KS_NOERROR is expected.</value>
+ </description>
+ <tags>
+ <value />
+ </tags>
+ <code>
+ <value><![CDATA[kserror_t error;
+
+error = ksInit();
+test_assert(error == KS_NOERROR, "initialization error with erased flash");]]></value>
+ </code>
+ </step>
+ <step>
+ <description>
+ <value>Calling ksInit() on a newly initialized flash array, KS_NOERROR is expected.</value>
+ </description>
+ <tags>
+ <value />
+ </tags>
+ <code>
+ <value><![CDATA[kserror_t error;
+
+error = ksInit();
+test_assert(error == KS_NOERROR, "initialization error with initialized flash");]]></value>
+ </code>
+ </step>
+ </steps>
+ </case>
+ <case>
+ <brief>
+ <value>Checking for non existing keys.</value>
+ </brief>
+ <description>
+ <value>The keys space is explored with an initialized but empty keys storage, no key should exist.</value>
+ </description>
+ <condition>
+ <value />
+ </condition>
+ <various_code>
+ <setup_code>
+ <value><![CDATA[ksInit();]]></value>
+ </setup_code>
+ <teardown_code>
+ <value><![CDATA[ksDeinit();]]></value>
+ </teardown_code>
+ <local_variables>
+ <value />
+ </local_variables>
+ </various_code>
+ <steps>
+ <step>
+ <description>
+ <value>Exploring the keys space, KS_KEY_NOT_FOUND is expected for each key.</value>
+ </description>
+ <tags>
+ <value />
+ </tags>
+ <code>
+ <value><![CDATA[kserror_t error;
+kskey_t key;
+size_t size;
+uint8_t *keyp;
+
+for (key = 0; key < KS_CFG_NUM_KEYS; key++) {
+ error = ksGetKey(key, &size, &keyp);
+ test_assert(error == KS_KEY_NOT_FOUND,
+ "found a key that should not exists");
+}]]></value>
+ </code>
+ </step>
+ </steps>
+ </case>
+ <case>
+ <brief>
+ <value>Creating, updating and erasing a key.</value>
+ </brief>
+ <description>
+ <value>A key is created, updated several times with different payloads and finally erased.</value>
+ </description>
+ <condition>
+ <value />
+ </condition>
+ <various_code>
+ <setup_code>
+ <value><![CDATA[ksInit();]]></value>
+ </setup_code>
+ <teardown_code>
+ <value><![CDATA[ksDeinit();]]></value>
+ </teardown_code>
+ <local_variables>
+ <value><![CDATA[size_t size;
+uint8_t *keyp;]]></value>
+ </local_variables>
+ </various_code>
+ <steps>
+ <step>
+ <description>
+ <value>The key must not already exists, KS_KEY_NOT_FOUND is expected.</value>
+ </description>
+ <tags>
+ <value />
+ </tags>
+ <code>
+ <value><![CDATA[kserror_t error = ksGetKey(0, &size, &keyp);
+test_assert(error == KS_KEY_NOT_FOUND, "key was already present");]]></value>
+ </code>
+ </step>
+ <step>
+ <description>
+ <value>Creating the key then retrieving it again, KS_KEY_NOT_FOUND is expected, key content and size are compared with the original.</value>
+ </description>
+ <tags>
+ <value />
+ </tags>
+ <code>
+ <value><![CDATA[kserror_t error;
+
+error = ksWriteKey(0, sizeof(pattern1), pattern1);
+test_assert(error == KS_NOERROR, "error creating the key");
+error = ksGetKey(0, &size, &keyp);
+test_assert(error == KS_NOERROR, "key not found");
+test_assert(size == sizeof(pattern1), "unexpected key length");
+test_assert(memcmp(pattern1, keyp, size) == 0, "wrong key content");]]></value>
+ </code>
+ </step>
+ <step>
+ <description>
+ <value>Updating the key then retrieving it again, KS_NOERROR is expected, key content and size are compared with the original.</value>
+ </description>
+ <tags>
+ <value />
+ </tags>
+ <code>
+ <value><![CDATA[kserror_t error;
+
+error = ksWriteKey(0, sizeof(pattern2), pattern2);
+test_assert(error == KS_NOERROR, "error updating the key");
+error = ksGetKey(0, &size, &keyp);
+test_assert(error == KS_NOERROR, "key not found");
+test_assert(size == sizeof(pattern2), "unexpected key length");
+test_assert(memcmp(pattern2, keyp, size) == 0, "wrong key content");]]></value>
+ </code>
+ </step>
+ <step>
+ <description>
+ <value>Updating the key again with an unaligned key size then retrieving it again, KS_NOERROR is expected, key content and size are compared with the original.</value>
+ </description>
+ <tags>
+ <value />
+ </tags>
+ <code>
+ <value><![CDATA[kserror_t error;
+
+error = ksWriteKey(0, sizeof(pattern3), pattern3);
+test_assert(error == KS_NOERROR, "error updating the key");
+error = ksGetKey(0, &size, &keyp);
+test_assert(error == KS_NOERROR, "key not found");
+test_assert(size == sizeof(pattern3), "unexpected key length");
+test_assert(memcmp(pattern3, keyp, size) == 0, "wrong key content");]]></value>
+ </code>
+ </step>
+ <step>
+ <description>
+ <value>Erasing the key the then retrieving it, KS_NOERROR is expected on erase, KS_KEY_NOT_FOUND is expected on retrieve.</value>
+ </description>
+ <tags>
+ <value />
+ </tags>
+ <code>
+ <value><![CDATA[kserror_t error;
+
+error = ksEraseKey(0);
+test_assert(error == KS_NOERROR, "error erasing the key");
+error = ksGetKey(0, &size, &keyp);
+test_assert(error == KS_KEY_NOT_FOUND, "key not erased");]]></value>
+ </code>
+ </step>
+ </steps>
+ </case>
+ <case>
+ <brief>
+ <value>Erasing the whole storage.</value>
+ </brief>
+ <description>
+ <value>The key storage is erased and re-initialized.</value>
+ </description>
+ <condition>
+ <value />
+ </condition>
+ <various_code>
+ <setup_code>
+ <value><![CDATA[ks_lld_block_erase(KS_BLOCK0);
+ks_lld_block_erase(KS_BLOCK1);
+ksInit();]]></value>
+ </setup_code>
+ <teardown_code>
+ <value><![CDATA[ksDeinit();]]></value>
+ </teardown_code>
+ <local_variables>
+ <value />
+ </local_variables>
+ </various_code>
+ <steps>
+ <step>
+ <description>
+ <value>Creating keys 0, 1 and 2, KS_NOERROR is expected.</value>
+ </description>
+ <tags>
+ <value />
+ </tags>
+ <code>
+ <value><![CDATA[kserror_t error;
+
+error = ksWriteKey(0, sizeof(pattern1), pattern1);
+test_assert(error == KS_NOERROR, "error creating the key");
+error = ksWriteKey(1, sizeof(pattern2), pattern2);
+test_assert(error == KS_NOERROR, "error creating the key");
+error = ksWriteKey(2, sizeof(pattern3), pattern3);
+test_assert(error == KS_NOERROR, "error creating the key");]]></value>
+ </code>
+ </step>
+ <step>
+ <description>
+ <value>Erasing storage and verify that the keys have been removed, KS_NOERROR is expected on erase, KS_KEY_NOT_FOUND is expected on retrieve.</value>
+ </description>
+ <tags>
+ <value />
+ </tags>
+ <code>
+ <value><![CDATA[kserror_t error;
+size_t size;
+uint8_t *keyp;
+
+error = ksErase();
+test_assert(error == KS_NOERROR, "storage erase error");
+error = ksGetKey(0, &size, &keyp);
+test_assert(error == KS_KEY_NOT_FOUND, "key 0 still present");
+error = ksGetKey(1, &size, &keyp);
+test_assert(error == KS_KEY_NOT_FOUND, "key 1 still present");
+error = ksGetKey(2, &size, &keyp);
+test_assert(error == KS_KEY_NOT_FOUND, "key 2 still present");]]></value>
+ </code>
+ </step>
+ </steps>
+ </case>
+ <case>
+ <brief>
+ <value>Testing storage size limit.</value>
+ </brief>
+ <description>
+ <value>The storage is entirely filled with different keys and the final error is tested.</value>
+ </description>
+ <condition>
+ <value />
+ </condition>
+ <various_code>
+ <setup_code>
+ <value><![CDATA[ksInit();
+ksErase();]]></value>
+ </setup_code>
+ <teardown_code>
+ <value><![CDATA[ksDeinit();]]></value>
+ </teardown_code>
+ <local_variables>
+ <value />
+ </local_variables>
+ </various_code>
+ <steps>
+ <step>
+ <description>
+ <value>Filling up the storage by writing keys with increasing IDs, KS_NOERROR is expected.</value>
+ </description>
+ <tags>
+ <value />
+ </tags>
+ <code>
+ <value><![CDATA[kskey_t key;
+kskey_t kmax = (KS_LLD_BLOCKS_SIZE - sizeof(kskeyheader_t)) /
+ (sizeof(kskeyheader_t) + sizeof(pattern512));
+
+for (key = 0; key < kmax; key++) {
+ kserror_t error;
+ size_t size;
+ uint8_t *keyp;
+
+ error = ksWriteKey(key, sizeof(pattern512), pattern512);
+ test_assert(error == KS_NOERROR, "error creating the key");
+ error = ksGetKey(key, &size, &keyp);
+ test_assert(error == KS_NOERROR, "key not found");
+ test_assert(size == sizeof(pattern512), "unexpected key length");
+ test_assert(memcmp(pattern512, keyp, size) == 0, "wrong key content");
+}]]></value>
+ </code>
+ </step>
+ <step>
+ <description>
+ <value>Creating one more key, should fail, KS_OUT_OF_MEM is expected.</value>
+ </description>
+ <tags>
+ <value />
+ </tags>
+ <code>
+ <value><![CDATA[kserror_t error;
+kskey_t kmax = (KS_LLD_BLOCKS_SIZE - sizeof(kskeyheader_t)) /
+ (sizeof(kskeyheader_t) + sizeof(pattern512));
+
+error = ksWriteKey(kmax, sizeof(pattern512), pattern512);
+test_assert(error == KS_OUT_OF_MEM, "creation didn't fail");]]></value>
+ </code>
+ </step>
+ <step>
+ <description>
+ <value>Adding a smaller key to fill the final gap. A reinitialization is performed and KS_NOERROR is expected.</value>
+ </description>
+ <tags>
+ <value />
+ </tags>
+ <code>
+ <value><![CDATA[kserror_t error;
+size_t remaining;
+
+remaining = KS_LLD_BLOCK0_ADDRESS + KS_LLD_BLOCKS_SIZE - (size_t)ks.free_next;
+test_assert(remaining >= sizeof(kskeyheader_t), "not enough space");
+test_assert((remaining & KS_LLD_PAGE_SIZE) == 0, "unaligned space");
+
+if (remaining > sizeof(kskeyheader_t) * 2) {
+ error = ksWriteKey(KS_CFG_NUM_KEYS - 1,
+ remaining - (sizeof(kskeyheader_t) * 2),
+ pattern512);
+ test_assert(error == KS_NOERROR, "error filling remaining space");
+}
+else {
+ if (remaining == sizeof(kskeyheader_t) * 2) {
+ error = ksEraseKey(1);
+ test_assert(error == KS_NOERROR, "error filling remaining space");
+ }
+ error = ksEraseKey(0);
+ test_assert(error == KS_NOERROR, "error filling remaining space");
+}
+
+remaining = KS_LLD_BLOCK0_ADDRESS + KS_LLD_BLOCKS_SIZE - (size_t)ks.free_next;
+test_assert(remaining == 0, "remaining space not zero");
+
+ksDeinit();
+error = ksInit();
+test_assert(error == KS_NOERROR, "initialization error");]]></value>
+ </code>
+ </step>
+ </steps>
+ </case>
+ <case>
+ <brief>
+ <value>Testing garbage collection by writing.</value>
+ </brief>
+ <description>
+ <value>The garbage collection procedure is triggeredby a write operation and the state of both banks is checked.</value>
+ </description>
+ <condition>
+ <value />
+ </condition>
+ <various_code>
+ <setup_code>
+ <value><![CDATA[ksInit();
+ksErase();]]></value>
+ </setup_code>
+ <teardown_code>
+ <value><![CDATA[ksDeinit();]]></value>
+ </teardown_code>
+ <local_variables>
+ <value />
+ </local_variables>
+ </various_code>
+ <steps>
+ <step>
+ <description>
+ <value>Filling up the storage by writing keys with increasing IDs, KS_NOERROR is expected.</value>
+ </description>
+ <tags>
+ <value />
+ </tags>
+ <code>
+ <value><![CDATA[kskey_t key;
+kskey_t kmax = (KS_LLD_BLOCKS_SIZE - sizeof(kskeyheader_t)) /
+ (sizeof(kskeyheader_t) + sizeof(pattern512));
+
+for (key = 0; key < kmax; key++) {
+ kserror_t error;
+ size_t size;
+ uint8_t *keyp;
+
+ error = ksWriteKey(key, sizeof(pattern512), pattern512);
+ test_assert(error == KS_NOERROR, "error creating the key");
+ error = ksGetKey(key, &size, &keyp);
+ test_assert(error == KS_NOERROR, "key not found");
+ test_assert(size == sizeof(pattern512), "unexpected key length");
+ test_assert(memcmp(pattern512, keyp, size) == 0, "wrong key content");
+}]]></value>
+ </code>
+ </step>
+ <step>
+ <description>
+ <value>Erasing one key in the middle, KS_NOERROR is expected.</value>
+ </description>
+ <tags>
+ <value />
+ </tags>
+ <code>
+ <value><![CDATA[kserror_t error;
+size_t size;
+uint8_t *keyp;
+
+error = ksEraseKey(16);
+test_assert(error == KS_NOERROR, "error erasing the key");
+error = ksGetKey(16, &size, &keyp);
+test_assert(error == KS_KEY_NOT_FOUND, "key not erased");]]></value>
+ </code>
+ </step>
+ <step>
+ <description>
+ <value>Writing one more key triggers garbage collection, KS_WARNING is expected, KS state is checked for correctness after the operation.</value>
+ </description>
+ <tags>
+ <value />
+ </tags>
+ <code>
+ <value><![CDATA[kserror_t error;
+size_t size;
+uint8_t *keyp;
+
+test_assert(ks.header->fields.instance == 1, "not first instance");
+error = ksWriteKey(16, sizeof(pattern512), pattern512);
+test_assert(error == KS_WARNING, "error creating the key");
+test_assert(ks.header->fields.instance == 2, "not second instance");
+error = ksGetKey(16, &size, &keyp);
+test_assert(error == KS_NOERROR, "key not found");
+test_assert(size == sizeof(pattern512), "unexpected key length");
+test_assert(memcmp(pattern512, keyp, size) == 0, "wrong key content");
+test_assert(ks.block == KS_BLOCK1, "unexpected block");
+test_assert(ks_lld_is_block_erased(KS_BLOCK0) == true, "block 0 not erased");]]></value>
+ </code>
+ </step>
+ <step>
+ <description>
+ <value>Checking for all keys in the new bank, KS_NOERROR is expected for each key.</value>
+ </description>
+ <tags>
+ <value />
+ </tags>
+ <code>
+ <value><![CDATA[kskey_t key;
+kskey_t kmax = (KS_LLD_BLOCKS_SIZE - sizeof(kskeyheader_t)) /
+ (sizeof(kskeyheader_t) + sizeof(pattern512));
+
+for (key = 0; key < KS_CFG_NUM_KEYS; key++) {
+ kserror_t error;
+ size_t size;
+ uint8_t *keyp;
+
+ if (key < kmax) {
+ error = ksGetKey(key, &size, &keyp);
+ test_assert(error == KS_NOERROR, "key not found");
+ test_assert(size == sizeof(pattern512), "unexpected key length");
+ test_assert(memcmp(pattern512, keyp, size) == 0, "wrong key content");
+ }
+ else {
+ error = ksGetKey(key, &size, &keyp);
+ test_assert(error == KS_KEY_NOT_FOUND, "found unexpected key");
+ }
+}]]></value>
+ </code>
+ </step>
+ <step>
+ <description>
+ <value>Erasing one key in the middle, KS_NOERROR is expected.</value>
+ </description>
+ <tags>
+ <value />
+ </tags>
+ <code>
+ <value><![CDATA[kserror_t error;
+size_t size;
+uint8_t *keyp;
+
+error = ksEraseKey(16);
+test_assert(error == KS_NOERROR, "error erasing the key");
+error = ksGetKey(16, &size, &keyp);
+test_assert(error == KS_KEY_NOT_FOUND, "key not erased");]]></value>
+ </code>
+ </step>
+ <step>
+ <description>
+ <value>Writing one more key triggers garbage collection, KS_WARNING is expected, KS state is checked for correctness after the operation.</value>
+ </description>
+ <tags>
+ <value />
+ </tags>
+ <code>
+ <value><![CDATA[kserror_t error;
+size_t size;
+uint8_t *keyp;
+
+test_assert(ks.header->fields.instance == 2, "not second instance");
+error = ksWriteKey(16, sizeof(pattern512), pattern512);
+test_assert(error == KS_WARNING, "error creating the key");
+test_assert(ks.header->fields.instance == 3, "not third instance");
+error = ksGetKey(16, &size, &keyp);
+test_assert(error == KS_NOERROR, "key not found");
+test_assert(size == sizeof(pattern512), "unexpected key length");
+test_assert(memcmp(pattern512, keyp, size) == 0, "wrong key content");
+test_assert(ks.block == KS_BLOCK0, "unexpected block");
+test_assert(ks_lld_is_block_erased(KS_BLOCK1) == true, "block 0 not erased");]]></value>
+ </code>
+ </step>
+ <step>
+ <description>
+ <value>Checking for all keys in the new bank, KS_NOERROR is expected for each key.</value>
+ </description>
+ <tags>
+ <value />
+ </tags>
+ <code>
+ <value><![CDATA[kskey_t key;
+kskey_t kmax = (KS_LLD_BLOCKS_SIZE - sizeof(kskeyheader_t)) /
+ (sizeof(kskeyheader_t) + sizeof(pattern512));
+
+for (key = 0; key < KS_CFG_NUM_KEYS; key++) {
+ kserror_t error;
+ size_t size;
+ uint8_t *keyp;
+
+ if (key < kmax) {
+ error = ksGetKey(key, &size, &keyp);
+ test_assert(error == KS_NOERROR, "key not found");
+ test_assert(size == sizeof(pattern512), "unexpected key length");
+ test_assert(memcmp(pattern512, keyp, size) == 0, "wrong key content");
+ }
+ else {
+ error = ksGetKey(key, &size, &keyp);
+ test_assert(error == KS_KEY_NOT_FOUND, "found unexpected key");
+ }
+}]]></value>
+ </code>
+ </step>
+ </steps>
+ </case>
+ <case>
+ <brief>
+ <value>Testing garbage collection by erasing</value>
+ </brief>
+ <description>
+ <value>The garbage collection procedure is triggeredby an erase operation and the state of both banks is checked.</value>
+ </description>
+ <condition>
+ <value />
+ </condition>
+ <various_code>
+ <setup_code>
+ <value><![CDATA[ksInit();
+ksErase();]]></value>
+ </setup_code>
+ <teardown_code>
+ <value><![CDATA[ksDeinit();]]></value>
+ </teardown_code>
+ <local_variables>
+ <value />
+ </local_variables>
+ </various_code>
+ <steps>
+ <step>
+ <description>
+ <value>Filling up the storage by writing keys with increasing IDs, KS_NOERROR is expected.</value>
+ </description>
+ <tags>
+ <value />
+ </tags>
+ <code>
+ <value><![CDATA[kskey_t key;
+kskey_t kmax = (KS_LLD_BLOCKS_SIZE - sizeof(kskeyheader_t)) /
+ (sizeof(kskeyheader_t) + sizeof(pattern512));
+
+for (key = 0; key < kmax; key++) {
+ kserror_t error;
+ size_t size;
+ uint8_t *keyp;
+
+ error = ksWriteKey(key, sizeof(pattern512), pattern512);
+ test_assert(error == KS_NOERROR, "error creating the key");
+ error = ksGetKey(key, &size, &keyp);
+ test_assert(error == KS_NOERROR, "key not found");
+ test_assert(size == sizeof(pattern512), "unexpected key length");
+ test_assert(memcmp(pattern512, keyp, size) == 0, "wrong key content");
+}]]></value>
+ </code>
+ </step>
+ <step>
+ <description>
+ <value>Erase keys until the flash bank is filled entirely.</value>
+ </description>
+ <tags>
+ <value />
+ </tags>
+ <code>
+ <value><![CDATA[kserror_t error;
+size_t size;
+uint8_t *keyp;
+kskey_t key;
+kskey_t kmax = (KS_LLD_BLOCKS_SIZE - sizeof(kskeyheader_t)) /
+ (sizeof(kskeyheader_t) + sizeof(pattern512));
+kskey_t n = ((KS_LLD_BLOCKS_SIZE - sizeof(kskeyheader_t)) -
+ (kmax * (sizeof(kskeyheader_t) + sizeof(pattern512)))) /
+ sizeof(kskeyheader_t);
+
+for (key = 0; key < n; key++) {
+ error = ksEraseKey(key);
+ test_assert(error == KS_NOERROR, "error erasing the key");
+ error = ksGetKey(key, &size, &keyp);
+ test_assert(error == KS_KEY_NOT_FOUND, "key not erased");
+}]]></value>
+ </code>
+ </step>
+ <step>
+ <description>
+ <value>Erasing one more key triggers garbage collection, KS_WARNING is expected, KS state is checked for correctness after the operation.</value>
+ </description>
+ <tags>
+ <value />
+ </tags>
+ <code>
+ <value><![CDATA[kserror_t error;
+size_t size;
+uint8_t *keyp;
+
+test_assert(ks.header->fields.instance == 1, "not first instance");
+error = ksEraseKey(16);
+test_assert(error == KS_WARNING, "error erasing the key");
+test_assert(ks.header->fields.instance == 2, "not second instance");
+error = ksGetKey(16, &size, &keyp);
+test_assert(error == KS_KEY_NOT_FOUND, "key not erased");
+test_assert(ks.block == KS_BLOCK1, "unexpected block");
+test_assert(ks_lld_is_block_erased(KS_BLOCK0) == true, "block 0 not erased");]]></value>
+ </code>
+ </step>
+ </steps>
+ </case>
+ </cases>
+ </sequence>
+ </sequences>
+ </instance>
+ </instances>
+ <exportedFeatures />
+ </application>
+</SPC5-Config>
diff --git a/test/mfs/nil_test.mk b/test/mfs/nil_test.mk
new file mode 100644
index 000000000..c49541d73
--- /dev/null
+++ b/test/mfs/nil_test.mk
@@ -0,0 +1,9 @@
+# List of all the ChibiOS/NIL test files.
+TESTSRC += ${CHIBIOS}/test/nil/source/test/nil_test_root.c \
+ ${CHIBIOS}/test/nil/source/test/nil_test_sequence_001.c \
+ ${CHIBIOS}/test/nil/source/test/nil_test_sequence_002.c \
+ ${CHIBIOS}/test/nil/source/test/nil_test_sequence_003.c \
+ ${CHIBIOS}/test/nil/source/test/nil_test_sequence_004.c
+
+# Required include directories
+TESTINC += ${CHIBIOS}/test/nil/source/test
diff --git a/test/mfs/patch.xml b/test/mfs/patch.xml
new file mode 100644
index 000000000..879b2ed23
--- /dev/null
+++ b/test/mfs/patch.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<SPC5-Patch version="1.0.0">
+ <!--It is your patch repository, do not break your XML File.-->
+ <files />
+</SPC5-Patch>