mirror of
https://github.com/nqtronix/fifofast.git
synced 2026-02-06 00:52:43 +08:00
Add 'unittrace' and update the test code
Test fully passes
This commit is contained in:
@@ -51,6 +51,8 @@
|
||||
</ToolNumber>
|
||||
<ToolName xmlns="">Simulator</ToolName>
|
||||
</com_atmel_avrdbg_tool_simulator>
|
||||
<ResetRule>0</ResetRule>
|
||||
<EraseKey />
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
|
||||
<ToolchainSettings>
|
||||
@@ -88,47 +90,55 @@
|
||||
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
|
||||
<ToolchainSettings>
|
||||
<AvrGcc>
|
||||
<avrgcc.common.Device>-mmcu=atmega328p -B "%24(PackRepoDir)\atmel\ATmega_DFP\1.0.90\gcc\dev\atmega328p"</avrgcc.common.Device>
|
||||
<avrgcc.common.outputfiles.hex>True</avrgcc.common.outputfiles.hex>
|
||||
<avrgcc.common.outputfiles.lss>True</avrgcc.common.outputfiles.lss>
|
||||
<avrgcc.common.outputfiles.eep>True</avrgcc.common.outputfiles.eep>
|
||||
<avrgcc.common.outputfiles.srec>True</avrgcc.common.outputfiles.srec>
|
||||
<avrgcc.common.outputfiles.usersignatures>False</avrgcc.common.outputfiles.usersignatures>
|
||||
<avrgcc.compiler.general.ChangeDefaultCharTypeUnsigned>True</avrgcc.compiler.general.ChangeDefaultCharTypeUnsigned>
|
||||
<avrgcc.compiler.general.ChangeDefaultBitFieldUnsigned>True</avrgcc.compiler.general.ChangeDefaultBitFieldUnsigned>
|
||||
<avrgcc.compiler.symbols.DefSymbols>
|
||||
<ListValues>
|
||||
<Value>DEBUG</Value>
|
||||
</ListValues>
|
||||
</avrgcc.compiler.symbols.DefSymbols>
|
||||
<avrgcc.compiler.directories.IncludePaths>
|
||||
<ListValues>
|
||||
<Value>%24(PackRepoDir)\atmel\ATmega_DFP\1.0.90\include</Value>
|
||||
</ListValues>
|
||||
</avrgcc.compiler.directories.IncludePaths>
|
||||
<avrgcc.compiler.optimization.PackStructureMembers>True</avrgcc.compiler.optimization.PackStructureMembers>
|
||||
<avrgcc.compiler.optimization.AllocateBytesNeededForEnum>True</avrgcc.compiler.optimization.AllocateBytesNeededForEnum>
|
||||
<avrgcc.compiler.optimization.DebugLevel>Default (-g2)</avrgcc.compiler.optimization.DebugLevel>
|
||||
<avrgcc.compiler.warnings.AllWarnings>True</avrgcc.compiler.warnings.AllWarnings>
|
||||
<avrgcc.linker.libraries.Libraries>
|
||||
<ListValues>
|
||||
<Value>libm</Value>
|
||||
</ListValues>
|
||||
</avrgcc.linker.libraries.Libraries>
|
||||
<avrgcc.assembler.debugging.DebugLevel>Default (-Wa,-g)</avrgcc.assembler.debugging.DebugLevel>
|
||||
</AvrGcc>
|
||||
<avrgcc.common.Device>-mmcu=atmega328p -B "%24(PackRepoDir)\atmel\ATmega_DFP\1.0.90\gcc\dev\atmega328p"</avrgcc.common.Device>
|
||||
<avrgcc.common.outputfiles.hex>True</avrgcc.common.outputfiles.hex>
|
||||
<avrgcc.common.outputfiles.lss>True</avrgcc.common.outputfiles.lss>
|
||||
<avrgcc.common.outputfiles.eep>True</avrgcc.common.outputfiles.eep>
|
||||
<avrgcc.common.outputfiles.srec>True</avrgcc.common.outputfiles.srec>
|
||||
<avrgcc.common.outputfiles.usersignatures>False</avrgcc.common.outputfiles.usersignatures>
|
||||
<avrgcc.compiler.general.ChangeDefaultCharTypeUnsigned>True</avrgcc.compiler.general.ChangeDefaultCharTypeUnsigned>
|
||||
<avrgcc.compiler.general.ChangeDefaultBitFieldUnsigned>True</avrgcc.compiler.general.ChangeDefaultBitFieldUnsigned>
|
||||
<avrgcc.compiler.symbols.DefSymbols>
|
||||
<ListValues>
|
||||
<Value>DEBUG</Value>
|
||||
</ListValues>
|
||||
</avrgcc.compiler.symbols.DefSymbols>
|
||||
<avrgcc.compiler.directories.IncludePaths>
|
||||
<ListValues>
|
||||
<Value>%24(PackRepoDir)\atmel\ATmega_DFP\1.0.90\include</Value>
|
||||
<Value>../subrepos</Value>
|
||||
</ListValues>
|
||||
</avrgcc.compiler.directories.IncludePaths>
|
||||
<avrgcc.compiler.optimization.level>Optimize (-O1)</avrgcc.compiler.optimization.level>
|
||||
<avrgcc.compiler.optimization.PackStructureMembers>True</avrgcc.compiler.optimization.PackStructureMembers>
|
||||
<avrgcc.compiler.optimization.AllocateBytesNeededForEnum>True</avrgcc.compiler.optimization.AllocateBytesNeededForEnum>
|
||||
<avrgcc.compiler.optimization.DebugLevel>Default (-g2)</avrgcc.compiler.optimization.DebugLevel>
|
||||
<avrgcc.compiler.warnings.AllWarnings>True</avrgcc.compiler.warnings.AllWarnings>
|
||||
<avrgcc.linker.libraries.Libraries>
|
||||
<ListValues>
|
||||
<Value>libm</Value>
|
||||
</ListValues>
|
||||
</avrgcc.linker.libraries.Libraries>
|
||||
<avrgcc.assembler.debugging.DebugLevel>Default (-Wa,-g)</avrgcc.assembler.debugging.DebugLevel>
|
||||
</AvrGcc>
|
||||
</ToolchainSettings>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="fifofast.c">
|
||||
<SubType>compile</SubType>
|
||||
</Compile>
|
||||
<Compile Include="fifofast.h">
|
||||
<SubType>compile</SubType>
|
||||
</Compile>
|
||||
<Compile Include="fifofast_demo.c">
|
||||
<SubType>compile</SubType>
|
||||
</Compile>
|
||||
<Compile Include="subrepos\unittrace\unittrace.c">
|
||||
<SubType>compile</SubType>
|
||||
</Compile>
|
||||
<Compile Include="subrepos\unittrace\unittrace.h">
|
||||
<SubType>compile</SubType>
|
||||
</Compile>
|
||||
<Compile Include="subrepos\unittrace\utility\macros\com\macro_type.h">
|
||||
<SubType>compile</SubType>
|
||||
</Compile>
|
||||
<Compile Include="utility\macros\com\macro_array.h">
|
||||
<SubType>compile</SubType>
|
||||
</Compile>
|
||||
@@ -149,12 +159,35 @@
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="subrepos" />
|
||||
<Folder Include="subrepos\unittrace\" />
|
||||
<Folder Include="subrepos\unittrace\utility\" />
|
||||
<Folder Include="subrepos\unittrace\utility\macros\" />
|
||||
<Folder Include="subrepos\unittrace\utility\macros\com\" />
|
||||
<Folder Include="utility\" />
|
||||
<Folder Include="utility\macros\" />
|
||||
<Folder Include="utility\macros\com\" />
|
||||
<Folder Include="utility\macros\mpl\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="LICENSE.md">
|
||||
<SubType>compile</SubType>
|
||||
</None>
|
||||
<None Include="README.md">
|
||||
<SubType>compile</SubType>
|
||||
</None>
|
||||
<None Include="subrepos\readme %28license info%29.txt">
|
||||
<SubType>compile</SubType>
|
||||
</None>
|
||||
<None Include="subrepos\unittrace\LICENSE.md">
|
||||
<SubType>compile</SubType>
|
||||
</None>
|
||||
<None Include="subrepos\unittrace\README.md">
|
||||
<SubType>compile</SubType>
|
||||
</None>
|
||||
<None Include="subrepos\unittrace\utility\macros\com\com readme.txt">
|
||||
<SubType>compile</SubType>
|
||||
</None>
|
||||
<None Include="utility\macros\com\com readme.txt">
|
||||
<SubType>compile</SubType>
|
||||
</None>
|
||||
|
||||
337
fifofast_demo.c
337
fifofast_demo.c
@@ -10,6 +10,7 @@
|
||||
*/
|
||||
|
||||
#include "fifofast.h"
|
||||
#include "unittrace/unittrace.h"
|
||||
|
||||
// all declarations CAN be moved into a separate header file just like any other declaration
|
||||
|
||||
@@ -56,21 +57,7 @@ int main(void)
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// 'volatile' prevents compiler from removing these "unused" variables and thus allows
|
||||
// inspection during debugging. It is recommended to rightclick->watch each variable
|
||||
// Note: The compiler will throw a warning per variable, these can be safely ignored
|
||||
|
||||
// general inspection of data stored in fifo
|
||||
__attribute__ ((unused)) volatile uint8_t dbg0 = 0;
|
||||
__attribute__ ((unused)) volatile uint8_t dbg1 = 0;
|
||||
__attribute__ ((unused)) volatile uint8_t dbg2 = 0;
|
||||
__attribute__ ((unused)) volatile uint8_t dbg3 = 0;
|
||||
__attribute__ ((unused)) volatile uint8_t dbg4 = 0;
|
||||
|
||||
// for "_fff_read...()" macros only
|
||||
__attribute__ ((unused)) volatile uint8_t dbg_read0 = 0;
|
||||
__attribute__ ((unused)) volatile uint8_t dbg_read1 = 0;
|
||||
__attribute__ ((unused)) volatile uint8_t dbg_read2 = 0;
|
||||
__attribute__ ((unused)) volatile uint8_t dbg_read3 = 0;
|
||||
// inspection during debugging.
|
||||
|
||||
// for "_fff_add...()" macros only
|
||||
__attribute__ ((unused)) volatile uint8_t* dbg_p0 = 0;
|
||||
@@ -78,30 +65,23 @@ int main(void)
|
||||
__attribute__ ((unused)) volatile uint8_t* dbg_p2 = 0;
|
||||
__attribute__ ((unused)) volatile uint8_t* dbg_p3 = 0;
|
||||
|
||||
// inspection of macros that return a value
|
||||
__attribute__ ((unused)) volatile uint8_t dbg_mem_depth = 0;
|
||||
__attribute__ ((unused)) volatile uint8_t dbg_mem_mask = 0;
|
||||
__attribute__ ((unused)) volatile uint8_t dbg_mem_level = 0;
|
||||
__attribute__ ((unused)) volatile uint8_t dbg_mem_free = 0;
|
||||
__attribute__ ((unused)) volatile uint8_t dbg_is_empty = 0;
|
||||
__attribute__ ((unused)) volatile uint8_t dbg_is_full = 0;
|
||||
|
||||
// initialize all fifos
|
||||
__attribute__ ((unused)) _fff_init(fifo_uint8);
|
||||
__attribute__ ((unused)) _fff_init(fifo_int16);
|
||||
__attribute__ ((unused)) _fff_init(fifo_frame);
|
||||
asm volatile ("nop"); // easy breakpoint
|
||||
UT_BREAK();
|
||||
|
||||
|
||||
// Note: only fifo_uint8 is tested here as uint8 are most easy to work with
|
||||
// after each change (or set of changes) call all returning functions
|
||||
dbg_mem_depth = _fff_mem_depth(fifo_uint8); // = 4 (constant)
|
||||
dbg_mem_mask = _fff_mem_mask(fifo_uint8); // = 3 (= 0b11, constant)
|
||||
dbg_mem_level = _fff_mem_level(fifo_uint8); // = 0
|
||||
dbg_mem_free = _fff_mem_free(fifo_uint8); // = 3 (see macro description)
|
||||
dbg_is_empty = _fff_is_empty(fifo_uint8); // != 0 (= true, note that the actually value is NOT guaranteed to be '1'!)
|
||||
dbg_is_full = _fff_is_full(fifo_uint8); // = 0 (= false)
|
||||
asm volatile ("nop"); // easy breakpoint
|
||||
UT_ASSERT(_fff_mem_depth(fifo_uint8) == 4); // constant
|
||||
UT_ASSERT(_fff_mem_mask(fifo_uint8) == 3); // constant = 0b11
|
||||
UT_ASSERT(_fff_mem_level(fifo_uint8) == 0);
|
||||
UT_ASSERT(_fff_mem_free(fifo_uint8) == 3);
|
||||
UT_ASSERT(_fff_is_empty(fifo_uint8) != 0);
|
||||
UT_ASSERT(_fff_is_full(fifo_uint8) == 0);
|
||||
UT_BREAK();
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
@@ -113,36 +93,31 @@ int main(void)
|
||||
_fff_write_lite(fifo_uint8, 0x73);
|
||||
_fff_write_lite(fifo_uint8, 0x74);
|
||||
|
||||
dbg0 = _fff_peek(fifo_uint8, 0); // = 0x73
|
||||
dbg1 = _fff_peek(fifo_uint8, 1); // = 0x74
|
||||
dbg2 = _fff_peek(fifo_uint8, 2); // = "empty" = any value (not initialized)
|
||||
dbg3 = _fff_peek(fifo_uint8, 3); // = "empty" = any value (not initialized)
|
||||
|
||||
dbg_mem_depth = _fff_mem_depth(fifo_uint8); // = 4 (constant)
|
||||
dbg_mem_mask = _fff_mem_mask(fifo_uint8); // = 3 (= 0b11, constant)
|
||||
dbg_mem_level = _fff_mem_level(fifo_uint8); // = 2
|
||||
dbg_mem_free = _fff_mem_free(fifo_uint8); // = 1 (see macro description)
|
||||
dbg_is_empty = _fff_is_empty(fifo_uint8); // = 0 (= false)
|
||||
dbg_is_full = _fff_is_full(fifo_uint8); // = 0 (= false)
|
||||
asm volatile ("nop"); // easy breakpoint
|
||||
UT_ASSERT(_fff_mem_level(fifo_uint8) == 2);
|
||||
UT_ASSERT(_fff_mem_free(fifo_uint8) == 1);
|
||||
UT_ASSERT(_fff_is_empty(fifo_uint8) == 0);
|
||||
UT_ASSERT(_fff_is_full(fifo_uint8) == 0);
|
||||
|
||||
UT_ASSERT(_fff_peek(fifo_uint8, 0) == 0x73);
|
||||
UT_ASSERT(_fff_peek(fifo_uint8, 1) == 0x74);
|
||||
UT_BREAK();
|
||||
|
||||
|
||||
// add 3 values to demonstrate overflow safety
|
||||
_fff_write(fifo_uint8, 0x75);
|
||||
_fff_write(fifo_uint8, 0x76);
|
||||
_fff_write(fifo_uint8, 0x77);
|
||||
dbg0 = _fff_peek(fifo_uint8, 0); // = 0x73
|
||||
dbg1 = _fff_peek(fifo_uint8, 1); // = 0x74
|
||||
dbg2 = _fff_peek(fifo_uint8, 2); // = 0x75
|
||||
dbg3 = _fff_peek(fifo_uint8, 3); // = 0x76
|
||||
|
||||
dbg_mem_depth = _fff_mem_depth(fifo_uint8); // = 4 (constant)
|
||||
dbg_mem_mask = _fff_mem_mask(fifo_uint8); // = 3 (= 0b11, constant)
|
||||
dbg_mem_level = _fff_mem_level(fifo_uint8); // = 3 (see macro description)
|
||||
dbg_mem_free = _fff_mem_free(fifo_uint8); // = 0 (see macro description)
|
||||
dbg_is_empty = _fff_is_empty(fifo_uint8); // = 0 (= false)
|
||||
dbg_is_full = _fff_is_full(fifo_uint8); // != 0 (= true, note that the actually value is NOT guaranteed to be '1'!)
|
||||
asm volatile ("nop"); // easy breakpoint
|
||||
UT_ASSERT(_fff_mem_level(fifo_uint8) == 3);
|
||||
UT_ASSERT(_fff_mem_free(fifo_uint8) == 0);
|
||||
UT_ASSERT(_fff_is_empty(fifo_uint8) == 0);
|
||||
UT_ASSERT(_fff_is_full(fifo_uint8) != 0);
|
||||
|
||||
UT_ASSERT(_fff_peek(fifo_uint8, 0) == 0x73);
|
||||
UT_ASSERT(_fff_peek(fifo_uint8, 1) == 0x74);
|
||||
UT_ASSERT(_fff_peek(fifo_uint8, 2) == 0x75);
|
||||
UT_ASSERT(_fff_peek(fifo_uint8, 3) == 0x76);
|
||||
UT_BREAK();
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
@@ -152,22 +127,20 @@ int main(void)
|
||||
// modify existing value (index 0 and 2) with _fff_peek()
|
||||
_fff_peek(fifo_uint8, 0) = 0x53;
|
||||
_fff_peek(fifo_uint8, 2) = 0x55;
|
||||
|
||||
dbg0 = _fff_peek(fifo_uint8, 0); // = 0x53
|
||||
dbg1 = _fff_peek(fifo_uint8, 1); // = 0x74
|
||||
dbg2 = _fff_peek(fifo_uint8, 2); // = 0x55
|
||||
dbg3 = _fff_peek(fifo_uint8, 3); // = 0x76
|
||||
|
||||
// demonstrate "out of bounds" safety
|
||||
dbg4 = _fff_peek(fifo_uint8, 4); // = 0x53
|
||||
|
||||
dbg_mem_depth = _fff_mem_depth(fifo_uint8); // = 4 (constant)
|
||||
dbg_mem_mask = _fff_mem_mask(fifo_uint8); // = 3 (= 0b11, constant)
|
||||
dbg_mem_level = _fff_mem_level(fifo_uint8); // = 3 (see macro description)
|
||||
dbg_mem_free = _fff_mem_free(fifo_uint8); // = 0 (see macro description)
|
||||
dbg_is_empty = _fff_is_empty(fifo_uint8); // = 0 (= false)
|
||||
dbg_is_full = _fff_is_full(fifo_uint8); // != 0 (= true, note that the actually value is NOT guaranteed to be '1'!)
|
||||
asm volatile ("nop"); // easy breakpoint
|
||||
|
||||
UT_ASSERT(_fff_mem_level(fifo_uint8) == 3);
|
||||
UT_ASSERT(_fff_mem_free(fifo_uint8) == 0);
|
||||
UT_ASSERT(_fff_is_empty(fifo_uint8) == 0);
|
||||
UT_ASSERT(_fff_is_full(fifo_uint8) != 0);
|
||||
|
||||
UT_ASSERT(_fff_peek(fifo_uint8, 0) == 0x53);
|
||||
UT_ASSERT(_fff_peek(fifo_uint8, 1) == 0x74);
|
||||
UT_ASSERT(_fff_peek(fifo_uint8, 2) == 0x55);
|
||||
UT_ASSERT(_fff_peek(fifo_uint8, 3) == 0x76);
|
||||
// demonstrate "out of bounds" safety (no over-read/ over-write possible)
|
||||
UT_ASSERT(_fff_peek(fifo_uint8, 4) == 0x53);
|
||||
|
||||
UT_BREAK();
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
@@ -175,40 +148,29 @@ int main(void)
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// read 2 values with the fast '_lite' variant (we know we have written at least to entries)
|
||||
dbg_read0 = _fff_read_lite(fifo_uint8); // = 0x53
|
||||
dbg_read1 = _fff_read_lite(fifo_uint8); // = 0x74
|
||||
UT_ASSERT(_fff_read_lite(fifo_uint8) == 0x53);
|
||||
UT_ASSERT(_fff_read_lite(fifo_uint8) == 0x74);
|
||||
|
||||
dbg0 = _fff_peek(fifo_uint8, 0); // = 0x55
|
||||
dbg1 = _fff_peek(fifo_uint8, 1); // = 0x76
|
||||
dbg2 = _fff_peek(fifo_uint8, 2); // = "empty" = any value (empty elements are NOT reset back to '0'!)
|
||||
dbg3 = _fff_peek(fifo_uint8, 3); // = "empty" = any value
|
||||
|
||||
dbg_mem_depth = _fff_mem_depth(fifo_uint8); // = 4 (constant)
|
||||
dbg_mem_mask = _fff_mem_mask(fifo_uint8); // = 3 (= 0b11, constant)
|
||||
dbg_mem_level = _fff_mem_level(fifo_uint8); // = 2
|
||||
dbg_mem_free = _fff_mem_free(fifo_uint8); // = 1 (see macro description)
|
||||
dbg_is_empty = _fff_is_empty(fifo_uint8); // = 0 (= false)
|
||||
dbg_is_full = _fff_is_full(fifo_uint8); // = 0 (= false)
|
||||
asm volatile ("nop"); // easy breakpoint
|
||||
UT_ASSERT(_fff_mem_level(fifo_uint8) == 2);
|
||||
UT_ASSERT(_fff_mem_free(fifo_uint8) == 1);
|
||||
UT_ASSERT(_fff_is_empty(fifo_uint8) == 0);
|
||||
UT_ASSERT(_fff_is_full(fifo_uint8) == 0);
|
||||
|
||||
UT_ASSERT(_fff_peek(fifo_uint8, 0) == 0x55);
|
||||
UT_ASSERT(_fff_peek(fifo_uint8, 1) == 0x76);
|
||||
UT_BREAK();
|
||||
|
||||
|
||||
// read 3 values t demonstrate overflow safety
|
||||
dbg_read0 = _fff_read(fifo_uint8); // = 0x55
|
||||
dbg_read1 = _fff_read(fifo_uint8); // = 0x76
|
||||
dbg_read2 = _fff_read(fifo_uint8); // = 0x00 (returns always 0 if empty)
|
||||
UT_ASSERT(_fff_read(fifo_uint8) == 0x55);
|
||||
UT_ASSERT(_fff_read(fifo_uint8) == 0x76);
|
||||
UT_ASSERT(_fff_read(fifo_uint8) == 0x00);
|
||||
|
||||
dbg0 = _fff_peek(fifo_uint8, 0); // = "empty" = any value (empty elements are NOT reset back to '0'!)
|
||||
dbg1 = _fff_peek(fifo_uint8, 1); // = "empty" = any value
|
||||
dbg2 = _fff_peek(fifo_uint8, 2); // = "empty" = any value
|
||||
dbg3 = _fff_peek(fifo_uint8, 3); // = "empty" = any value
|
||||
|
||||
dbg_mem_depth = _fff_mem_depth(fifo_uint8); // = 4 (constant)
|
||||
dbg_mem_mask = _fff_mem_mask(fifo_uint8); // = 3 (= 0b11, constant)
|
||||
dbg_mem_level = _fff_mem_level(fifo_uint8); // = 0
|
||||
dbg_mem_free = _fff_mem_free(fifo_uint8); // = 3 (see macro description)
|
||||
dbg_is_empty = _fff_is_empty(fifo_uint8); // != 0 (= true)
|
||||
dbg_is_full = _fff_is_full(fifo_uint8); // = 0 (= false)
|
||||
asm volatile ("nop"); // easy breakpoint
|
||||
UT_ASSERT(_fff_mem_level(fifo_uint8) == 0);
|
||||
UT_ASSERT(_fff_mem_free(fifo_uint8) == 3);
|
||||
UT_ASSERT(_fff_is_empty(fifo_uint8) != 0);
|
||||
UT_ASSERT(_fff_is_full(fifo_uint8) == 0);
|
||||
UT_BREAK();
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
@@ -223,18 +185,14 @@ int main(void)
|
||||
if(dbg_p0 != 0) *dbg_p0 = 0x3a;
|
||||
if(dbg_p1 != 0) *dbg_p1 = 0x3b;
|
||||
|
||||
dbg0 = _fff_peek(fifo_uint8, 0); // = 0x3a
|
||||
dbg1 = _fff_peek(fifo_uint8, 1); // = 0x3b
|
||||
dbg2 = _fff_peek(fifo_uint8, 2); // = "empty" = any value (not initialized)
|
||||
dbg3 = _fff_peek(fifo_uint8, 3); // = "empty" = any value (not initialized)
|
||||
|
||||
dbg_mem_depth = _fff_mem_depth(fifo_uint8); // = 4 (constant)
|
||||
dbg_mem_mask = _fff_mem_mask(fifo_uint8); // = 3 (= 0b11, constant)
|
||||
dbg_mem_level = _fff_mem_level(fifo_uint8); // = 2
|
||||
dbg_mem_free = _fff_mem_free(fifo_uint8); // = 1 (see macro description)
|
||||
dbg_is_empty = _fff_is_empty(fifo_uint8); // = 0 (= false)
|
||||
dbg_is_full = _fff_is_full(fifo_uint8); // = 0 (= false)
|
||||
asm volatile ("nop"); // easy breakpoint
|
||||
UT_ASSERT(_fff_mem_level(fifo_uint8) == 2);
|
||||
UT_ASSERT(_fff_mem_free(fifo_uint8) == 1);
|
||||
UT_ASSERT(_fff_is_empty(fifo_uint8) == 0);
|
||||
UT_ASSERT(_fff_is_full(fifo_uint8) == 0);
|
||||
|
||||
UT_ASSERT(_fff_peek(fifo_uint8, 0) == 0x3a);
|
||||
UT_ASSERT(_fff_peek(fifo_uint8, 1) == 0x3b);
|
||||
UT_BREAK();
|
||||
|
||||
|
||||
// add 3 values to demonstrate overflow safety
|
||||
@@ -246,18 +204,16 @@ int main(void)
|
||||
if(dbg_p1 != 0) *dbg_p1 = 0x3d;
|
||||
if(dbg_p2 != 0) *dbg_p2 = 0x3e;
|
||||
|
||||
dbg0 = _fff_peek(fifo_uint8, 0); // = 0x3a
|
||||
dbg1 = _fff_peek(fifo_uint8, 1); // = 0x3b
|
||||
dbg2 = _fff_peek(fifo_uint8, 2); // = 0x3c
|
||||
dbg3 = _fff_peek(fifo_uint8, 3); // = 0x3d
|
||||
|
||||
dbg_mem_depth = _fff_mem_depth(fifo_uint8); // = 4 (constant)
|
||||
dbg_mem_mask = _fff_mem_mask(fifo_uint8); // = 3 (= 0b11, constant)
|
||||
dbg_mem_level = _fff_mem_level(fifo_uint8); // = 3 (see macro description)
|
||||
dbg_mem_free = _fff_mem_free(fifo_uint8); // = 0 (see macro description)
|
||||
dbg_is_empty = _fff_is_empty(fifo_uint8); // = 0 (= false)
|
||||
dbg_is_full = _fff_is_full(fifo_uint8); // != 0 (= true, note that the actually value is NOT guaranteed to be '1'!)
|
||||
asm volatile ("nop"); // easy breakpoint
|
||||
UT_ASSERT(_fff_mem_level(fifo_uint8) == 3);
|
||||
UT_ASSERT(_fff_mem_free(fifo_uint8) == 0);
|
||||
UT_ASSERT(_fff_is_empty(fifo_uint8) == 0);
|
||||
UT_ASSERT(_fff_is_full(fifo_uint8) != 0);
|
||||
|
||||
UT_ASSERT(_fff_peek(fifo_uint8, 0) == 0x3a);
|
||||
UT_ASSERT(_fff_peek(fifo_uint8, 1) == 0x3b);
|
||||
UT_ASSERT(_fff_peek(fifo_uint8, 2) == 0x3c);
|
||||
UT_ASSERT(_fff_peek(fifo_uint8, 3) == 0x3d);
|
||||
UT_BREAK();
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
@@ -266,20 +222,13 @@ int main(void)
|
||||
|
||||
// only header is reset to its initial values which marks all present data as "empty" (but data
|
||||
// is not reset to 0)
|
||||
_fff_reset(fifo_uint8);
|
||||
_fff_reset(fifo_uint8);
|
||||
|
||||
dbg0 = _fff_peek(fifo_uint8, 0); // = 0x3a
|
||||
dbg1 = _fff_peek(fifo_uint8, 1); // = 0x3b
|
||||
dbg2 = _fff_peek(fifo_uint8, 2); // = 0x3c
|
||||
dbg3 = _fff_peek(fifo_uint8, 3); // = 0x3d
|
||||
|
||||
dbg_mem_depth = _fff_mem_depth(fifo_uint8); // = 4 (constant)
|
||||
dbg_mem_mask = _fff_mem_mask(fifo_uint8); // = 3 (= 0b11, constant)
|
||||
dbg_mem_level = _fff_mem_level(fifo_uint8); // = 3 (see macro description)
|
||||
dbg_mem_free = _fff_mem_free(fifo_uint8); // = 0 (see macro description)
|
||||
dbg_is_empty = _fff_is_empty(fifo_uint8); // = 0 (= false)
|
||||
dbg_is_full = _fff_is_full(fifo_uint8); // != 0 (= true, note that the actually value is NOT guaranteed to be '1'!)
|
||||
asm volatile ("nop"); // easy breakpoint
|
||||
UT_ASSERT(_fff_mem_level(fifo_uint8) == 0);
|
||||
UT_ASSERT(_fff_mem_free(fifo_uint8) == 3);
|
||||
UT_ASSERT(_fff_is_empty(fifo_uint8) != 0);
|
||||
UT_ASSERT(_fff_is_full(fifo_uint8) == 0);
|
||||
UT_BREAK();
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
@@ -295,51 +244,37 @@ int main(void)
|
||||
|
||||
// _remove 2 (Test case: fifo full before macro)
|
||||
_fff_remove_lite(fifo_uint8, 2);
|
||||
|
||||
UT_ASSERT(_fff_mem_level(fifo_uint8) == 2);
|
||||
UT_ASSERT(_fff_mem_free(fifo_uint8) == 1);
|
||||
UT_ASSERT(_fff_is_empty(fifo_uint8) == 0);
|
||||
UT_ASSERT(_fff_is_full(fifo_uint8) == 0);
|
||||
|
||||
UT_ASSERT(_fff_peek(fifo_uint8, 0) == 0x25);
|
||||
UT_ASSERT(_fff_peek(fifo_uint8, 1) == 0x26);
|
||||
UT_BREAK();
|
||||
|
||||
dbg0 = _fff_peek(fifo_uint8, 0); // = 0x25
|
||||
dbg1 = _fff_peek(fifo_uint8, 1); // = 0x26
|
||||
dbg2 = _fff_peek(fifo_uint8, 2); // = 0x23 (empty)
|
||||
dbg3 = _fff_peek(fifo_uint8, 3); // = 0x24 (empty)
|
||||
|
||||
dbg_mem_depth = _fff_mem_depth(fifo_uint8); // = 4 (constant)
|
||||
dbg_mem_mask = _fff_mem_mask(fifo_uint8); // = 3 (= 0b11, constant)
|
||||
dbg_mem_level = _fff_mem_level(fifo_uint8); // = 2 (see macro description)
|
||||
dbg_mem_free = _fff_mem_free(fifo_uint8); // = 1 (see macro description)
|
||||
dbg_is_empty = _fff_is_empty(fifo_uint8); // = 0 (= false)
|
||||
dbg_is_full = _fff_is_full(fifo_uint8); // = 0 (= false)
|
||||
asm volatile ("nop"); // easy breakpoint
|
||||
|
||||
// _remove 1 (Test case: fifo not full before and not empty after macro)
|
||||
_fff_remove_lite(fifo_uint8, 1);
|
||||
|
||||
dbg0 = _fff_peek(fifo_uint8, 0); // = 0x26
|
||||
dbg1 = _fff_peek(fifo_uint8, 1); // = 0x23 (empty)
|
||||
dbg2 = _fff_peek(fifo_uint8, 2); // = 0x24 (empty)
|
||||
dbg3 = _fff_peek(fifo_uint8, 3); // = 0x25 (empty)
|
||||
|
||||
dbg_mem_depth = _fff_mem_depth(fifo_uint8); // = 4 (constant)
|
||||
dbg_mem_mask = _fff_mem_mask(fifo_uint8); // = 3 (= 0b11, constant)
|
||||
dbg_mem_level = _fff_mem_level(fifo_uint8); // = 1 (see macro description)
|
||||
dbg_mem_free = _fff_mem_free(fifo_uint8); // = 2 (see macro description)
|
||||
dbg_is_empty = _fff_is_empty(fifo_uint8); // = 0 (= false)
|
||||
dbg_is_full = _fff_is_full(fifo_uint8); // = 0 (= false)
|
||||
asm volatile ("nop"); // easy breakpoint
|
||||
UT_ASSERT(_fff_mem_level(fifo_uint8) == 1);
|
||||
UT_ASSERT(_fff_mem_free(fifo_uint8) == 2);
|
||||
UT_ASSERT(_fff_is_empty(fifo_uint8) == 0);
|
||||
UT_ASSERT(_fff_is_full(fifo_uint8) == 0);
|
||||
|
||||
UT_ASSERT(_fff_peek(fifo_uint8, 0) == 0x26);
|
||||
UT_BREAK();
|
||||
|
||||
|
||||
// _remove 1 (Test case: fifo empty after macro)
|
||||
_fff_remove_lite(fifo_uint8, 1);
|
||||
|
||||
dbg0 = _fff_peek(fifo_uint8, 0); // = 0x23 (empty)
|
||||
dbg1 = _fff_peek(fifo_uint8, 1); // = 0x24 (empty)
|
||||
dbg2 = _fff_peek(fifo_uint8, 2); // = 0x25 (empty)
|
||||
dbg3 = _fff_peek(fifo_uint8, 3); // = 0x26 (empty)
|
||||
|
||||
dbg_mem_depth = _fff_mem_depth(fifo_uint8); // = 4 (constant)
|
||||
dbg_mem_mask = _fff_mem_mask(fifo_uint8); // = 3 (= 0b11, constant)
|
||||
dbg_mem_level = _fff_mem_level(fifo_uint8); // = 0 (see macro description)
|
||||
dbg_mem_free = _fff_mem_free(fifo_uint8); // = 3 (see macro description)
|
||||
dbg_is_empty = _fff_is_empty(fifo_uint8); // != 0 (= true, note that the actually value is NOT guaranteed to be '1'!)
|
||||
dbg_is_full = _fff_is_full(fifo_uint8); // = 0 (= false)
|
||||
asm volatile ("nop"); // easy breakpoint
|
||||
UT_ASSERT(_fff_mem_level(fifo_uint8) == 0);
|
||||
UT_ASSERT(_fff_mem_free(fifo_uint8) == 3);
|
||||
UT_ASSERT(_fff_is_empty(fifo_uint8) != 0);
|
||||
UT_ASSERT(_fff_is_full(fifo_uint8) == 0);
|
||||
UT_BREAK();
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
@@ -353,53 +288,42 @@ int main(void)
|
||||
_fff_write_lite(fifo_uint8, 0x16);
|
||||
// fifo is now full
|
||||
|
||||
|
||||
// _remove 0 (Test case: amount <= 0 elements)
|
||||
_fff_remove(fifo_uint8, 0);
|
||||
|
||||
dbg0 = _fff_peek(fifo_uint8, 0); // = 0x13
|
||||
dbg1 = _fff_peek(fifo_uint8, 1); // = 0x14
|
||||
dbg2 = _fff_peek(fifo_uint8, 2); // = 0x15
|
||||
dbg3 = _fff_peek(fifo_uint8, 3); // = 0x16
|
||||
UT_ASSERT(_fff_mem_level(fifo_uint8) == 3);
|
||||
UT_ASSERT(_fff_mem_free(fifo_uint8) == 0);
|
||||
UT_ASSERT(_fff_is_empty(fifo_uint8) == 0);
|
||||
UT_ASSERT(_fff_is_full(fifo_uint8) != 0);
|
||||
|
||||
UT_ASSERT(_fff_peek(fifo_uint8, 0) == 0x13);
|
||||
UT_ASSERT(_fff_peek(fifo_uint8, 1) == 0x14);
|
||||
UT_ASSERT(_fff_peek(fifo_uint8, 2) == 0x15);
|
||||
UT_ASSERT(_fff_peek(fifo_uint8, 3) == 0x16);
|
||||
UT_BREAK();
|
||||
|
||||
dbg_mem_depth = _fff_mem_depth(fifo_uint8); // = 4 (constant)
|
||||
dbg_mem_mask = _fff_mem_mask(fifo_uint8); // = 3 (= 0b11, constant)
|
||||
dbg_mem_level = _fff_mem_level(fifo_uint8); // = 0 (see macro description)
|
||||
dbg_mem_free = _fff_mem_free(fifo_uint8); // = 3 (see macro description)
|
||||
dbg_is_empty = _fff_is_empty(fifo_uint8); // = 0 (= false)
|
||||
dbg_is_full = _fff_is_full(fifo_uint8); // != 0 (= true, note that the actually value is NOT guaranteed to be '1'!)
|
||||
asm volatile ("nop"); // easy breakpoint
|
||||
|
||||
// _remove 4 (Test case: amount > _fff_mem_level() w/ fifo full)
|
||||
_fff_remove(fifo_uint8, 4);
|
||||
|
||||
dbg0 = _fff_peek(fifo_uint8, 0); // = 0x16
|
||||
dbg1 = _fff_peek(fifo_uint8, 1); // = 0x13 (empty)
|
||||
dbg2 = _fff_peek(fifo_uint8, 2); // = 0x14 (empty)
|
||||
dbg3 = _fff_peek(fifo_uint8, 3); // = 0x15 (empty)
|
||||
UT_ASSERT(_fff_mem_level(fifo_uint8) == 1);
|
||||
UT_ASSERT(_fff_mem_free(fifo_uint8) == 2);
|
||||
UT_ASSERT(_fff_is_empty(fifo_uint8) == 0);
|
||||
UT_ASSERT(_fff_is_full(fifo_uint8) == 0);
|
||||
|
||||
UT_ASSERT(_fff_peek(fifo_uint8, 0) == 0x16);
|
||||
UT_BREAK();
|
||||
|
||||
dbg_mem_depth = _fff_mem_depth(fifo_uint8); // = 4 (constant)
|
||||
dbg_mem_mask = _fff_mem_mask(fifo_uint8); // = 3 (= 0b11, constant)
|
||||
dbg_mem_level = _fff_mem_level(fifo_uint8); // = 1 (see macro description)
|
||||
dbg_mem_free = _fff_mem_free(fifo_uint8); // = 2 (see macro description)
|
||||
dbg_is_empty = _fff_is_empty(fifo_uint8); // = 0 (= false)
|
||||
dbg_is_full = _fff_is_full(fifo_uint8); // = 0 (= false)
|
||||
asm volatile ("nop"); // easy breakpoint
|
||||
|
||||
// _remove 4 (Test case: amount > _fff_mem_level() w/ fifo not full)
|
||||
_fff_remove(fifo_uint8, 4);
|
||||
|
||||
dbg0 = _fff_peek(fifo_uint8, 0); // = 0x13 (empty)
|
||||
dbg1 = _fff_peek(fifo_uint8, 1); // = 0x14 (empty)
|
||||
dbg2 = _fff_peek(fifo_uint8, 2); // = 0x15 (empty)
|
||||
dbg3 = _fff_peek(fifo_uint8, 3); // = 0x16 (empty)
|
||||
|
||||
dbg_mem_depth = _fff_mem_depth(fifo_uint8); // = 4 (constant)
|
||||
dbg_mem_mask = _fff_mem_mask(fifo_uint8); // = 3 (= 0b11, constant)
|
||||
dbg_mem_level = _fff_mem_level(fifo_uint8); // = 0 (see macro description)
|
||||
dbg_mem_free = _fff_mem_free(fifo_uint8); // = 3 (see macro description)
|
||||
dbg_is_empty = _fff_is_empty(fifo_uint8); // != 0 (= true, note that the actually value is NOT guaranteed to be '1'!)
|
||||
dbg_is_full = _fff_is_full(fifo_uint8); // = 0 (= false)
|
||||
asm volatile ("nop"); // easy breakpoint
|
||||
UT_ASSERT(_fff_mem_level(fifo_uint8) == 0);
|
||||
UT_ASSERT(_fff_mem_free(fifo_uint8) == 3);
|
||||
UT_ASSERT(_fff_is_empty(fifo_uint8) != 0);
|
||||
UT_ASSERT(_fff_is_full(fifo_uint8) == 0);
|
||||
UT_BREAK();
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
@@ -422,5 +346,4 @@ int main(void)
|
||||
|
||||
// End simulation
|
||||
while (1) asm volatile ("nop");
|
||||
}
|
||||
|
||||
}
|
||||
1
subrepos/readme (license info).txt
Normal file
1
subrepos/readme (license info).txt
Normal file
@@ -0,0 +1 @@
|
||||
This folder contains other projects with their own source code and associated files. The included LICENSE files ONLY apply to the folder (and the project) they are located in.
|
||||
2
subrepos/unittrace/.gitignore
vendored
Normal file
2
subrepos/unittrace/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
/Debug
|
||||
/.vs
|
||||
21
subrepos/unittrace/LICENSE.md
Normal file
21
subrepos/unittrace/LICENSE.md
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018 nqtronix (github.com/nqtronix)
|
||||
|
||||
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.
|
||||
276
subrepos/unittrace/README.md
Normal file
276
subrepos/unittrace/README.md
Normal file
@@ -0,0 +1,276 @@
|
||||
<h1 align="center" style="font-weight: bold; margin-top: 20px; margin-bottom: 20px;">unittrace</h4>
|
||||
|
||||
<h4 align="center"> A simple testing and debugging tool for MCUs inspired by <a href="http://www.jera.com/techinfo/jtns/jtn002.html" target="_blank">MinUnit</a>.</h4>
|
||||
|
||||
<p align="center">
|
||||
<a href="#changelog"><img src="https://img.shields.io/github/release-pre/nqtronix/unittrace.svg" alt="release: NA"></a>
|
||||
<a href="#about"><img src="https://img.shields.io/badge/language-C_(GCC_5.4.0)-blue.svg" alt="language: C GCC (5.4.0)"></a>
|
||||
<a href="#about"><img src="https://img.shields.io/badge/platform-MCUs, AVR8-blue.svg" alt="platform: MCUs, AVR8"></a>
|
||||
<a href="#about"><img src="https://img.shields.io/badge/status-maintained-green.svg" alt="status: maintained"></a>
|
||||
<a href="https://github.com/nqtronix/unittrace/issues"><img src="https://img.shields.io/github/issues/nqtronix/unittrace.svg" alt="issues: NA"></a>
|
||||
<a href="#license"><img src="https://img.shields.io/github/license/nqtronix/unittrace.svg" alt="license: NA"></a>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="#getting-started">Getting Started</a> •
|
||||
<a href="#documentation">Documentation</a> •
|
||||
<a href="#under-the-hood">Under the Hood</a> •
|
||||
<a href="#support">Need Help?</a> •
|
||||
<a href="#about">About</a> •
|
||||
<a href="#credits-and-references">Credits</a>
|
||||
</p>
|
||||
|
||||
|
||||
|
||||
## Introduction
|
||||
Testing is an important part of writing code, especially if the code is meant to be re-used for other projects. On small MCUs testing can be quite tricky as the memory is limited and errors can't be easily reported with `printf()` or similar.
|
||||
|
||||
**unittrace** provides basic testing functionality and is designed with the limits of MCUs in mind. It runs directly on the hardware and thus can catch errors other test software can't. Fetch the results through a debugger or with a function.
|
||||
|
||||
<br>
|
||||
|
||||
## Key Features
|
||||
|
||||
- **lightweight:** absolute minimum Flash & RAM usage
|
||||
- **runtime test:** catches both software and hardware errors
|
||||
- **static memory**: no malloc overhead
|
||||
|
||||
<br>
|
||||
|
||||
## Limitations
|
||||
|
||||
- on AVR8 MCUs the maximum usable flash memory is 128KB or 64K words, as the address must fit into the 16bit pointer. On 32bit MCUs pointers are always 32bit and therefore there is no upper limit.
|
||||
|
||||
<br>
|
||||
|
||||
## Usage Example
|
||||
**unittrace** is ridiculously simple to use. You can place the `ut_assert` functions wherever you want:
|
||||
|
||||
```c
|
||||
int main(void)
|
||||
{
|
||||
// using inline functions
|
||||
ut_assert(5 == 5); // passes
|
||||
ut_assert(5 == 7); // fails and code address gets stored in array
|
||||
|
||||
// using macros (equivalently behavior to functions)
|
||||
UT_ASSERT(5 == 5); // passes
|
||||
UT_ASSERT(5 == 7); // fails and code address gets stored in array
|
||||
|
||||
// set a breakpoint
|
||||
UT_BREAK();
|
||||
while (1);
|
||||
}
|
||||
```
|
||||
[](#interpreting-the-data)
|
||||
|
||||
<br>
|
||||
|
||||
## Getting Started
|
||||
This section is written especially for everyone who is **not familiar** with the used tools. If you run into problems, please [ask for clarification](#get-help).<br>
|
||||
|
||||
### Step 1: Software and Tools
|
||||
- [**Atmel Studio 7.0**][tool-atmel-studio-7-0]** (Build 1931) [free**]<br>
|
||||
The installer contains all tools you need to open, edit, compile, simulate and flash this code. If you favor another development tool, feel free to use it instead. (But please understand that I can not provide any support).
|
||||
- **An AVR8 ISP/JTAG programmer [optional]**<br>
|
||||
To program AVR8 MCUs I use the [AVR Dragon][tool-avr-dragon]. It can be also used as a debugger and is available within Atmel Studio by default.
|
||||
|
||||
### Step 2: Download unittrace
|
||||
- Clone this repository or hit [Download][git-download] and extract the .zip file.
|
||||
|
||||
### Step 3: Browse the project
|
||||
- **Open the project in Atmel Studio:**<br>
|
||||
Either double click `unittrace.atsln` or open Atmel Studio and select "File -> Open -> Project/Solution..."
|
||||
|
||||
- **Open any file of your interest:**<br>
|
||||
Select the file in the top right window "Solution Explorer". If the window is not visible, open it by pressing `CTRL + ALT + L` or selecting "View -> Solution Explorer" from the menu.
|
||||
|
||||
### Step 4: Run the demo
|
||||
- **Compile the demo code:**<br>
|
||||
Press `F7` or select "Build -> Build Solution" from the menu
|
||||
|
||||
- **Run the demo code in the simulator:**<br>
|
||||
Press `CTRL + F5` or select "Debug -> Start Debugging and Break" from the menu
|
||||
|
||||
- **Place breakpoints:**<br>
|
||||
Left-Click on the light grey area left of the code to place or remove a breakpoint. Select lines with the comment "easy breakpoint".
|
||||
|
||||
- **View variable values:**<br>
|
||||
When the code is paused, hover over any variable to display its value. Alternately you can "Right-Click -> Watch" to display the value in the "watch window".
|
||||
|
||||
- **Run Code:**<br>
|
||||
Press `F5` to run to the next breakpoint or `F10` to execute one step.
|
||||
|
||||
### Step 5: Going further
|
||||
- **Changing the target device:**<br>
|
||||
Press `ALT + F7` and select "Device -> Change device..." to select your desired MCU.
|
||||
|
||||
- **Program a real device:**<br>
|
||||
Connect your programmer, press `ALT + F7` and select "Tool". Choose your tool, your programming interface and wire up your MCU. Press `CTRL + ALT + F7` to flash the code to the MCU. Non-official programmers are not supported by Atmel Studio.
|
||||
|
||||
<br>
|
||||
|
||||
## Documentation
|
||||
|
||||
### Interpreting the Data
|
||||
|
||||
The results of the test can be accessed at any time, even if the test is not fully complete. The global variable `unittrace_count` contains the number of failed asserts, the array `unittrace_array` contains pointers to the location of the failed instruction in the flash memory. Both variables can be read at runtime or in the debugger with right-click -> watch.
|
||||
|
||||
However due to limitations of the build-in debugger there is no direct way to jump to the corresponding line of code. Instead you have to:
|
||||
|
||||
1. Start the debug session
|
||||
2. Right-click on the source code -> open disassembly
|
||||
3. Scroll and search the correct line
|
||||
4. Right-click on the line -> Go to source code
|
||||
|
||||
This section will be updated, if I figure out a better way.
|
||||
|
||||
<br>
|
||||
|
||||
### API
|
||||
|
||||
To keep the documentation up-to-date with the least hassle, all configuration options, functions and their arguments are explained in a comment right in front of the declaration. See `unittrace.h` for more information. This section will be updated as soon as this project hits version 1.0.0.
|
||||
|
||||
<br>
|
||||
|
||||
## Under the Hood
|
||||
I possibly should note that I've never used any "professional" unit testing library, so this may be unlike the unit testing you are used to. The code was written from scratch and inspired by [MinUnit][tool-minunit].
|
||||
|
||||
> Of course, if you have access to a full-featured testing framework like JUnit, by all means use it. But if you don't, you can still use a simple framework like MinUnit, or whip up your own in a few hours. There's no excuse for not unit testing.
|
||||
|
||||
<br>
|
||||
|
||||
### Development History
|
||||
|
||||
I didn't want to use `printf` or any UART equivalent, but the debugger instead. This is not as easy as it seems. Here are the ideas I've tried:
|
||||
|
||||
<br>
|
||||
|
||||
#### Idea 1
|
||||
Create a global `static void*` pointer and one for each assert macro. All shall be initialized with `NULL`. Whenever the assert condition is false, the local pointer gets the value from the global one and the global is updated with a reference to the local one. After multiple failed asserted this generates a linked list.
|
||||
|
||||
Problems:
|
||||
1. The Atmel Studio 7 Debugger can't jump to the location of a variable, so one can not tell which assert failed.
|
||||
2. After multiple de-referencing a pointer like this multiple times the 'watch-window' gets progressively slower.
|
||||
|
||||
<br>
|
||||
|
||||
#### Idea 2
|
||||
Create an array of structs in SRAM, each containing:
|
||||
- pointer to a String in FLASH containing the filename and path
|
||||
- uint16_t with the line number of the failed assert
|
||||
New struct shall be added whenever an assert fails. Filename and line number can be accessed with the macros `__FILE__` and `__LINE__`, respectively.
|
||||
|
||||
Problem:<br>
|
||||
To show strings in the watch window, the suffix `,s` must be added manually. If the suffix is added to a struct array like this, ALL contents are interpreted as string.
|
||||
|
||||
<br>
|
||||
|
||||
#### Idea 3
|
||||
Instead of saving filename and line number individually, put them in one string into flash. Now whenever a assert fails, store a pointer to the corresponding string in the array.
|
||||
|
||||
Problem:<br>
|
||||
The debugger can't access the data of a FLASH pointer address, if the address is stored in SRAM (or at least I couldn't figure out how). In short: you can't mix SRAM and FLASH pointer as one expression in the debugger.
|
||||
|
||||
<br>
|
||||
|
||||
#### Idea 4
|
||||
Instead of generating a list of human readable strings, store the physical location of the assert macro in a SRAM array. The location in the program memory is a 16 bit pointer, so the amount of SRAM required is pretty low. Also this solution requires almost no flash memory, except the few instructions to per assert.
|
||||
|
||||
Downside:<br>
|
||||
Although it is easy to get the value of the pointer in the array, you can not jump to the corresponding location in the C source code. See section [Interpreting the Data](#interpreting-the-data) for more details.
|
||||
|
||||
As of now idea 4 is the only one that works, so it is the implemented solution. Please [tell me](#contribute) if you know a more straightforward solution.
|
||||
|
||||
<br>
|
||||
|
||||
## Support
|
||||
|
||||
### Get Help
|
||||
|
||||
**Something doesn't work as expected?** No worries! Just open up a new issue in the [GitHub issue tracker][git-issues]. Please provide all information to reproduce your problem. If you don't have a GitHub account (and can't be bothered to create one,) you can [contact](#contact) me directly.
|
||||
|
||||
<br>
|
||||
|
||||
### Contribute
|
||||
|
||||
**Spotted an error?** [Open an issue][git-issues] or submit a pull request.
|
||||
|
||||
There is no CONTRIBUTING.md yet, sorry. Contributions will inherit the [license](#license) of this project. If you have any questions, just ask.
|
||||
|
||||
<br>
|
||||
|
||||
## About
|
||||
### Status
|
||||
**This project is currently classified as** <a href="https://github.com/nqtronix/git-template/blob/master/badges.md#project-status"><img src="https://img.shields.io/badge/status-maintained-green.svg" alt="status: maintained"></a><br>
|
||||
_The developers intend to keep the code in working condition by updating dependencies, fixing bugs and solving issues._
|
||||
|
||||
As my testing needs increase I will likely add the functionality I need.
|
||||
|
||||
<br>
|
||||
|
||||
### Changelog
|
||||
This project uses [**Semantic Versioning 2.0.0**][semver.org]. During initial development (0.x.x versions) any _major_ increase is substituted with a _minor_ increase (0.1.0->0.2.0 instead of 0.1.0->1.0.0).
|
||||
|
||||
The message of each commit contains detailed information about the changes made. The list below is a summary about all significant improvements.
|
||||
|
||||
- **0.1.0 (latest)** <br>
|
||||
- initial release
|
||||
|
||||
<br>
|
||||
|
||||
### Contact
|
||||
|
||||
If you haven't done so already, please check out [Get Help](#get-help) for the fastest possible help on your issue. Alternatively you can find my public email address on my [profile][git-profile].
|
||||
|
||||
<br>
|
||||
|
||||
## Credits and References
|
||||
|
||||
### Projects Used
|
||||
- [**MinUnit**][tool-minunit] - _a minimal unit testing framework for C_<br>
|
||||
Great inspiration, thanks!
|
||||
|
||||
- [**git-template**][git-repo-git-template] - _A simple and clean git repository template._<br>
|
||||
|
||||
<br>
|
||||
|
||||
### Related Projects
|
||||
|
||||
- none (yet)
|
||||
|
||||
Want yours to be listed here, too? Create a merge request or [**get in touch**](#get-help).
|
||||
|
||||
<br>
|
||||
|
||||
### Additional Resources
|
||||
|
||||
- [**Catch2**][git-repo-catch2] by [@catchorg][at-catchorg]<br>
|
||||
A header-only test framework. Found it by chance and it seems like a great choice for PC applications.
|
||||
|
||||
|
||||
<br>
|
||||
|
||||
## License
|
||||
This project is proudly licensed under the [MIT license][git-license].
|
||||
|
||||
The MIT license was chosen to give you the freedom to use this project in any way you want, while protecting all contributors from legal claims. Good code works, great code works for everyone. If this code has become a part of one of your projects, a link back to us would be highly appreciated. Thanks!
|
||||
|
||||
<!-- Links -->
|
||||
|
||||
[git-readme]:README.md
|
||||
[git-license]:LICENSE.md
|
||||
[git-profile]:https://github.com/nqtronix
|
||||
[git-issues]:https://github.com/nqtronix/unittrace/issues
|
||||
[git-download]:https://github.com/nqtronix/unittrace/archive/master.zip
|
||||
|
||||
[git-repo-git-template]:https://github.com/nqtronix/git-template
|
||||
|
||||
[semver.org]:semver.org
|
||||
|
||||
[tool-atmel-studio-7-0]:https://www.microchip.com/mplab/avr-support/atmel-studio-7
|
||||
[tool-avr-dragon]:https://www.microchip.com/Developmenttools/ProductDetails/ATAVRDRAGON
|
||||
[tool-minunit]:http://www.jera.com/techinfo/jtns/jtn002.html
|
||||
|
||||
[at-catchorg]:https://github.com/catchorg
|
||||
[git-repo-catch2]:https://github.com/catchorg/Catch2
|
||||
22
subrepos/unittrace/unittrace.atsln
Normal file
22
subrepos/unittrace/unittrace.atsln
Normal file
@@ -0,0 +1,22 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Atmel Studio Solution File, Format Version 11.00
|
||||
VisualStudioVersion = 14.0.23107.0
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{54F91283-7BC4-4236-8FF9-10F437C3AD48}") = "unittrace", "unittrace.cproj", "{DCE6C7E3-EE26-4D79-826B-08594B9AD897}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|AVR = Debug|AVR
|
||||
Release|AVR = Release|AVR
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{DCE6C7E3-EE26-4D79-826B-08594B9AD897}.Debug|AVR.ActiveCfg = Debug|AVR
|
||||
{DCE6C7E3-EE26-4D79-826B-08594B9AD897}.Debug|AVR.Build.0 = Debug|AVR
|
||||
{DCE6C7E3-EE26-4D79-826B-08594B9AD897}.Release|AVR.ActiveCfg = Release|AVR
|
||||
{DCE6C7E3-EE26-4D79-826B-08594B9AD897}.Release|AVR.Build.0 = Release|AVR
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
62
subrepos/unittrace/unittrace.c
Normal file
62
subrepos/unittrace/unittrace.c
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* unittrace.c
|
||||
*
|
||||
* Created: 29.10.2018 20:34:06
|
||||
* Author: Dennis aka nqtronix (github.com/nqtronix)
|
||||
*/
|
||||
|
||||
|
||||
#include "unittrace.h"
|
||||
#include <stddef.h> // required for 'NULL'
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Variables
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
volatile void* unittrace_array[UNITTRACE_LIST_SIZE] = {[0 ... UNITTRACE_LIST_SIZE-1] = NULL};
|
||||
ut_cnt_t unittrace_count = 0;
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Functions
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void ut_assert_manual(void* addr, uint8_t cond)
|
||||
{
|
||||
// only store event, if condition is 'false'
|
||||
if (cond == 0)
|
||||
{
|
||||
#ifndef UNITTRACE_USE_EXT_COUNTER
|
||||
// store event data into array, if it is not full yet
|
||||
if (unittrace_count < UNITTRACE_LIST_SIZE)
|
||||
{
|
||||
unittrace_array[unittrace_count] = addr;
|
||||
unittrace_count++;
|
||||
}
|
||||
|
||||
#else
|
||||
// store event data into array, if it is not full yet
|
||||
if (unittrace_count < UNITTRACE_LIST_SIZE)
|
||||
unittrace_array[unittrace_count] = addr;
|
||||
|
||||
// increment counter, reset if overflow detected
|
||||
// this odd code works with any positive integer type
|
||||
unittrace_count++;
|
||||
if (unittrace_count == 0)
|
||||
unittrace_count--;
|
||||
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void* ut_get_array(void)
|
||||
{
|
||||
return unittrace_array;
|
||||
}
|
||||
|
||||
ut_cnt_t ut_get_count(void)
|
||||
{
|
||||
return unittrace_count;
|
||||
}
|
||||
86
subrepos/unittrace/unittrace.componentinfo.xml
Normal file
86
subrepos/unittrace/unittrace.componentinfo.xml
Normal file
@@ -0,0 +1,86 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Store xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="AtmelPackComponentManagement">
|
||||
<ProjectComponents>
|
||||
<ProjectComponent z:Id="i1" xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/">
|
||||
<CApiVersion></CApiVersion>
|
||||
<CBundle></CBundle>
|
||||
<CClass>Device</CClass>
|
||||
<CGroup>Startup</CGroup>
|
||||
<CSub></CSub>
|
||||
<CVariant></CVariant>
|
||||
<CVendor>Atmel</CVendor>
|
||||
<CVersion>1.2.0</CVersion>
|
||||
<DefaultRepoPath>C:/Program Files (x86)\Atmel\Studio\7.0\Packs</DefaultRepoPath>
|
||||
<DependentComponents xmlns:d4p1="http://schemas.microsoft.com/2003/10/Serialization/Arrays" />
|
||||
<Description></Description>
|
||||
<Files xmlns:d4p1="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
|
||||
<d4p1:anyType i:type="FileInfo">
|
||||
<AbsolutePath>C:/Program Files (x86)\Atmel\Studio\7.0\Packs\atmel\ATmega_DFP\1.2.209\include</AbsolutePath>
|
||||
<Attribute></Attribute>
|
||||
<Category>include</Category>
|
||||
<Condition>C</Condition>
|
||||
<FileContentHash i:nil="true" />
|
||||
<FileVersion></FileVersion>
|
||||
<Name>include</Name>
|
||||
<SelectString></SelectString>
|
||||
<SourcePath></SourcePath>
|
||||
</d4p1:anyType>
|
||||
<d4p1:anyType i:type="FileInfo">
|
||||
<AbsolutePath>C:/Program Files (x86)\Atmel\Studio\7.0\Packs\atmel\ATmega_DFP\1.2.209\include\avr\iom328p.h</AbsolutePath>
|
||||
<Attribute></Attribute>
|
||||
<Category>header</Category>
|
||||
<Condition>C</Condition>
|
||||
<FileContentHash>UMk4QUzkkuShabuoYtNl/Q==</FileContentHash>
|
||||
<FileVersion></FileVersion>
|
||||
<Name>include/avr/iom328p.h</Name>
|
||||
<SelectString></SelectString>
|
||||
<SourcePath></SourcePath>
|
||||
</d4p1:anyType>
|
||||
<d4p1:anyType i:type="FileInfo">
|
||||
<AbsolutePath>C:/Program Files (x86)\Atmel\Studio\7.0\Packs\atmel\ATmega_DFP\1.2.209\templates\main.c</AbsolutePath>
|
||||
<Attribute>template</Attribute>
|
||||
<Category>source</Category>
|
||||
<Condition>C Exe</Condition>
|
||||
<FileContentHash>GD1k8YYhulqRs6FD1B2Hog==</FileContentHash>
|
||||
<FileVersion></FileVersion>
|
||||
<Name>templates/main.c</Name>
|
||||
<SelectString>Main file (.c)</SelectString>
|
||||
<SourcePath></SourcePath>
|
||||
</d4p1:anyType>
|
||||
<d4p1:anyType i:type="FileInfo">
|
||||
<AbsolutePath>C:/Program Files (x86)\Atmel\Studio\7.0\Packs\atmel\ATmega_DFP\1.2.209\templates\main.cpp</AbsolutePath>
|
||||
<Attribute>template</Attribute>
|
||||
<Category>source</Category>
|
||||
<Condition>C Exe</Condition>
|
||||
<FileContentHash>YXFphlh0CtZJU+ebktABgQ==</FileContentHash>
|
||||
<FileVersion></FileVersion>
|
||||
<Name>templates/main.cpp</Name>
|
||||
<SelectString>Main file (.cpp)</SelectString>
|
||||
<SourcePath></SourcePath>
|
||||
</d4p1:anyType>
|
||||
<d4p1:anyType i:type="FileInfo">
|
||||
<AbsolutePath>C:/Program Files (x86)\Atmel\Studio\7.0\Packs\atmel\ATmega_DFP\1.2.209\gcc\dev\atmega328p</AbsolutePath>
|
||||
<Attribute></Attribute>
|
||||
<Category>libraryPrefix</Category>
|
||||
<Condition>GCC</Condition>
|
||||
<FileContentHash i:nil="true" />
|
||||
<FileVersion></FileVersion>
|
||||
<Name>gcc/dev/atmega328p</Name>
|
||||
<SelectString></SelectString>
|
||||
<SourcePath></SourcePath>
|
||||
</d4p1:anyType>
|
||||
</Files>
|
||||
<PackName>ATmega_DFP</PackName>
|
||||
<PackPath>C:/Program Files (x86)/Atmel/Studio/7.0/Packs/atmel/ATmega_DFP/1.2.209/Atmel.ATmega_DFP.pdsc</PackPath>
|
||||
<PackVersion>1.2.209</PackVersion>
|
||||
<PresentInProject>true</PresentInProject>
|
||||
<ReferenceConditionId>ATmega328P</ReferenceConditionId>
|
||||
<RteComponents xmlns:d4p1="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
|
||||
<d4p1:string></d4p1:string>
|
||||
</RteComponents>
|
||||
<Status>Resolved</Status>
|
||||
<VersionMode>Fixed</VersionMode>
|
||||
<IsComponentInAtProject>true</IsComponentInAtProject>
|
||||
</ProjectComponent>
|
||||
</ProjectComponents>
|
||||
</Store>
|
||||
168
subrepos/unittrace/unittrace.cproj
Normal file
168
subrepos/unittrace/unittrace.cproj
Normal file
@@ -0,0 +1,168 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="14.0">
|
||||
<PropertyGroup>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<ProjectVersion>7.0</ProjectVersion>
|
||||
<ToolchainName>com.Atmel.AVRGCC8.C</ToolchainName>
|
||||
<ProjectGuid>dce6c7e3-ee26-4d79-826b-08594b9ad897</ProjectGuid>
|
||||
<avrdevice>ATmega328P</avrdevice>
|
||||
<avrdeviceseries>none</avrdeviceseries>
|
||||
<OutputType>Executable</OutputType>
|
||||
<Language>C</Language>
|
||||
<OutputFileName>$(MSBuildProjectName)</OutputFileName>
|
||||
<OutputFileExtension>.elf</OutputFileExtension>
|
||||
<OutputDirectory>$(MSBuildProjectDirectory)\$(Configuration)</OutputDirectory>
|
||||
<AssemblyName>unittrace</AssemblyName>
|
||||
<Name>unittrace</Name>
|
||||
<RootNamespace>unittrace</RootNamespace>
|
||||
<ToolchainFlavour>Native</ToolchainFlavour>
|
||||
<KeepTimersRunning>true</KeepTimersRunning>
|
||||
<OverrideVtor>false</OverrideVtor>
|
||||
<CacheFlash>true</CacheFlash>
|
||||
<ProgFlashFromRam>true</ProgFlashFromRam>
|
||||
<RamSnippetAddress>0x20000000</RamSnippetAddress>
|
||||
<UncachedRange />
|
||||
<preserveEEPROM>true</preserveEEPROM>
|
||||
<OverrideVtorValue>exception_table</OverrideVtorValue>
|
||||
<BootSegment>2</BootSegment>
|
||||
<eraseonlaunchrule>0</eraseonlaunchrule>
|
||||
<AsfFrameworkConfig>
|
||||
<framework-data xmlns="">
|
||||
<options />
|
||||
<configurations />
|
||||
<files />
|
||||
<documentation help="" />
|
||||
<offline-documentation help="" />
|
||||
<dependencies>
|
||||
<content-extension eid="atmel.asf" uuidref="Atmel.ASF" version="3.40.0" />
|
||||
</dependencies>
|
||||
</framework-data>
|
||||
</AsfFrameworkConfig>
|
||||
<avrtool>com.atmel.avrdbg.tool.simulator</avrtool>
|
||||
<avrtoolserialnumber />
|
||||
<avrdeviceexpectedsignature>0x1E950F</avrdeviceexpectedsignature>
|
||||
<com_atmel_avrdbg_tool_simulator>
|
||||
<ToolOptions>
|
||||
<InterfaceProperties>
|
||||
</InterfaceProperties>
|
||||
<InterfaceName>
|
||||
</InterfaceName>
|
||||
</ToolOptions>
|
||||
<ToolType>com.atmel.avrdbg.tool.simulator</ToolType>
|
||||
<ToolNumber>
|
||||
</ToolNumber>
|
||||
<ToolName>Simulator</ToolName>
|
||||
</com_atmel_avrdbg_tool_simulator>
|
||||
<avrtoolinterface />
|
||||
<ResetRule>0</ResetRule>
|
||||
<EraseKey />
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
|
||||
<ToolchainSettings>
|
||||
<AvrGcc>
|
||||
<avrgcc.common.Device>-mmcu=atmega328p -B "%24(PackRepoDir)\atmel\ATmega_DFP\1.2.209\gcc\dev\atmega328p"</avrgcc.common.Device>
|
||||
<avrgcc.common.optimization.RelaxBranches>True</avrgcc.common.optimization.RelaxBranches>
|
||||
<avrgcc.common.outputfiles.hex>True</avrgcc.common.outputfiles.hex>
|
||||
<avrgcc.common.outputfiles.lss>True</avrgcc.common.outputfiles.lss>
|
||||
<avrgcc.common.outputfiles.eep>True</avrgcc.common.outputfiles.eep>
|
||||
<avrgcc.common.outputfiles.srec>True</avrgcc.common.outputfiles.srec>
|
||||
<avrgcc.common.outputfiles.usersignatures>False</avrgcc.common.outputfiles.usersignatures>
|
||||
<avrgcc.compiler.general.ChangeDefaultCharTypeUnsigned>True</avrgcc.compiler.general.ChangeDefaultCharTypeUnsigned>
|
||||
<avrgcc.compiler.general.ChangeDefaultBitFieldUnsigned>True</avrgcc.compiler.general.ChangeDefaultBitFieldUnsigned>
|
||||
<avrgcc.compiler.symbols.DefSymbols>
|
||||
<ListValues>
|
||||
<Value>NDEBUG</Value>
|
||||
</ListValues>
|
||||
</avrgcc.compiler.symbols.DefSymbols>
|
||||
<avrgcc.compiler.directories.IncludePaths>
|
||||
<ListValues>
|
||||
<Value>%24(PackRepoDir)\atmel\ATmega_DFP\1.2.209\include</Value>
|
||||
</ListValues>
|
||||
</avrgcc.compiler.directories.IncludePaths>
|
||||
<avrgcc.compiler.optimization.level>Optimize for size (-Os)</avrgcc.compiler.optimization.level>
|
||||
<avrgcc.compiler.optimization.PackStructureMembers>True</avrgcc.compiler.optimization.PackStructureMembers>
|
||||
<avrgcc.compiler.optimization.AllocateBytesNeededForEnum>True</avrgcc.compiler.optimization.AllocateBytesNeededForEnum>
|
||||
<avrgcc.compiler.warnings.AllWarnings>True</avrgcc.compiler.warnings.AllWarnings>
|
||||
<avrgcc.linker.libraries.Libraries>
|
||||
<ListValues>
|
||||
<Value>libm</Value>
|
||||
</ListValues>
|
||||
</avrgcc.linker.libraries.Libraries>
|
||||
<avrgcc.assembler.general.IncludePaths>
|
||||
<ListValues>
|
||||
<Value>%24(PackRepoDir)\atmel\ATmega_DFP\1.2.209\include</Value>
|
||||
</ListValues>
|
||||
</avrgcc.assembler.general.IncludePaths>
|
||||
</AvrGcc>
|
||||
</ToolchainSettings>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
|
||||
<ToolchainSettings>
|
||||
<AvrGcc>
|
||||
<avrgcc.common.Device>-mmcu=atmega328p -B "%24(PackRepoDir)\atmel\ATmega_DFP\1.2.209\gcc\dev\atmega328p"</avrgcc.common.Device>
|
||||
<avrgcc.common.optimization.RelaxBranches>True</avrgcc.common.optimization.RelaxBranches>
|
||||
<avrgcc.common.outputfiles.hex>True</avrgcc.common.outputfiles.hex>
|
||||
<avrgcc.common.outputfiles.lss>True</avrgcc.common.outputfiles.lss>
|
||||
<avrgcc.common.outputfiles.eep>True</avrgcc.common.outputfiles.eep>
|
||||
<avrgcc.common.outputfiles.srec>True</avrgcc.common.outputfiles.srec>
|
||||
<avrgcc.common.outputfiles.usersignatures>False</avrgcc.common.outputfiles.usersignatures>
|
||||
<avrgcc.compiler.general.ChangeDefaultCharTypeUnsigned>True</avrgcc.compiler.general.ChangeDefaultCharTypeUnsigned>
|
||||
<avrgcc.compiler.general.ChangeDefaultBitFieldUnsigned>True</avrgcc.compiler.general.ChangeDefaultBitFieldUnsigned>
|
||||
<avrgcc.compiler.symbols.DefSymbols>
|
||||
<ListValues>
|
||||
<Value>DEBUG</Value>
|
||||
</ListValues>
|
||||
</avrgcc.compiler.symbols.DefSymbols>
|
||||
<avrgcc.compiler.directories.IncludePaths>
|
||||
<ListValues>
|
||||
<Value>%24(PackRepoDir)\atmel\ATmega_DFP\1.2.209\include</Value>
|
||||
</ListValues>
|
||||
</avrgcc.compiler.directories.IncludePaths>
|
||||
<avrgcc.compiler.optimization.level>Optimize (-O1)</avrgcc.compiler.optimization.level>
|
||||
<avrgcc.compiler.optimization.PackStructureMembers>True</avrgcc.compiler.optimization.PackStructureMembers>
|
||||
<avrgcc.compiler.optimization.AllocateBytesNeededForEnum>True</avrgcc.compiler.optimization.AllocateBytesNeededForEnum>
|
||||
<avrgcc.compiler.optimization.DebugLevel>Default (-g2)</avrgcc.compiler.optimization.DebugLevel>
|
||||
<avrgcc.compiler.warnings.AllWarnings>True</avrgcc.compiler.warnings.AllWarnings>
|
||||
<avrgcc.linker.libraries.Libraries>
|
||||
<ListValues>
|
||||
<Value>libm</Value>
|
||||
</ListValues>
|
||||
</avrgcc.linker.libraries.Libraries>
|
||||
<avrgcc.assembler.general.IncludePaths>
|
||||
<ListValues>
|
||||
<Value>%24(PackRepoDir)\atmel\ATmega_DFP\1.2.209\include</Value>
|
||||
</ListValues>
|
||||
</avrgcc.assembler.general.IncludePaths>
|
||||
<avrgcc.assembler.debugging.DebugLevel>Default (-Wa,-g)</avrgcc.assembler.debugging.DebugLevel>
|
||||
</AvrGcc>
|
||||
</ToolchainSettings>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="unittrace.c">
|
||||
<SubType>compile</SubType>
|
||||
</Compile>
|
||||
<Compile Include="unittrace.h">
|
||||
<SubType>compile</SubType>
|
||||
</Compile>
|
||||
<Compile Include="unittrace_demo.c">
|
||||
<SubType>compile</SubType>
|
||||
</Compile>
|
||||
<Compile Include="utility\macros\com\macro_type.h">
|
||||
<SubType>compile</SubType>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="utility" />
|
||||
<Folder Include="utility\macros" />
|
||||
<Folder Include="utility\macros\com" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="README.md">
|
||||
<SubType>compile</SubType>
|
||||
</None>
|
||||
<None Include="utility\macros\com\com readme.txt">
|
||||
<SubType>compile</SubType>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<Import Project="$(AVRSTUDIO_EXE_PATH)\\Vs\\Compiler.targets" />
|
||||
</Project>
|
||||
138
subrepos/unittrace/unittrace.h
Normal file
138
subrepos/unittrace/unittrace.h
Normal file
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
* unittrace.h
|
||||
*
|
||||
* Created: 29.10.2018 20:36:59
|
||||
* Author: Dennis aka nqtronix (github.com/nqtronix)
|
||||
*
|
||||
* Description:
|
||||
* Testing is an important part of writing code, especially if the code is meant to be re-used for
|
||||
* other projects. On small MCUs testing can be quite tricky as the memory is limited and errors
|
||||
* can't be easily reported with `printf()` or similiar.
|
||||
*
|
||||
* unittrace provides basic testing functionality and is designed with the limits of MCUs in mind.
|
||||
* It runs directly on the hardware and thus can catch errors other test software can't. Fetch the
|
||||
* results through a debugger or with a function.
|
||||
*
|
||||
* See included 'README.md' for additional information.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef UNITTRACE_H_
|
||||
#define UNITTRACE_H_
|
||||
|
||||
|
||||
#include <stdint.h> // required for data types (uint8_t, uint16_t, ...)
|
||||
#include "utility/macros/com/macro_type.h"
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Check requirements
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef __GNUC__
|
||||
#error unittrace.h requires "always inline functions", "local labels" and "typeof" offered by a GNU C/ GCC compiler!
|
||||
#endif
|
||||
// Workarounds are possible. See comments in the source code.
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// General Info
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// version numbering is based on "Semantic Versioning 2.0.0" (semver.org)
|
||||
#define UNITTRACE_VERSION_MAJOR 0
|
||||
#define UNITTRACE_VERSION_MINOR 1
|
||||
#define UNITTRACE_VERSION_PATCH 0
|
||||
#define UNITTRACE_VERSION_SUFFIX
|
||||
#define UNITTRACE_VERSION_META
|
||||
|
||||
// For all development versions (0.x.x) the patch version is increased whenever a function was renamed
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Settings (This section can be modified by the user)
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Define the amount of failed events to log in detail. The same event can be logged multiple times.
|
||||
// Each event required 4 byte of RAM. There is no upper limit except the device's SRAM. The compiler
|
||||
// will automatically choose the smallest possible data type for most efficient operation.
|
||||
#define UNITTRACE_LIST_SIZE 8
|
||||
|
||||
// Especially on small embedded systems it is best to choose the smallest data type for every
|
||||
// variable. This macro selects the smallest possible type based on 'UNITTRACE_LIST_SIZE'. Change
|
||||
// to 'uint8_t', 'uint16_t' or 'uint32_t' to manually overwrite this feature.
|
||||
//
|
||||
// extra '#define UNITTRACE_COUNTER_TYPE' prevents VAssistX from marking 'ut_cnt_t' red
|
||||
#define UNITTRACE_COUNTER_TYPE _type_min(UNITTRACE_LIST_SIZE)
|
||||
typedef UNITTRACE_COUNTER_TYPE ut_cnt_t;
|
||||
|
||||
// If 'UNITTRACE_USE_EXT_COUNTER' is defined, failed asserts will be counted till the maximum value,
|
||||
// even if no space in the array is available. This might be helpful for some test cases, but does
|
||||
// increase the assert execution time slightly.
|
||||
#define UNITTRACE_USE_EXT_COUNTER
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Global Variables
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// I couldn't figure out how to pass a void array half-way decently, so both variables are
|
||||
// now global instead. This is not "how it's don", I know, but unittrace is for testing only anyway.
|
||||
|
||||
// WATCH THESE VARIABLES IN THE DEBUGGER
|
||||
|
||||
// contains all traced events
|
||||
volatile void* unittrace_array[UNITTRACE_LIST_SIZE];
|
||||
|
||||
// amount of traced events
|
||||
ut_cnt_t unittrace_count;
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Function Declarations
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// 'ut_assert' is used to validate any given condition. If the condition is false (cond == 0), the
|
||||
// assembler instruction address is stored to an array (unless it is full). This array can be read
|
||||
// during debugging.
|
||||
// If your compiler does not support inline functions, use the macro 'UT_ASSERT(cond)'.
|
||||
static inline void ut_assert(uint8_t cond) __attribute__((always_inline));
|
||||
|
||||
// If you manually want to write a value to the array, you can use this macro. Usually the first few
|
||||
// instructions are generated by the compiler and their addresses will never naturally appear in
|
||||
// said array. Thus you may abuse low values for your own, custom purpose (<50 should be safe on
|
||||
// AVR8 MCUs)
|
||||
void ut_assert_manual(void* addr, uint8_t cond);
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Macros
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// alternative implementation of the macro 'ut_assert(cond)'
|
||||
#define UT_ASSERT(cond) do{__label__ lcl; lcl: ut_assert_manual(&&lcl, cond);}while(0)
|
||||
|
||||
// places a single 'nop' instruction. This will not be optimized an is ideal to place a breakpoint.
|
||||
// Unlike an inline function a macro is taken "as is". In this case it make debugging a little
|
||||
// easier, so support for the equivalent inline function has been removed.
|
||||
#define UT_BREAK() asm("nop")
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Inline functions
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Inline functions MUST be defined in the .h, not in the .c file to work correctly!
|
||||
|
||||
// This function MUST be always inline to create an individual label for each call. In GCC inline
|
||||
// functions declared with '__attribute__((always_inline))' are as fast as the respective macro.
|
||||
// '__label__' creates a local label to prevent a littered namespace. Alternatively you could use
|
||||
// the build-in macro '__COUNTER__' and concat '##' to generate unique labels.
|
||||
static inline void ut_assert(uint8_t cond)
|
||||
{
|
||||
__label__ local_label;
|
||||
local_label:
|
||||
ut_assert_manual(&&local_label, cond);
|
||||
}
|
||||
|
||||
#endif /* UNITTRACE_H_ */
|
||||
36
subrepos/unittrace/unittrace_demo.c
Normal file
36
subrepos/unittrace/unittrace_demo.c
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* unittrace.c
|
||||
*
|
||||
* Created: 29.10.2018 20:32:06
|
||||
* Author : Dennis aka nqtronix (github.com/nqtronix)
|
||||
*/
|
||||
|
||||
|
||||
#include "unittrace.h"
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// using inline functions
|
||||
ut_assert(5 == 5); // passes
|
||||
UT_BREAK();
|
||||
ut_assert(5 == 7); // fails and code address gets stored in array
|
||||
UT_BREAK();
|
||||
|
||||
// using macros (equivalently behavior to functions)
|
||||
UT_ASSERT(5 == 5); // passes
|
||||
UT_BREAK();
|
||||
UT_ASSERT(5 == 7); // fails and code address gets stored in array
|
||||
UT_BREAK();
|
||||
|
||||
// Access generated data
|
||||
// You can access the data either with a debugger by watching the two global variables or use
|
||||
// them in your code. See pseudocode below:
|
||||
for (uint8_t cnt=0; cnt < unittrace_count; cnt++)
|
||||
{
|
||||
/*usedata(unittrace_array[cnt]);*/
|
||||
}
|
||||
|
||||
// End test
|
||||
UT_BREAK();
|
||||
while (1);
|
||||
}
|
||||
3
subrepos/unittrace/utility/macros/com/com readme.txt
Normal file
3
subrepos/unittrace/utility/macros/com/com readme.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
This folder "com" contains macros for common functionalities and can result in significant cleaner
|
||||
code. In addition the majority of macros can be highly optimized by the compiler, if the imput
|
||||
arguments are literals.
|
||||
39
subrepos/unittrace/utility/macros/com/macro_type.h
Normal file
39
subrepos/unittrace/utility/macros/com/macro_type.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* macro_type.h
|
||||
*
|
||||
* Created: 14.10.2018 14:34:03
|
||||
* Author: Dennis
|
||||
*
|
||||
* Description:
|
||||
* Provides typ-related macros
|
||||
*/
|
||||
|
||||
|
||||
#ifndef MACRO_TYPE_H_
|
||||
#define MACRO_TYPE_H_
|
||||
|
||||
|
||||
// returns a value not smaller or larger than the limit
|
||||
#define _limit(arg, lo, hi) ((arg)<lo? lo : (arg)>hi? hi : (arg))
|
||||
#define _limit_lo(arg, lo) ((arg)<lo? lo : (arg))
|
||||
#define _limit_hi(arg, hi) ((arg)>hi? hi : (arg))
|
||||
|
||||
|
||||
// returns smallest type for given integer
|
||||
#define _type_min(_integer) typeof(_type_cast_min(_integer))
|
||||
|
||||
// By default all literals are interpreted as a int, whose size varies between systems
|
||||
// This macro forces minimum memory usage by casting a literal to the smallest data type suitable.
|
||||
// Unsigned types are proffered.
|
||||
#define _type_cast_min(_integer) \
|
||||
(__builtin_choose_expr((_integer)>0, \
|
||||
__builtin_choose_expr((_integer)<=UINT8_MAX, (uint8_t) (_integer), \
|
||||
__builtin_choose_expr((_integer)<=UINT16_MAX, (uint16_t) (_integer), \
|
||||
__builtin_choose_expr((_integer)<=UINT32_MAX, (uint32_t) (_integer), (uint64_t) (_integer)))), \
|
||||
__builtin_choose_expr((_integer)>=INT8_MIN, (int8_t) (_integer), \
|
||||
__builtin_choose_expr((_integer)>=INT16_MIN, (int16_t) (_integer), \
|
||||
__builtin_choose_expr((_integer)>=INT32_MIN, (int32_t) (_integer), (int64_t) (_integer))))))
|
||||
|
||||
|
||||
|
||||
#endif /* MACRO_TYPE_H_ */
|
||||
Reference in New Issue
Block a user