diff --git a/README.md b/README.md index 84b26c0..c35b9de 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ A python 3.8 or higher version is required. The parameter generator tool can then by called on cmdline using $ pargen -h - usage: pargen [-h] [--ihex] [--csrc] [--gld] [--a2l] [--pyhexdump] [--destdir directory] [--filename basename] [--static] [--modify name=value] [--version] file + usage: pargen [-h] [--ihex] [--csrc] [--gld] [--a2l] [--pyhexdump] [--destdir directory] [--filename basename] [--static] [--modify name=value] [--version] [-v] file pargen 0.4.0: A tool for generating flashable parameter container. @@ -56,6 +56,7 @@ The parameter generator tool can then by called on cmdline using --modify name=value, -m name=value modify parameter value using name=value notation --version show program's version number and exit + -v, --verbose increase logging level Copyright (c) 2022-2023 Haju Schulz . Visit https://github.com/nhjschulz/flashcontainer for full documentation and examples. @@ -80,7 +81,7 @@ understand Pargen's XML capabilities in depth, read on. ### XML Configuration File Anatomy The XML follows an XSD-schema defined in -[pargen_1.0.xsd](https://github.com/nhjschulz/flashcontainer/blob/master/src/flashcontainer/pargen_1.0.xsd). +[pargen_1.1.xsd](https://github.com/nhjschulz/flashcontainer/blob/master/src/flashcontainer/pargen_1.1.xsd). It is highly recommended to use an XML editor with schema validation support to avoid or detect validations already while editing. Visual Studio Code is a perfect choice, given the @@ -90,16 +91,23 @@ This extensions brings validation and "IntelliSense" to editing XML files. The file defines the following data element hierarchy. The "..." lines mean that the preceding element may appear multiple times: - - - - or - ... - + + + or or or + ... + + + ... + + + + or + ... + + ... + ... - - ... - + ### XML Root Element @@ -108,9 +116,9 @@ following (static) XML element to be used as the root XML element at the beginning of the file: ?xml version="1.0" encoding="utf-8"?> - + xsi:schemaLocation="http://nhjschulz.github.io/1.1/pargen http://nhjschulz.github.io/xsd/pargen_1.1.xsd" > ### Container Element @@ -221,8 +229,9 @@ have one to many parameter elements. |-----------|-------------------------|--------|-------| | offset | Memory start offset inside block. Value may be "." to use the next free offset inside the block.|No|| | name | The parameter name. | No | | -| type |Parameter type, one of [u]int{bits} with bits one of 8,16,32,64 or float32,float64 or utf8|No| +| type |Parameter type, one of [u]int{bits} with bits one of 8,16,32,64 or float32,float64 or utf8 or complex|No| | align | Parameter offset alignment to the next 1,2,4,8 bytes boundary|Yes|1| +| struct | Struct type of the parameter, if type is complex | Yes | "" | #### Parameter Child Elements @@ -251,6 +260,15 @@ JSON definitions are supported: | Strings in double quotes | "Hello world!" | | One-dimensional arrays | [1, 2, 3, 4, 5, 6] | +For complex parameters (that have the type of a defined struct), JSON input is parsed as key: value pairs to populate the structs fields. +Input is required for every Field or Array Field in the struct, Padding and CRCs need no input in the value element. +This means the set of keys in the input JSON has to match the set of Field names and Array Field names of the struct, or pargen will detect the input as invalid. + +|Value type | Examples | +|----------------------------------|--------------| +| JSON key value pairs | {"f1": 1, "f2": 9999999, "arrayf": [1, 4, 16, 64]} | + + ### Crc Element The crc element defines an integer parameter. The difference to a @@ -314,6 +332,52 @@ but derived from the type attribute of the crc element. +### The Struct Element + +A **struct** is a way to group multiple simple types into a combined data structure. By referencing a structs name in a block parameter, +the parameters type will be interpreted as the struct. A struct features multiple attributes that define how the struct and the data of the encompassed fields. + +|Attribute |Description |optional| default | +|------------------|------------------------------|--------|---------| +| name | The structs name. | No | | +| fill | Byte value used for padding | Yes | parent | + + +The fill value will be used as padding, with the additional options of "parent". +Choosing **parent** will use the fill value of a parameters encompassing block. + +### The Field Element + +A field is the basic building block of a struct and serves as a placeholder for a value of a basic type in instances of the struct. +Unlike parameter elements in a block, a field does not hold offset or alignment information, instead alignment is handled by padding tags. +The basic type of the field defines its size and content interpretation. + +|Attribute |Description |optional| default | +|------------------|------------------------------|--------|---------| +| name | The fields name. | No | | +| type | Basic type of the field | No | | + +### The CRC Field Element + +The CRC Field Element functions similarly to a CRC Element, except it does not feature offset and alignment attributes. + + +### The Array Field Element + +Array Fields are similar to fields, but feature a size attribute that determines the resulting arrays size + +|Attribute |Description |optional| default | +|------------------|------------------------------|--------|---------| +| name | The fields name. | No | | +| type | Basic type of the field | No | | +| size | Size of the array | No | | + +### The Padding Element + +The padding element is used to introduce gaps / offsets between a structs fields. It features a size attribute that determines the padding size. +|Attribute |Description |optional| default | +|------------------|------------------------------|--------|---------| +| size | Size of the array (in bytes) | No | | ## Generating TC3xx Boot Mode Header Structures diff --git a/examples/arduino/platformio.ini b/examples/arduino/platformio.ini index ba1674b..dc7ae9c 100644 --- a/examples/arduino/platformio.ini +++ b/examples/arduino/platformio.ini @@ -15,6 +15,8 @@ framework = arduino build_flags = -Wl,-Map,output.map ; -Wl,--verbose board_build.ldscript = avr5.xn +platform_packages = platformio/tool-simavr + debug_tool = simavr debug_server = ${platformio.packages_dir}/tool-simavr/bin/simavr diff --git a/examples/arduino_struct_test/avr5.xn b/examples/arduino_struct_test/avr5.xn new file mode 100644 index 0000000..fc0257c --- /dev/null +++ b/examples/arduino_struct_test/avr5.xn @@ -0,0 +1,264 @@ +/* Script for -n: mix text and data on same page */ +/* Copyright (C) 2014-2015 Free Software Foundation, Inc. + Copying and distribution of this script, with or without modification, + are permitted in any medium without royalty provided the copyright + notice and this notice are preserved. */ +OUTPUT_FORMAT("elf32-avr","elf32-avr","elf32-avr") +OUTPUT_ARCH(avr:5) +__TEXT_REGION_LENGTH__ = DEFINED(__TEXT_REGION_LENGTH__) ? __TEXT_REGION_LENGTH__ : 128K; +__DATA_REGION_LENGTH__ = DEFINED(__DATA_REGION_LENGTH__) ? __DATA_REGION_LENGTH__ : 0xffa0; +__EEPROM_REGION_LENGTH__ = DEFINED(__EEPROM_REGION_LENGTH__) ? __EEPROM_REGION_LENGTH__ : 64K; +__FUSE_REGION_LENGTH__ = DEFINED(__FUSE_REGION_LENGTH__) ? __FUSE_REGION_LENGTH__ : 1K; +__LOCK_REGION_LENGTH__ = DEFINED(__LOCK_REGION_LENGTH__) ? __LOCK_REGION_LENGTH__ : 1K; +__SIGNATURE_REGION_LENGTH__ = DEFINED(__SIGNATURE_REGION_LENGTH__) ? __SIGNATURE_REGION_LENGTH__ : 1K; +__USER_SIGNATURE_REGION_LENGTH__ = DEFINED(__USER_SIGNATURE_REGION_LENGTH__) ? __USER_SIGNATURE_REGION_LENGTH__ : 1K; +MEMORY +{ + text (rx) : ORIGIN = 0, LENGTH = __TEXT_REGION_LENGTH__ + data (rw!x) : ORIGIN = 0x800060, LENGTH = __DATA_REGION_LENGTH__ + eeprom (rw!x) : ORIGIN = 0x810000, LENGTH = __EEPROM_REGION_LENGTH__ + fuse (rw!x) : ORIGIN = 0x820000, LENGTH = __FUSE_REGION_LENGTH__ + lock (rw!x) : ORIGIN = 0x830000, LENGTH = __LOCK_REGION_LENGTH__ + signature (rw!x) : ORIGIN = 0x840000, LENGTH = __SIGNATURE_REGION_LENGTH__ + user_signatures (rw!x) : ORIGIN = 0x850000, LENGTH = __USER_SIGNATURE_REGION_LENGTH__ +} +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rel.init : { *(.rel.init) } + .rela.init : { *(.rela.init) } + .rel.text : + { + *(.rel.text) + *(.rel.text.*) + *(.rel.gnu.linkonce.t*) + } + .rela.text : + { + *(.rela.text) + *(.rela.text.*) + *(.rela.gnu.linkonce.t*) + } + .rel.fini : { *(.rel.fini) } + .rela.fini : { *(.rela.fini) } + .rel.rodata : + { + *(.rel.rodata) + *(.rel.rodata.*) + *(.rel.gnu.linkonce.r*) + } + .rela.rodata : + { + *(.rela.rodata) + *(.rela.rodata.*) + *(.rela.gnu.linkonce.r*) + } + .rel.data : + { + *(.rel.data) + *(.rel.data.*) + *(.rel.gnu.linkonce.d*) + } + .rela.data : + { + *(.rela.data) + *(.rela.data.*) + *(.rela.gnu.linkonce.d*) + } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rel.bss : { *(.rel.bss) } + .rela.bss : { *(.rela.bss) } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + /* Internal text space or external memory. */ + .text : + { + *(.vectors) + KEEP(*(.vectors)) + /* For data that needs to reside in the lower 64k of progmem. */ + *(.progmem.gcc*) + /* PR 13812: Placing the trampolines here gives a better chance + that they will be in range of the code that uses them. */ + . = ALIGN(2); + __trampolines_start = . ; + /* The jump trampolines for the 16-bit limited relocs will reside here. */ + *(.trampolines) + *(.trampolines*) + __trampolines_end = . ; + /* avr-libc expects these data to reside in lower 64K. */ + *libprintf_flt.a:*(.progmem.data) + *libc.a:*(.progmem.data) + *(.progmem*) + . = ALIGN(2); + /* For future tablejump instruction arrays for 3 byte pc devices. + We don't relax jump/call instructions within these sections. */ + *(.jumptables) + *(.jumptables*) + /* For code that needs to reside in the lower 128k progmem. */ + *(.lowtext) + *(.lowtext*) + __ctors_start = . ; + *(.ctors) + __ctors_end = . ; + __dtors_start = . ; + *(.dtors) + __dtors_end = . ; + KEEP(SORT(*)(.ctors)) + KEEP(SORT(*)(.dtors)) + /* From this point on, we don't bother about wether the insns are + below or above the 16 bits boundary. */ + *(.init0) /* Start here after reset. */ + KEEP (*(.init0)) + *(.init1) + KEEP (*(.init1)) + *(.init2) /* Clear __zero_reg__, set up stack pointer. */ + KEEP (*(.init2)) + *(.init3) + KEEP (*(.init3)) + *(.init4) /* Initialize data and BSS. */ + KEEP (*(.init4)) + *(.init5) + KEEP (*(.init5)) + *(.init6) /* C++ constructors. */ + KEEP (*(.init6)) + *(.init7) + KEEP (*(.init7)) + *(.init8) + KEEP (*(.init8)) + *(.init9) /* Call main(). */ + KEEP (*(.init9)) + *(.text) + . = ALIGN(2); + *(.text.*) + . = ALIGN(2); + *(.fini9) /* _exit() starts here. */ + KEEP (*(.fini9)) + *(.fini8) + KEEP (*(.fini8)) + *(.fini7) + KEEP (*(.fini7)) + *(.fini6) /* C++ destructors. */ + KEEP (*(.fini6)) + *(.fini5) + KEEP (*(.fini5)) + *(.fini4) + KEEP (*(.fini4)) + *(.fini3) + KEEP (*(.fini3)) + *(.fini2) + KEEP (*(.fini2)) + *(.fini1) + KEEP (*(.fini1)) + *(.fini0) /* Infinite loop after program termination. */ + KEEP (*(.fini0)) + _etext = . ; + } > text + .data : + { + PROVIDE (__data_start = .) ; + *(.data) + *(.data*) + *(.gnu.linkonce.d*) + *(.rodata) /* We need to include .rodata here if gcc is used */ + *(.rodata*) /* with -fdata-sections. */ + *(.gnu.linkonce.r*) + . = ALIGN(2); + _edata = . ; + PROVIDE (__data_end = .) ; + } > data AT> text + .bss ADDR(.data) + SIZEOF (.data) : AT (ADDR (.bss)) + { + PROVIDE (__bss_start = .) ; + *(.bss) + *(.bss*) + *(COMMON) + PROVIDE (__bss_end = .) ; + } > data + __data_load_start = LOADADDR(.data); + __data_load_end = __data_load_start + SIZEOF(.data); + /* Global data not cleared after reset. */ + .noinit ADDR(.bss) + SIZEOF (.bss) : AT (ADDR (.noinit)) + { + PROVIDE (__noinit_start = .) ; + *(.noinit*) + PROVIDE (__noinit_end = .) ; + _end = . ; + PROVIDE (__heap_start = .) ; + } > data + .eeprom : + { + INCLUDE param/param.ld /* Add pargen generated symbols */ + /* See .data above... */ + KEEP(*(.eeprom*)) + __eeprom_end = . ; + } > eeprom + .fuse : + { + KEEP(*(.fuse)) + KEEP(*(.lfuse)) + KEEP(*(.hfuse)) + KEEP(*(.efuse)) + } > fuse + .lock : + { + KEEP(*(.lock*)) + } > lock + .signature : + { + KEEP(*(.signature*)) + } > signature + .user_signatures : + { + KEEP(*(.user_signatures*)) + } > user_signatures + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + .note.gnu.build-id : { *(.note.gnu.build-id) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end ) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /* DWARF 3 */ + .debug_pubtypes 0 : { *(.debug_pubtypes) } + .debug_ranges 0 : { *(.debug_ranges) } + /* DWARF Extension. */ + .debug_macro 0 : { *(.debug_macro) } +} diff --git a/examples/arduino_struct_test/example.md b/examples/arduino_struct_test/example.md new file mode 100644 index 0000000..146e71f --- /dev/null +++ b/examples/arduino_struct_test/example.md @@ -0,0 +1,113 @@ +# Arduino Example with PlatformIO + +This example generates a hex file with a parameter block that +gets used as EEPROM content on an ATmega328P processor. It is +executable without hardware using the simavr simulator. +This simulator is part of the +[PlatformIO](https://platformio.org/) toolchain for this processor. +PlatformIO must therefore be installed to run or rebuild the example. + +## Running the example with SimAVR + +The script [run_simavr.sh](./run_simavr.sh) shows how to run the +example. It provides the following option to SimAVR: + + $HOME/.platformio/packages/tool-simavr/bin/simavr + -m atmega328p + -f 16000000L + -ee param/param.hex + .pio/build/ATmega328P/firmware.hex + +The example will generate the following output: + + ./run_simavr.sh + AVR: 'param\param.hex' invalid ihex format (; AU) + Loaded 1 section of ihex + Load HEX eeprom 81000000, 1024 + Loaded 1 section of ihex + Load HEX flash 00000000, 3704 + Found pargen block header in EEPROM: ID:EE Version:1.0 Length: 1024 bytes. + This message is defined as a Pargen parameter!.. + This message is defined as a Pargen parameter!.. + This message is defined as a Pargen parameter!.. + This message is defined as a Pargen parameter!.. + This message is defined as a Pargen parameter!.. + +The repeated output message and update delay is configured by +parameters from the pargen configuration. +The warning about an invalid ihex format can be ignored. SimAVR reads passed the end +record of the file and complains about the "; ..." comment at the end of the file. + +## Noteworthy Configuration + +The example deviates from a 'normal' arduino project in the following ways + + 1) It contains a pargen configuration for header, hex and link file + generation. + 2) It uses a modified linker script to generate parameter symbols + 3) It includes the pargen generated header file + 4) It customizes the call to simavr to include the EEPROM data + +### Pargen Configuration + +The param folder holds the [pargen configuration XML](./param/param.hex). +It creates a parameter block with header ID 0xEE at the logical +address 0x8100000. This address is required by the avr gcc toolchain +as the start of the EEPROM space. The following pargen options are +needed to regenerate the required project files: + + pargen --ihex --gld --csrc -o param param/param.xml + +The display message and repeat delay can be changed inside the XML +before rerunning pargen. The example will use the changed values +in the next simavr run without the need for recompiling. + +### Modified Linker Script + +The example needs a local copy of the avr linker script avr5.xn. +This is required to add the include directive for the pargen linker +script into it. Add the following configuration option to the +platformio.ini file to use the local copy: + + [env:ATmega328P] + ... + board_build.ldscript = avr5.xn + +Note: To find out the path to the original linker script, add the +following option to the "env:ATmega328P" section as well: + + build_flags = -Wl,--verbose + +The modification is the following single line addition into the eeprom +section definition: + + INCLUDE param/param.ld /* Add pargen generated symbols */ + +The eeprom section will then look like this: + + .eeprom : + { + INCLUDE param/param.ld /* Add pargen generated symbols */ + /* See .data above... */ + KEEP(*(.eeprom*)) + __eeprom_end = . ; + } > eeprom + +The include file will generate public symbols for all pargen +parameters at their EEPROM addresses. + +### Using the Include File to Access Parameters + +The file [src/main.cpp](./src/main.cpp) includes the +param/param.h header file to access the parameters from the +application code. The generated C-Source file is not used by the +application. It is intended for test development purposes only. + +### Providing the EEPROM data to SimAVR + +The EEPROM data from pargen is passed to SimAVR as an additional +hexfile together with the application. The file param/param.hex +is passed together with the "-ee" option to tell the simulator +that this is EEPROM data. + + simavr ... -ee param/param.hex ... diff --git a/examples/arduino_struct_test/gen_param.bat b/examples/arduino_struct_test/gen_param.bat new file mode 100644 index 0000000..9cfcc8c --- /dev/null +++ b/examples/arduino_struct_test/gen_param.bat @@ -0,0 +1 @@ +pargen --ihex --csrc --gld --pyhexdump --destdir param --filename param param\structexample.xml diff --git a/examples/arduino_struct_test/gen_param.sh b/examples/arduino_struct_test/gen_param.sh new file mode 100644 index 0000000..5d6e382 --- /dev/null +++ b/examples/arduino_struct_test/gen_param.sh @@ -0,0 +1 @@ +pargen --ihex --csrc --gld --pyhexdump --destdir param --filename param param/structexample.xml diff --git a/examples/arduino_struct_test/include/README b/examples/arduino_struct_test/include/README new file mode 100644 index 0000000..194dcd4 --- /dev/null +++ b/examples/arduino_struct_test/include/README @@ -0,0 +1,39 @@ + +This directory is intended for project header files. + +A header file is a file containing C declarations and macro definitions +to be shared between several project source files. You request the use of a +header file in your project source file (C, C++, etc) located in `src` folder +by including it, with the C preprocessing directive `#include'. + +```src/main.c + +#include "header.h" + +int main (void) +{ + ... +} +``` + +Including a header file produces the same results as copying the header file +into each source file that needs it. Such copying would be time-consuming +and error-prone. With a header file, the related declarations appear +in only one place. If they need to be changed, they can be changed in one +place, and programs that include the header file will automatically use the +new version when next recompiled. The header file eliminates the labor of +finding and changing all the copies as well as the risk that a failure to +find one copy will result in inconsistencies within a program. + +In C, the usual convention is to give header files names that end with `.h'. +It is most portable to use only letters, digits, dashes, and underscores in +header file names, and at most one dot. + +Read more about using header files in official GCC documentation: + +* Include Syntax +* Include Operation +* Once-Only Headers +* Computed Includes + +https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html diff --git a/examples/arduino_struct_test/output.map b/examples/arduino_struct_test/output.map new file mode 100644 index 0000000..e244e13 --- /dev/null +++ b/examples/arduino_struct_test/output.map @@ -0,0 +1,692 @@ +Archive member included to satisfy reference by file (symbol) + +.pio\build\ATmega328P\libFrameworkArduino.a(HardwareSerial.cpp.o) + .pio\build\ATmega328P\src\main.cpp.o (symbol from plugin) (_ZN14HardwareSerial5beginEmh) +.pio\build\ATmega328P\libFrameworkArduino.a(HardwareSerial0.cpp.o) + .pio\build\ATmega328P\src\main.cpp.o (symbol from plugin) (Serial) +.pio\build\ATmega328P\libFrameworkArduino.a(Print.cpp.o) + HardwareSerial.cpp.o (symbol from plugin) (_ZN5Print5writeEPKhj) +.pio\build\ATmega328P\libFrameworkArduino.a(abi.cpp.o) + Print.cpp.o (symbol from plugin) (__cxa_pure_virtual) +.pio\build\ATmega328P\libFrameworkArduino.a(main.cpp.o) + c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5/crtatmega328p.o (main) +.pio\build\ATmega328P\libFrameworkArduino.a(wiring.c.o) + .pio\build\ATmega328P\src\main.cpp.o (symbol from plugin) (delay) +.pio\build\ATmega328P\libFrameworkArduino.a(hooks.c.o) + wiring.c.o (symbol from plugin) (yield) +c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_exit.o) + c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5/crtatmega328p.o (exit) +c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5\libc.a(vfprintf_p.o) + Print.cpp.o (symbol from plugin) (vfprintf_P) +c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5\libc.a(vfprintf_std.o) + c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5\libc.a(vfprintf_p.o) (vfprintf) +c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5\libc.a(strnlen_P.o) + c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5\libc.a(vfprintf_std.o) (strnlen_P) +c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5\libc.a(strnlen.o) + c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5\libc.a(vfprintf_std.o) (strnlen) +c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5\libc.a(fputc.o) + c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5\libc.a(vfprintf_std.o) (fputc) +c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5\libc.a(ultoa_invert.o) + c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5\libc.a(vfprintf_std.o) (__ultoa_invert) +c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5\libatmega328p.a(eerd_block.o) + .pio\build\ATmega328P\src\main.cpp.o (symbol from plugin) (eeprom_read_block) +c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5\libatmega328p.a(eerd_byte.o) + .pio\build\ATmega328P\src\main.cpp.o (symbol from plugin) (eeprom_read_byte) +c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5\libatmega328p.a(eerd_word.o) + .pio\build\ATmega328P\src\main.cpp.o (symbol from plugin) (eeprom_read_word) +c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_prologue.o) + c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5\libc.a(vfprintf_std.o) (__prologue_saves__) +c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_epilogue.o) + c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5\libc.a(vfprintf_std.o) (__epilogue_restores__) +c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_copy_data.o) + C:\Users\ldubies\AppData\Local\Temp\ccI9JQwb.ltrans0.ltrans.o (__do_copy_data) +c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_clear_bss.o) + C:\Users\ldubies\AppData\Local\Temp\ccI9JQwb.ltrans0.ltrans.o (__do_clear_bss) +c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_ctors.o) + C:\Users\ldubies\AppData\Local\Temp\ccI9JQwb.ltrans0.ltrans.o (__do_global_ctors) +c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_tablejump2.o) + c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_ctors.o) (__tablejump2__) + +Discarded input sections + + .data 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5/crtatmega328p.o + .bss 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5/crtatmega328p.o + .text 0x00000000 0x0 .pio\build\ATmega328P\src\main.cpp.o (symbol from plugin) + .gnu.linkonce.t._ZN14HardwareSerial5beginEm + 0x00000000 0x0 .pio\build\ATmega328P\src\main.cpp.o (symbol from plugin) + .data 0x00000000 0x0 C:\Users\ldubies\AppData\Local\Temp\ccI9JQwb.ltrans0.ltrans.o + .text 0x00000000 0x0 HardwareSerial.cpp.o (symbol from plugin) + .gnu.linkonce.t._ZTV14HardwareSerial + 0x00000000 0x0 HardwareSerial.cpp.o (symbol from plugin) + .text 0x00000000 0x0 HardwareSerial0.cpp.o (symbol from plugin) + .gnu.linkonce.t._ZN14HardwareSerial16_rx_complete_irqEv + 0x00000000 0x0 HardwareSerial0.cpp.o (symbol from plugin) + .text 0x00000000 0x0 Print.cpp.o (symbol from plugin) + .gnu.linkonce.t._ZN5Print17availableForWriteEv + 0x00000000 0x0 Print.cpp.o (symbol from plugin) + .gnu.linkonce.t._ZN5Print5flushEv + 0x00000000 0x0 Print.cpp.o (symbol from plugin) + .gnu.linkonce.t._ZN5Print5writeEPKc + 0x00000000 0x0 Print.cpp.o (symbol from plugin) + .gnu.linkonce.t._ZN5Print5writeEPKcj + 0x00000000 0x0 Print.cpp.o (symbol from plugin) + .gnu.linkonce.t._ZTV5Print + 0x00000000 0x0 Print.cpp.o (symbol from plugin) + .text 0x00000000 0x0 abi.cpp.o (symbol from plugin) + .text 0x00000000 0x0 main.cpp.o (symbol from plugin) + .text 0x00000000 0x0 wiring.c.o (symbol from plugin) + .text 0x00000000 0x0 hooks.c.o (symbol from plugin) + .text 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_exit.o) + .data 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_exit.o) + .bss 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_exit.o) + .text.libgcc.mul + 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_exit.o) + .text.libgcc.div + 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_exit.o) + .text.libgcc 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_exit.o) + .text.libgcc.prologue + 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_exit.o) + .text.libgcc.builtins + 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_exit.o) + .text.libgcc.fmul + 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_exit.o) + .text.libgcc.fixed + 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_exit.o) + .text 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5\libc.a(vfprintf_p.o) + .data 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5\libc.a(vfprintf_p.o) + .bss 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5\libc.a(vfprintf_p.o) + .text.avr-libc + 0x00000000 0x1e c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5\libc.a(vfprintf_p.o) + .comment 0x00000000 0x12 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5\libc.a(vfprintf_p.o) + .text 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5\libc.a(vfprintf_std.o) + .data 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5\libc.a(vfprintf_std.o) + .bss 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5\libc.a(vfprintf_std.o) + .text 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5\libc.a(strnlen_P.o) + .data 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5\libc.a(strnlen_P.o) + .bss 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5\libc.a(strnlen_P.o) + .text 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5\libc.a(strnlen.o) + .data 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5\libc.a(strnlen.o) + .bss 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5\libc.a(strnlen.o) + .text 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5\libc.a(fputc.o) + .data 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5\libc.a(fputc.o) + .bss 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5\libc.a(fputc.o) + .text 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5\libc.a(ultoa_invert.o) + .data 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5\libc.a(ultoa_invert.o) + .bss 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5\libc.a(ultoa_invert.o) + .text 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5\libatmega328p.a(eerd_block.o) + .data 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5\libatmega328p.a(eerd_block.o) + .bss 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5\libatmega328p.a(eerd_block.o) + .text 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5\libatmega328p.a(eerd_byte.o) + .data 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5\libatmega328p.a(eerd_byte.o) + .bss 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5\libatmega328p.a(eerd_byte.o) + .text 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5\libatmega328p.a(eerd_word.o) + .data 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5\libatmega328p.a(eerd_word.o) + .bss 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5\libatmega328p.a(eerd_word.o) + .text 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_prologue.o) + .data 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_prologue.o) + .bss 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_prologue.o) + .text.libgcc.mul + 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_prologue.o) + .text.libgcc.div + 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_prologue.o) + .text.libgcc 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_prologue.o) + .text.libgcc.builtins + 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_prologue.o) + .text.libgcc.fmul + 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_prologue.o) + .text.libgcc.fixed + 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_prologue.o) + .text 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_epilogue.o) + .data 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_epilogue.o) + .bss 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_epilogue.o) + .text.libgcc.mul + 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_epilogue.o) + .text.libgcc.div + 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_epilogue.o) + .text.libgcc 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_epilogue.o) + .text.libgcc.builtins + 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_epilogue.o) + .text.libgcc.fmul + 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_epilogue.o) + .text.libgcc.fixed + 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_epilogue.o) + .text 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_copy_data.o) + .data 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_copy_data.o) + .bss 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_copy_data.o) + .text.libgcc.mul + 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_copy_data.o) + .text.libgcc.div + 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_copy_data.o) + .text.libgcc 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_copy_data.o) + .text.libgcc.prologue + 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_copy_data.o) + .text.libgcc.builtins + 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_copy_data.o) + .text.libgcc.fmul + 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_copy_data.o) + .text.libgcc.fixed + 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_copy_data.o) + .text 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_clear_bss.o) + .data 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_clear_bss.o) + .bss 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_clear_bss.o) + .text.libgcc.mul + 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_clear_bss.o) + .text.libgcc.div + 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_clear_bss.o) + .text.libgcc 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_clear_bss.o) + .text.libgcc.prologue + 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_clear_bss.o) + .text.libgcc.builtins + 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_clear_bss.o) + .text.libgcc.fmul + 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_clear_bss.o) + .text.libgcc.fixed + 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_clear_bss.o) + .text 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_ctors.o) + .data 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_ctors.o) + .bss 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_ctors.o) + .text.libgcc.mul + 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_ctors.o) + .text.libgcc.div + 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_ctors.o) + .text.libgcc 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_ctors.o) + .text.libgcc.prologue + 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_ctors.o) + .text.libgcc.builtins + 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_ctors.o) + .text.libgcc.fmul + 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_ctors.o) + .text.libgcc.fixed + 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_ctors.o) + .text 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_tablejump2.o) + .data 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_tablejump2.o) + .bss 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_tablejump2.o) + .text.libgcc.mul + 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_tablejump2.o) + .text.libgcc.div + 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_tablejump2.o) + .text.libgcc.prologue + 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_tablejump2.o) + .text.libgcc.builtins + 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_tablejump2.o) + .text.libgcc.fmul + 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_tablejump2.o) + .text.libgcc.fixed + 0x00000000 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_tablejump2.o) + +Memory Configuration + +Name Origin Length Attributes +text 0x00000000 0x00020000 xr +data 0x00800060 0x0000ffa0 rw !x +eeprom 0x00810000 0x00010000 rw !x +fuse 0x00820000 0x00000003 rw !x +lock 0x00830000 0x00000400 rw !x +signature 0x00840000 0x00000400 rw !x +user_signatures 0x00850000 0x00000400 rw !x +*default* 0x00000000 0xffffffff + +Linker script and memory map + +Address of section .data set to 0x800100 +LOAD c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5/crtatmega328p.o +LOAD .pio\build\ATmega328P\src\main.cpp.o +LOAD C:\Users\ldubies\AppData\Local\Temp\ccI9JQwb.ltrans0.ltrans.o +START GROUP +LOAD .pio\build\ATmega328P\libFrameworkArduinoVariant.a +LOAD .pio\build\ATmega328P\libFrameworkArduino.a +END GROUP +LOAD c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a +LOAD c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5\libm.a +START GROUP +LOAD c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a +LOAD c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5\libm.a +LOAD c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5\libc.a +LOAD c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5\libatmega328p.a +END GROUP + 0x00020000 __TEXT_REGION_LENGTH__ = DEFINED (__TEXT_REGION_LENGTH__)?__TEXT_REGION_LENGTH__:0x20000 + 0x0000ffa0 __DATA_REGION_LENGTH__ = DEFINED (__DATA_REGION_LENGTH__)?__DATA_REGION_LENGTH__:0xffa0 + 0x00010000 __EEPROM_REGION_LENGTH__ = DEFINED (__EEPROM_REGION_LENGTH__)?__EEPROM_REGION_LENGTH__:0x10000 + [0x00000003] __FUSE_REGION_LENGTH__ = DEFINED (__FUSE_REGION_LENGTH__)?__FUSE_REGION_LENGTH__:0x400 + 0x00000400 __LOCK_REGION_LENGTH__ = DEFINED (__LOCK_REGION_LENGTH__)?__LOCK_REGION_LENGTH__:0x400 + 0x00000400 __SIGNATURE_REGION_LENGTH__ = DEFINED (__SIGNATURE_REGION_LENGTH__)?__SIGNATURE_REGION_LENGTH__:0x400 + 0x00000400 __USER_SIGNATURE_REGION_LENGTH__ = DEFINED (__USER_SIGNATURE_REGION_LENGTH__)?__USER_SIGNATURE_REGION_LENGTH__:0x400 + +.hash + *(.hash) + +.dynsym + *(.dynsym) + +.dynstr + *(.dynstr) + +.gnu.version + *(.gnu.version) + +.gnu.version_d + *(.gnu.version_d) + +.gnu.version_r + *(.gnu.version_r) + +.rel.init + *(.rel.init) + +.rela.init + *(.rela.init) + +.rel.text + *(.rel.text) + *(.rel.text.*) + *(.rel.gnu.linkonce.t*) + +.rela.text + *(.rela.text) + *(.rela.text.*) + *(.rela.gnu.linkonce.t*) + +.rel.fini + *(.rel.fini) + +.rela.fini + *(.rela.fini) + +.rel.rodata + *(.rel.rodata) + *(.rel.rodata.*) + *(.rel.gnu.linkonce.r*) + +.rela.rodata + *(.rela.rodata) + *(.rela.rodata.*) + *(.rela.gnu.linkonce.r*) + +.rel.data + *(.rel.data) + *(.rel.data.*) + *(.rel.gnu.linkonce.d*) + +.rela.data + *(.rela.data) + *(.rela.data.*) + *(.rela.gnu.linkonce.d*) + +.rel.ctors + *(.rel.ctors) + +.rela.ctors + *(.rela.ctors) + +.rel.dtors + *(.rel.dtors) + +.rela.dtors + *(.rela.dtors) + +.rel.got + *(.rel.got) + +.rela.got + *(.rela.got) + +.rel.bss + *(.rel.bss) + +.rela.bss + *(.rela.bss) + +.rel.plt + *(.rel.plt) + +.rela.plt + *(.rela.plt) + +.text 0x00000000 0xee0 + *(.vectors) + .vectors 0x00000000 0x68 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5/crtatmega328p.o + 0x00000000 __vector_default + 0x00000000 __vectors + *(.vectors) + *(.progmem.gcc*) + 0x00000068 . = ALIGN (0x2) + 0x00000068 __trampolines_start = . + *(.trampolines) + .trampolines 0x00000068 0x0 linker stubs + *(.trampolines*) + 0x00000068 __trampolines_end = . + *libprintf_flt.a:*(.progmem.data) + *libc.a:*(.progmem.data) + *(.progmem*) + 0x00000068 . = ALIGN (0x2) + *(.jumptables) + *(.jumptables*) + *(.lowtext) + *(.lowtext*) + 0x00000068 __ctors_start = . + *(.ctors) + .ctors 0x00000068 0x2 C:\Users\ldubies\AppData\Local\Temp\ccI9JQwb.ltrans0.ltrans.o + 0x0000006a __ctors_end = . + 0x0000006a __dtors_start = . + *(.dtors) + 0x0000006a __dtors_end = . + SORT(*)(.ctors) + SORT(*)(.dtors) + *(.init0) + .init0 0x0000006a 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5/crtatmega328p.o + 0x0000006a __init + *(.init0) + *(.init1) + *(.init1) + *(.init2) + .init2 0x0000006a 0xc c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5/crtatmega328p.o + *(.init2) + *(.init3) + *(.init3) + *(.init4) + .init4 0x00000076 0x16 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_copy_data.o) + 0x00000076 __do_copy_data + .init4 0x0000008c 0x10 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_clear_bss.o) + 0x0000008c __do_clear_bss + *(.init4) + *(.init5) + *(.init5) + *(.init6) + .init6 0x0000009c 0x16 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_ctors.o) + 0x0000009c __do_global_ctors + *(.init6) + *(.init7) + *(.init7) + *(.init8) + *(.init8) + *(.init9) + .init9 0x000000b2 0x8 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5/crtatmega328p.o + *(.init9) + *(.text) + .text 0x000000ba 0x4 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5/crtatmega328p.o + 0x000000ba __vector_22 + 0x000000ba __vector_1 + 0x000000ba __vector_24 + 0x000000ba __vector_12 + 0x000000ba __bad_interrupt + 0x000000ba __vector_6 + 0x000000ba __vector_3 + 0x000000ba __vector_23 + 0x000000ba __vector_25 + 0x000000ba __vector_11 + 0x000000ba __vector_13 + 0x000000ba __vector_17 + 0x000000ba __vector_7 + 0x000000ba __vector_5 + 0x000000ba __vector_4 + 0x000000ba __vector_9 + 0x000000ba __vector_2 + 0x000000ba __vector_21 + 0x000000ba __vector_15 + 0x000000ba __vector_8 + 0x000000ba __vector_14 + 0x000000ba __vector_10 + 0x000000ba __vector_20 + .text 0x000000be 0x450 C:\Users\ldubies\AppData\Local\Temp\ccI9JQwb.ltrans0.ltrans.o + 0x000003ca __vector_16 + 0x0000045e __vector_19 + 0x000004aa __vector_18 + 0x0000050e . = ALIGN (0x2) + *(.text.*) + .text.startup 0x0000050e 0x41c C:\Users\ldubies\AppData\Local\Temp\ccI9JQwb.ltrans0.ltrans.o + 0x0000050e main + .text.avr-libc + 0x0000092a 0x3b4 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5\libc.a(vfprintf_std.o) + 0x0000092a vfprintf + .text.avr-libc + 0x00000cde 0x16 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5\libc.a(strnlen_P.o) + 0x00000cde strnlen_P + .text.avr-libc + 0x00000cf4 0x16 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5\libc.a(strnlen.o) + 0x00000cf4 strnlen + .text.avr-libc + 0x00000d0a 0x60 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5\libc.a(fputc.o) + 0x00000d0a fputc + .text.avr-libc + 0x00000d6a 0xbc c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5\libc.a(ultoa_invert.o) + 0x00000d6a __ultoa_invert + .text.avr-libc + 0x00000e26 0x20 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5\libatmega328p.a(eerd_block.o) + 0x00000e26 eeprom_read_block + 0x00000e2a eeprom_read_blraw + .text.avr-libc + 0x00000e46 0x10 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5\libatmega328p.a(eerd_byte.o) + 0x00000e46 eeprom_read_byte + .text.avr-libc + 0x00000e56 0xc c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5\libatmega328p.a(eerd_word.o) + 0x00000e56 eeprom_read_word + .text.libgcc.prologue + 0x00000e62 0x38 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_prologue.o) + 0x00000e62 __prologue_saves__ + .text.libgcc.prologue + 0x00000e9a 0x36 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_epilogue.o) + 0x00000e9a __epilogue_restores__ + .text.libgcc 0x00000ed0 0xc c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_tablejump2.o) + 0x00000ed0 __tablejump2__ + 0x00000edc . = ALIGN (0x2) + *(.fini9) + .fini9 0x00000edc 0x0 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_exit.o) + 0x00000edc _exit + 0x00000edc exit + *(.fini9) + *(.fini8) + *(.fini8) + *(.fini7) + *(.fini7) + *(.fini6) + *(.fini6) + *(.fini5) + *(.fini5) + *(.fini4) + *(.fini4) + *(.fini3) + *(.fini3) + *(.fini2) + *(.fini2) + *(.fini1) + *(.fini1) + *(.fini0) + .fini0 0x00000edc 0x4 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_exit.o) + *(.fini0) + 0x00000ee0 _etext = . + +.data 0x00800100 0x340 load address 0x00000ee0 + 0x00800100 PROVIDE (__data_start, .) + *(.data) + *(.data*) + *(.gnu.linkonce.d*) + *(.rodata) + .rodata 0x00800100 0x12 C:\Users\ldubies\AppData\Local\Temp\ccI9JQwb.ltrans0.ltrans.o + *(.rodata*) + .rodata.str1.1 + 0x00800112 0x32e C:\Users\ldubies\AppData\Local\Temp\ccI9JQwb.ltrans0.ltrans.o + 0x330 (size before relaxing) + *(.gnu.linkonce.r*) + 0x00800440 . = ALIGN (0x2) + 0x00800440 _edata = . + 0x00800440 PROVIDE (__data_end, .) + +.bss 0x00800440 0xa6 + 0x00800440 PROVIDE (__bss_start, .) + *(.bss) + .bss 0x00800440 0xa6 C:\Users\ldubies\AppData\Local\Temp\ccI9JQwb.ltrans0.ltrans.o + *(.bss*) + *(COMMON) + 0x008004e6 PROVIDE (__bss_end, .) + 0x00000ee0 __data_load_start = LOADADDR (.data) + 0x00001220 __data_load_end = (__data_load_start + SIZEOF (.data)) + +.noinit 0x008004e6 0x0 + [!provide] PROVIDE (__noinit_start, .) + *(.noinit*) + [!provide] PROVIDE (__noinit_end, .) + 0x008004e6 _end = . + [!provide] PROVIDE (__heap_start, .) + +.eeprom 0x00810000 0x0 + 0x81000000 paraBlkSafety_blkhdr = 0x81000000 + 0x81000010 array = 0x81000010 + 0x81000100 hello = 0x81000100 + 0x8100010e val = 0x8100010e + 0x81000110 birthday = 0x81000110 + 0x81000114 negativePi = 0x81000114 + 0x810001fc crc2 = 0x810001fc + 0x81000200 structTestBlock_blkhdr = 0x81000200 + 0x81000210 simpy = 0x81000210 + 0x81000213 biggy = 0x81000213 + *(.eeprom*) + 0x00810000 __eeprom_end = . + +.fuse + *(.fuse) + *(.lfuse) + *(.hfuse) + *(.efuse) + +.lock + *(.lock*) + +.signature + *(.signature*) + +.user_signatures + *(.user_signatures*) + +.stab + *(.stab) + +.stabstr + *(.stabstr) + +.stab.excl + *(.stab.excl) + +.stab.exclstr + *(.stab.exclstr) + +.stab.index + *(.stab.index) + +.stab.indexstr + *(.stab.indexstr) + +.comment 0x00000000 0x11 + *(.comment) + .comment 0x00000000 0x12 C:\Users\ldubies\AppData\Local\Temp\ccI9JQwb.ltrans0.ltrans.o + .comment 0x00000000 0x11 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5\libc.a(vfprintf_std.o) + 0x12 (size before relaxing) + .comment 0x00000011 0x12 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5\libc.a(fputc.o) + +.note.gnu.avr.deviceinfo + 0x00000000 0x40 + .note.gnu.avr.deviceinfo + 0x00000000 0x40 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5/crtatmega328p.o + +.note.gnu.build-id + *(.note.gnu.build-id) + +.debug + *(.debug) + +.line + *(.line) + +.debug_srcinfo + *(.debug_srcinfo) + +.debug_sfnames + *(.debug_sfnames) + +.debug_aranges 0x00000000 0xe0 + *(.debug_aranges) + .debug_aranges + 0x00000000 0x20 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_exit.o) + .debug_aranges + 0x00000020 0x20 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_prologue.o) + .debug_aranges + 0x00000040 0x20 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_epilogue.o) + .debug_aranges + 0x00000060 0x20 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_copy_data.o) + .debug_aranges + 0x00000080 0x20 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_clear_bss.o) + .debug_aranges + 0x000000a0 0x20 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_ctors.o) + .debug_aranges + 0x000000c0 0x20 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_tablejump2.o) + +.debug_pubnames + *(.debug_pubnames) + +.debug_info 0x00000000 0xb11 + *(.debug_info .gnu.linkonce.wi.*) + .debug_info 0x00000000 0x5f4 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5/crtatmega328p.o + .debug_info 0x000005f4 0xbb c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_exit.o) + .debug_info 0x000006af 0xbb c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_prologue.o) + .debug_info 0x0000076a 0xbb c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_epilogue.o) + .debug_info 0x00000825 0xbb c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_copy_data.o) + .debug_info 0x000008e0 0xbb c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_clear_bss.o) + .debug_info 0x0000099b 0xbb c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_ctors.o) + .debug_info 0x00000a56 0xbb c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_tablejump2.o) + +.debug_abbrev 0x00000000 0x62e + *(.debug_abbrev) + .debug_abbrev 0x00000000 0x5a2 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5/crtatmega328p.o + .debug_abbrev 0x000005a2 0x14 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_exit.o) + .debug_abbrev 0x000005b6 0x14 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_prologue.o) + .debug_abbrev 0x000005ca 0x14 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_epilogue.o) + .debug_abbrev 0x000005de 0x14 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_copy_data.o) + .debug_abbrev 0x000005f2 0x14 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_clear_bss.o) + .debug_abbrev 0x00000606 0x14 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_ctors.o) + .debug_abbrev 0x0000061a 0x14 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_tablejump2.o) + +.debug_line 0x00000000 0x49c + *(.debug_line .debug_line.* .debug_line_end) + .debug_line 0x00000000 0x1a c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5/crtatmega328p.o + .debug_line 0x0000001a 0x62 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_exit.o) + .debug_line 0x0000007c 0xfe c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_prologue.o) + .debug_line 0x0000017a 0xf8 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_epilogue.o) + .debug_line 0x00000272 0x98 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_copy_data.o) + .debug_line 0x0000030a 0x86 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_clear_bss.o) + .debug_line 0x00000390 0x92 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_ctors.o) + .debug_line 0x00000422 0x7a c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_tablejump2.o) + +.debug_frame + *(.debug_frame) + +.debug_str 0x00000000 0x208 + *(.debug_str) + .debug_str 0x00000000 0x208 c:/users/ldubies/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5/crtatmega328p.o + +.debug_loc + *(.debug_loc) + +.debug_macinfo + *(.debug_macinfo) + +.debug_weaknames + *(.debug_weaknames) + +.debug_funcnames + *(.debug_funcnames) + +.debug_typenames + *(.debug_typenames) + +.debug_varnames + *(.debug_varnames) + +.debug_pubtypes + *(.debug_pubtypes) + +.debug_ranges + *(.debug_ranges) + +.debug_macro + *(.debug_macro) +OUTPUT(.pio\build\ATmega328P\firmware.elf elf32-avr) +LOAD linker stubs diff --git a/examples/arduino_struct_test/param/param.c b/examples/arduino_struct_test/param/param.c new file mode 100644 index 0000000..1ff2b2d --- /dev/null +++ b/examples/arduino_struct_test/param/param.c @@ -0,0 +1,101 @@ +/* AUTOGENERATED by pargen 0.5.0 + * cmd: C:\Users\ldubies\Repos\flashcontainer\.venv\Scripts\pargen --ihex --csrc --gld --pyhexdump --destdir param --filename param param\structexample.xml + * Time: 2023-08-30 15:40:22.608431 + * Buildkey: 3979c938-ebaa-4c7d-b8fc-5b0624f977ec + * !! DO NOT EDIT MANUALLY !! + */ + +#include "param.h" + +/* BEGIN Block paraBlkSafety in container CodeFlash @ 0x81000000 + * + * This block is used for any-safety related parameters. + */ +volatile const pargen_header_type_t paraBlkSafety_blkhdr = +{ + 0x0D00, + 0x0001, + 0x0000, + 0x0000, + 0x00000000, + 0x00000200, +}; + +/* Parameter array @ 0x81000010 + */ +volatile const float array[6] = + +{ + 0.11100000, -2.09999990, 3.20000005, 4.50000000, + 5.40000010, 6.50000000 +}; + +/* Parameter hello @ 0x81000100 + */ +volatile const char hello[13] = + +{ + 0x48, 0x65, 0x6C, 0x6C, + 0x6F, 0x20, 0x77, 0x6F, + 0x72, 0x6C, 0x64, 0x21, + 0x00 +}; + +/* Parameter val @ 0x8100010e + */ +volatile const uint16_t val = +0x1604; + +/* Parameter birthday @ 0x81000110 + */ +volatile const float birthday = + 0.16046900; + +/* Parameter negativePi @ 0x81000114 + */ +volatile const float negativePi = + -3.14100003; + +/* Parameter crc2 @ 0x810001fc + * block crc32 (IEEE802.3) + * crc: 0x81000000-0x810001FB polynomial:0x4C11DB7, 32 Bit, init:0xFFFFFFFF, reverse in:True, reverse out:True, final xor:True, access:8, swap:False + */ +volatile const uint32_t crc2 = +0x330119E6; + +/* END Block paraBlkSafety */ + +/* BEGIN Block structTestBlock in container CodeFlash @ 0x81000200 + * + * This block contains parameters that use structs + */ +volatile const pargen_header_type_t structTestBlock_blkhdr = +{ + 0x0E12, + 0x0001, + 0x0000, + 0x0000, + 0x00000000, + 0x00000200, +}; + +/* Parameter simpy @ 0x81000210 + */ +volatile const pargen_SimpleS_type_t simpy = { + 0x03, + 0x05, + 0xD7, +}; + +/* Parameter biggy @ 0x81000213 + */ +volatile const pargen_ComplexS_type_t biggy = { + 0x01, + {0xFF, 0xFF, 0xFF, 0xFF}, + 0x2F59, + {0xFF, 0xFF}, + {0x0001, 0x0004, 0x0010, 0x0040}, +}; + +/* END Block structTestBlock */ + diff --git a/examples/arduino_struct_test/param/param.crc b/examples/arduino_struct_test/param/param.crc new file mode 100644 index 0000000..30b165d --- /dev/null +++ b/examples/arduino_struct_test/param/param.crc @@ -0,0 +1 @@ +0xB2FCD89 diff --git a/examples/arduino_struct_test/param/param.h b/examples/arduino_struct_test/param/param.h new file mode 100644 index 0000000..6cd1daa --- /dev/null +++ b/examples/arduino_struct_test/param/param.h @@ -0,0 +1,105 @@ +/* AUTOGENERATED by pargen 0.5.0 + * cmd: C:\Users\ldubies\Repos\flashcontainer\.venv\Scripts\pargen --ihex --csrc --gld --pyhexdump --destdir param --filename param param\structexample.xml + * Time: 2023-08-30 15:40:22.608431 + * Buildkey: 3979c938-ebaa-4c7d-b8fc-5b0624f977ec + * !! DO NOT EDIT MANUALLY !! + */ + +#ifndef PARGEN_HEADER_INCLUDED_PARAM +#define PARGEN_HEADER_INCLUDED_PARAM + +#ifdef __cplusplus +extern "C" { +#endif + +#include +typedef struct sruct_pargen_header_type +{ + uint16_t id; + uint16_t major; + uint16_t minor; + uint16_t dataver; + uint32_t reserved; + uint32_t length; +} pargen_header_type_t; + +/* Typedef for SimpleS struct * + * This struct is super simple + */ +#pragma pack(push, 1) +typedef struct sruct_pargen_SimpleS_type +{ + uint8_t int1; + uint8_t int2; + uint8_t smallcrc; +} pargen_SimpleS_type_t; +#pragma pack(pop) + +/* Typedef for ComplexS struct * + * This struct will feature padding and arrays + */ +#pragma pack(push, 1) +typedef struct sruct_pargen_ComplexS_type +{ + uint8_t int1; + char padding0[4]; + uint16_t int2; + char padding1[2]; + uint16_t intarray[4]; +} pargen_ComplexS_type_t; +#pragma pack(pop) + +/* BEGIN Block paraBlkSafety in container CodeFlash @ 0x81000000 + * + * This block is used for any-safety related parameters. + */ +extern volatile const pargen_header_type_t paraBlkSafety_blkhdr; + +/* Parameter array @ 0x81000010 + */ +extern volatile const float array[6]; + +/* Parameter hello @ 0x81000100 + */ +extern volatile const char hello[13]; + +/* Parameter val @ 0x8100010e + */ +extern volatile const uint16_t val; + +/* Parameter birthday @ 0x81000110 + */ +extern volatile const float birthday; + +/* Parameter negativePi @ 0x81000114 + */ +extern volatile const float negativePi; + +/* Parameter crc2 @ 0x810001fc + * block crc32 (IEEE802.3) + * crc: 0x81000000-0x810001FB polynomial:0x4C11DB7, 32 Bit, init:0xFFFFFFFF, reverse in:True, reverse out:True, final xor:True, access:8, swap:False + */ +extern volatile const uint32_t crc2; + +/* END Block paraBlkSafety */ + +/* BEGIN Block structTestBlock in container CodeFlash @ 0x81000200 + * + * This block contains parameters that use structs + */ +extern volatile const pargen_header_type_t structTestBlock_blkhdr; + +/* Parameter simpy @ 0x81000210 + */ +extern volatile const pargen_SimpleS_type_t simpy; + +/* Parameter biggy @ 0x81000213 + */ +extern volatile const pargen_ComplexS_type_t biggy; + +/* END Block structTestBlock */ + +#ifdef __cplusplus +} +#endif +#endif diff --git a/examples/arduino_struct_test/param/param.hex b/examples/arduino_struct_test/param/param.hex new file mode 100644 index 0000000..f04b510 --- /dev/null +++ b/examples/arduino_struct_test/param/param.hex @@ -0,0 +1,66 @@ +:02000004810079 +:10000000000D0100000000000000000000020000E0 +:10001000F853E33D666606C0CDCC4C4000009040EE +:10002000CDCCAC400000D040ABABABABABABABABE3 +:10003000ABABABABABABABABABABABABABABABAB10 +:10004000ABABABABABABABABABABABABABABABAB00 +:10005000ABABABABABABABABABABABABABABABABF0 +:10006000ABABABABABABABABABABABABABABABABE0 +:10007000ABABABABABABABABABABABABABABABABD0 +:10008000ABABABABABABABABABABABABABABABABC0 +:10009000ABABABABABABABABABABABABABABABABB0 +:1000A000ABABABABABABABABABABABABABABABABA0 +:1000B000ABABABABABABABABABABABABABABABAB90 +:1000C000ABABABABABABABABABABABABABABABAB80 +:1000D000ABABABABABABABABABABABABABABABAB70 +:1000E000ABABABABABABABABABABABABABABABAB60 +:1000F000ABABABABABABABABABABABABABABABAB50 +:1001000048656C6C6F20776F726C642100AB0416CD +:10011000FC51243E250649C0ABABABABABABABABA4 +:10012000ABABABABABABABABABABABABABABABAB1F +:10013000ABABABABABABABABABABABABABABABAB0F +:10014000ABABABABABABABABABABABABABABABABFF +:10015000ABABABABABABABABABABABABABABABABEF +:10016000ABABABABABABABABABABABABABABABABDF +:10017000ABABABABABABABABABABABABABABABABCF +:10018000ABABABABABABABABABABABABABABABABBF +:10019000ABABABABABABABABABABABABABABABABAF +:1001A000ABABABABABABABABABABABABABABABAB9F +:1001B000ABABABABABABABABABABABABABABABAB8F +:1001C000ABABABABABABABABABABABABABABABAB7F +:1001D000ABABABABABABABABABABABABABABABAB6F +:1001E000ABABABABABABABABABABABABABABABAB5F +:1001F000ABABABABABABABABABABABABE6190133C8 +:10020000120E0100000000000000000000020000CB +:100210000305D701FFFFFFFF592FFFFF0100040077 +:1002200010004000FFFFFFFFFFFFFFFFFFFFFFFF8A +:10023000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCE +:10024000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBE +:10025000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAE +:10026000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9E +:10027000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8E +:10028000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7E +:10029000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6E +:1002A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5E +:1002B000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4E +:1002C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3E +:1002D000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2E +:1002E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1E +:1002F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0E +:10030000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD +:10031000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED +:10032000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDD +:10033000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCD +:10034000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBD +:10035000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAD +:10036000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9D +:10037000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8D +:10038000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7D +:10039000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6D +:1003A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D +:1003B000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4D +:1003C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3D +:1003D000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2D +:1003E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1D +:1003F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0D +:00000001FF diff --git a/examples/arduino_struct_test/param/param.ld b/examples/arduino_struct_test/param/param.ld new file mode 100644 index 0000000..3305973 --- /dev/null +++ b/examples/arduino_struct_test/param/param.ld @@ -0,0 +1,21 @@ +/* AUTOGENERATED by pargen 0.5.0 + * GNU Linker script definitions - include to main script using 'INCLUDE param.ld' + * cmd: C:\Users\ldubies\Repos\flashcontainer\.venv\Scripts\pargen --ihex --csrc --gld --pyhexdump --destdir param --filename param param\structexample.xml + * Date: 2023-08-30 15:40:22.608431 + * Buildkey: 3979c938-ebaa-4c7d-b8fc-5b0624f977ec + * !! DO NOT EDIT MANUALLY !! + */ + +/* Begin flash container CodeFlash @ 0x81000000 */ +paraBlkSafety_blkhdr = 0x81000000; +array = 0x81000010; +hello = 0x81000100; +val = 0x8100010e; +birthday = 0x81000110; +negativePi = 0x81000114; +crc2 = 0x810001fc; /* block crc32 (IEEE802.3) */ + +structTestBlock_blkhdr = 0x81000200; +simpy = 0x81000210; +biggy = 0x81000213; +/* End flash container CodeFlash @ 0x81000000 */ diff --git a/examples/arduino_struct_test/param/param.pyhexdump b/examples/arduino_struct_test/param/param.pyhexdump new file mode 100644 index 0000000..902a956 --- /dev/null +++ b/examples/arduino_struct_test/param/param.pyhexdump @@ -0,0 +1,227 @@ +{ + "_comment_": [ + "Configuration file for pyHexDump, see https://github.com/BlueAndi/pyHexDump", + "GENERATED by pargen 0.5.0 ", + "cmd: C:\\Users\\ldubies\\Repos\\flashcontainer\\.venv\\Scripts\\pargen --ihex --csrc --gld --pyhexdump --destdir param --filename param param\\structexample.xml", + "date: 2023-08-30 15:40:22.608431", + "Buildkey: 3979c938-ebaa-4c7d-b8fc-5b0624f977ec" + ], + "structures": [ + { + "name": "pargen_header_le_t", + "elements": [ + { + "name": "id", + "dataType": "uint16le", + "count": 1 + }, + { + "name": "major", + "dataType": "uint16le", + "count": 1 + }, + { + "name": "minor", + "dataType": "uint16le", + "count": 1 + }, + { + "name": "dataver", + "dataType": "uint16le", + "count": 1 + }, + { + "name": "reserved", + "dataType": "uint32le", + "count": 1 + }, + { + "name": "length", + "dataType": "uint32le", + "count": 1 + } + ] + }, + { + "name": "pargen_header_be_t", + "elements": [ + { + "name": "id", + "dataType": "uint16be", + "count": 1 + }, + { + "name": "major", + "dataType": "uint16be", + "count": 1 + }, + { + "name": "minor", + "dataType": "uint16be", + "count": 1 + }, + { + "name": "dataver", + "dataType": "uint16be", + "count": 1 + }, + { + "name": "reserved", + "dataType": "uint32be", + "count": 1 + }, + { + "name": "length", + "dataType": "uint32be", + "count": 1 + } + ] + }, + { + "name": "pargen_SimpleS_le_t", + "elements": [ + { + "name": "int1", + "dataType": "uint8", + "count": 1 + }, + { + "name": "int2", + "dataType": "uint8", + "count": 1 + }, + { + "name": "smallcrc", + "dataType": "uint8", + "count": 1 + } + ] + }, + { + "name": "pargen_SimpleS_be_t", + "elements": [ + { + "name": "int1", + "dataType": "uint8", + "count": 1 + }, + { + "name": "int2", + "dataType": "uint8", + "count": 1 + }, + { + "name": "smallcrc", + "dataType": "uint8", + "count": 1 + } + ] + }, + { + "name": "pargen_ComplexS_le_t", + "elements": [ + { + "name": "int1", + "dataType": "uint8", + "count": 1 + }, + { + "name": "int2", + "dataType": "uint16le", + "count": 1, + "offset": 5 + }, + { + "name": "intarray", + "dataType": "uint16le", + "count": 4, + "offset": 9 + } + ] + }, + { + "name": "pargen_ComplexS_be_t", + "elements": [ + { + "name": "int1", + "dataType": "uint8", + "count": 1 + }, + { + "name": "int2", + "dataType": "uint16be", + "count": 1, + "offset": 5 + }, + { + "name": "intarray", + "dataType": "uint16be", + "count": 4, + "offset": 9 + } + ] + } + ], + "elements": [ + { + "name": "paraBlkSafety_blkhdr", + "addr": "0x81000000", + "dataType": "pargen_header_le_t", + "count": 1 + }, + { + "name": "array", + "addr": "0x81000010", + "dataType": "float32le", + "count": 6 + }, + { + "name": "hello", + "addr": "0x81000100", + "dataType": "utf8", + "count": 13 + }, + { + "name": "val", + "addr": "0x8100010e", + "dataType": "uint16le", + "count": 1 + }, + { + "name": "birthday", + "addr": "0x81000110", + "dataType": "float32le", + "count": 1 + }, + { + "name": "negativePi", + "addr": "0x81000114", + "dataType": "float32le", + "count": 1 + }, + { + "name": "crc2", + "addr": "0x810001fc", + "dataType": "uint32le", + "count": 1 + }, + { + "name": "structTestBlock_blkhdr", + "addr": "0x81000200", + "dataType": "pargen_header_le_t", + "count": 1 + }, + { + "name": "simpy", + "addr": "0x81000210", + "dataType": "pargen_SimpleS_le_t", + "count": 1 + }, + { + "name": "biggy", + "addr": "0x81000213", + "dataType": "pargen_ComplexS_le_t", + "count": 1 + } + ] +} \ No newline at end of file diff --git a/examples/arduino_struct_test/param/param.xml b/examples/arduino_struct_test/param/param.xml new file mode 100644 index 0000000..8076deb --- /dev/null +++ b/examples/arduino_struct_test/param/param.xml @@ -0,0 +1,26 @@ + + + + + + 1Kb Example parameter block for displaying a flashable message with update delay + + + + Interval time between dumping welcome message. + 2000 + + + Message to display in endless loop. + "This message is defined as a Pargen parameter!\r\n" + + + + + + + + + \ No newline at end of file diff --git a/examples/arduino_struct_test/param/structexample.xml b/examples/arduino_struct_test/param/structexample.xml new file mode 100644 index 0000000..85be03d --- /dev/null +++ b/examples/arduino_struct_test/param/structexample.xml @@ -0,0 +1,71 @@ + + + + This struct is super simple + + + + + + + + + + + This struct will feature padding and arrays + + + + + I will need so much space + + + + + + + + + + This block is used for any-safety related parameters. + + + + [0.111,-2.1,3.2,4.5,5.4,6.5] + + + "Hello world!" + + + 0x1604 + + + 0.160469 + + + -3.141 + + + block crc32 (IEEE802.3) + + + + + + + This block contains parameters that use structs + + + + { "int1": 3, "int2": 5} + + + {"int1": 1, "int2": 12121, "intarray": [1, 4, 16, 64]} + + + + + + diff --git a/examples/arduino_struct_test/param/weird.xml b/examples/arduino_struct_test/param/weird.xml new file mode 100644 index 0000000..38a24e3 --- /dev/null +++ b/examples/arduino_struct_test/param/weird.xml @@ -0,0 +1,97 @@ + + + + This struct is super simple + + + + + + + + + + + This struct will feature padding and arrays + + + + + I will need so much space + + + + + + + + + This block is used for non-safety related parameters only. + + + + see https://www.boost.org/doc/libs/1_79_0/libs/crc/test/crc_test2.cpp + [0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39] + + + expected: CBF43926 + + + + Integer array example + [-4, -3, -2, -1, 0, 1, 2, 3, 4] + + + block crc32 (IEEE802.3) + + + + + + + + This block is used for any-safety related parameters. + + + + [0.111,-2.1,3.2,4.5,5.4,6.5] + + + "Hello world!" + + + 0x1604 + + + 0.160469 + + + -3.141 + + + block crc32 (IEEE802.3) + + + + + + + This block contains parameters that use structs + + + + { "int1": 3, "int2": 5} + + + {"int1": 1, "int2": 9999999, "intarray": [1, 4, 16, 64]} + + + 0x3553 + + + + + + diff --git a/examples/arduino_struct_test/platformio.ini b/examples/arduino_struct_test/platformio.ini new file mode 100644 index 0000000..dc7ae9c --- /dev/null +++ b/examples/arduino_struct_test/platformio.ini @@ -0,0 +1,31 @@ +; PlatformIO Project Configuration File +; +; Build options: build flags, source filter +; Upload options: custom upload port, speed and extra flags +; Library options: dependencies, extra library storages +; Advanced options: extra scripting +; +; Please visit documentation for the other options and examples +; https://docs.platformio.org/page/projectconf.html + +[env:ATmega328P] +platform = atmelavr +board = ATmega328P +framework = arduino +build_flags = -Wl,-Map,output.map ; -Wl,--verbose +board_build.ldscript = avr5.xn + +platform_packages = platformio/tool-simavr + +debug_tool = simavr +debug_server = + ${platformio.packages_dir}/tool-simavr/bin/simavr + -g + 1234 + -m + atmega328p + -f + 16000000L + -ee + $PROJECT_DIR/param/param.hex + ${platformio.build_dir}/${this.__env__}/firmware.elf diff --git a/examples/arduino_struct_test/run_simavr.bat b/examples/arduino_struct_test/run_simavr.bat new file mode 100644 index 0000000..2454bf0 --- /dev/null +++ b/examples/arduino_struct_test/run_simavr.bat @@ -0,0 +1,2 @@ +@SET SIM=%USERPROFILE%\.platformio\packages\tool-simavr\bin\simavr +%SIM% -m atmega328p -f 16000000L -ee param\param.hex .pio\build\ATmega328P\firmware.hex diff --git a/examples/arduino_struct_test/run_simavr.sh b/examples/arduino_struct_test/run_simavr.sh new file mode 100644 index 0000000..67128b1 --- /dev/null +++ b/examples/arduino_struct_test/run_simavr.sh @@ -0,0 +1,3 @@ +#!/bin/sh +cmd=$HOME/.platformio/packages/tool-simavr/bin/simavr +$cmd -m atmega328p -f 16000000L -ee param/param.hex .pio/build/ATmega328P/firmware.hex diff --git a/examples/arduino_struct_test/src/main.cpp b/examples/arduino_struct_test/src/main.cpp new file mode 100644 index 0000000..2fa8f09 --- /dev/null +++ b/examples/arduino_struct_test/src/main.cpp @@ -0,0 +1,124 @@ +#include +#include + +#include "../param/param.h" + + +/** Crc32 simple implementation without lookup table*/ +class Crc32 +{ + public: + Crc32() : m_crc(0xFFFFFFFFUL) + { + } + + uint32_t get() + { + return ~m_crc; + } + + void update(uint8_t byte) + { + for (uint8_t i = 0; i < 8; ++i) + { + uint32_t tmp((byte ^ m_crc) & 0x1u); + m_crc >>= 1; + if (0 != tmp) { + m_crc ^= 0xEDB88320; + } + byte >>= 1; + } + } + + private: + uint32_t m_crc; +}; + +/** Check for expected block in EEPROM and validate content + * + * Halts on errors + */ +void setup() +{ + pargen_header_type_t parHdr; + + Serial.begin(9600); + + eeprom_read_block(&parHdr, (const void *)¶BlkSafety_blkhdr, sizeof(parHdr)); + + Serial.printf( + "Found pargen block header in EEPROM: ID:%0X Version:%d.%d Length: %lu bytes\n", + parHdr.id, + parHdr.major, + parHdr.minor, + parHdr.length + ); + Serial.printf("Address for safety block header in mem is %p \n", (void *)¶BlkSafety_blkhdr); + Serial.println("-------------------------------------------------"); + + Serial.println("Testing value out of safety block"); + uint16_t valtest = eeprom_read_word((const uint16_t*)&val); + Serial.printf("The val in eeprom is %u\n", (unsigned int)valtest); + Serial.printf("Address for val in mem is %p \n", (void *)&val); + Serial.println("-------------------------------------------------"); + + // output structure content + uint8_t one = eeprom_read_byte((const uint8_t*)(&simpy.int1)); + uint8_t two = eeprom_read_byte((const uint8_t*)(&simpy.int2)); + uint8_t three = eeprom_read_byte((const uint8_t*)&simpy.smallcrc); + + Serial.println("When reading single values out of structs:"); + Serial.printf("The simple struct contains %d, %d and %d\n", one, two, three); + + pargen_SimpleS_type_t newsimpy; + eeprom_read_block(&newsimpy, (const void *)&simpy, sizeof(newsimpy)); + + Serial.println("When reading the whole struct from eeprom:"); + Serial.printf( + "Simpy in EEPROM: int1:%d int2:%d smallcrc:%d\n", + newsimpy.int1, + newsimpy.int2, + newsimpy.smallcrc + ); + + Serial.println("-------------------------------------------------"); + Serial.printf("Address for simpy in mem is %p \n", (void *)&simpy); + Serial.printf("Address for simpy.smallcrc in mem is %p \n", (void *)&simpy.smallcrc); + + /* + Serial.println("Simpy from param.c holds:"); + Serial.printf( + "Simpy defined: int1:%d int2:%d smallcrc:%d\n", + simpy.int1, + simpy.int2, + simpy.smallcrc + ); + */ + + Serial.println("-------------------------------------------------"); + Serial.printf("Address for biggy in mem is %p \n", (void *)&biggy); + Serial.printf("Address for biggy.int1 in mem is %p \n", (void *)&biggy.int1); + Serial.printf("Address for biggy.padding0 in mem is %p \n", (void *)&biggy.padding0); + Serial.printf("Address for biggy.int2 in mem is %p \n", (void *)&biggy.int2); + Serial.printf("Address for biggy.padding1 in mem is %p \n", (void *)&biggy.padding1); + Serial.printf("Address for biggy.intarray in mem is %p \n", (void *)&biggy.intarray); + + pargen_ComplexS_type_t newbiggy; + eeprom_read_block(&newbiggy, (const void *)&biggy, sizeof(newbiggy)); + + + Serial.printf("biggy.int1 from EEPROM: %u \n", newbiggy.int1); + Serial.printf("biggy.int2 from EEPROM: %u \n", newbiggy.int2); + for(unsigned int i = 0; i < (sizeof(newbiggy.intarray) / sizeof(newbiggy.intarray[0])); i++) + { + Serial.printf("%u, ", newbiggy.intarray[i]); + } + Serial.println("\n"); + +} + + +void loop() +{ + delay(5000); +} \ No newline at end of file diff --git a/examples/arduino_struct_test/test/README b/examples/arduino_struct_test/test/README new file mode 100644 index 0000000..9b1e87b --- /dev/null +++ b/examples/arduino_struct_test/test/README @@ -0,0 +1,11 @@ + +This directory is intended for PlatformIO Test Runner and project tests. + +Unit Testing is a software testing method by which individual units of +source code, sets of one or more MCU program modules together with associated +control data, usage procedures, and operating procedures, are tested to +determine whether they are fit for use. Unit testing finds problems early +in the development cycle. + +More information about PlatformIO Unit Testing: +- https://docs.platformio.org/en/latest/advanced/unit-testing/index.html diff --git a/src/flashcontainer/byteconv.py b/src/flashcontainer/byteconv.py index 5528482..a453fdd 100644 --- a/src/flashcontainer/byteconv.py +++ b/src/flashcontainer/byteconv.py @@ -32,7 +32,7 @@ import struct import json5 - +from lxml.etree import DocumentInvalid import flashcontainer.datamodel as DM class ByteConvert: @@ -69,12 +69,71 @@ def json_to_bytes(ptype: DM.ParamType, endianess: DM.Endianness, value_str: str result.extend(b'\x00') else: - raise Exception(f"unsupported json value type {variant}") # pylint: disable=broad-except + raise DocumentInvalid(f"unsupported json value type {variant}") return result @staticmethod - def bytes_to_c_init(ptype: DM.ParamType, endianess: DM.Endianness, data: bytearray) -> str: + def fill_struct_from_json(strct: DM.Datastruct, input_str: str, + endianess: DM.Endianness, blockfill: int) -> bytearray: + """Parse values for the structs field from JSON input""" + + # check for invalid input + input_dict = json5.loads(input_str) + if not isinstance(input_dict, dict): + raise DocumentInvalid(f"Invalid input for struct:\n{input_str}") + if not set(strct.get_field_names()) == set(input_dict.keys()): + raise DocumentInvalid(f"struct {strct.name} field names and input keys are not equal") + + data = bytearray() + for component in strct.fields: + if isinstance(component, DM.Padding): + if strct.filloption == "parent": + data.extend(bytearray((blockfill for _ in range(component.size)))) + else: + data.extend(bytearray((strct.filloption for _ in range(component.size)))) + continue + fmt = "<" if endianess == DM.Endianness.LE else ">" + fmt += DM.TYPE_DATA[component.type].fmt + if isinstance(component, DM.Field): + data.extend(bytearray(struct.pack(fmt, input_dict[component.name]))) + elif isinstance(component, DM.ArrayField): + # check input validity for array + ain = input_dict[component.name] + if not isinstance(ain, list): + raise DocumentInvalid(f"Invalid input for struct:\n{input_str}") + if len(ain) != component.count: + raise DocumentInvalid(f"ArrayField {component.name} of size {component.count}\ + supplied with {len(ain)} values.") + for input_val in ain: + data.extend(bytearray(struct.pack(fmt, input_val))) + else: # crc + calculator = DM.Crc(component.cfg) + buffer = calculator.prepare(data.copy()) + crc_input = buffer[component.start: component.end + 1] + checksum = calculator.checksum(crc_input) + + fmt = f"<{DM.TYPE_DATA[component.type].fmt}" if endianess == DM.Endianness.LE \ + else f">{DM.TYPE_DATA[component.type].fmt}" + + byte_checksum = struct.pack(fmt, checksum) + data.extend(byte_checksum) + + return data + + @staticmethod + def value_to_c(value: int, type_data: DM.TypeData) -> str: + """Convert single value to valid C""" + if isinstance(value, float): + return f"{value:>{type_data.width}.8f}" + if isinstance(value, bytes): + return f"0x{value.hex().upper()}" + if type_data.signed: + return f"{value:>{type_data.width}}" + return f"0x{value:0{2*type_data.size}X}" + + @staticmethod + def bytes_to_c_init(ptype: DM.ParamType, endianess: DM.Endianness, data: bytearray) -> str: """Convert raw data to C-Language initializer""" result = "" @@ -91,15 +150,7 @@ def bytes_to_c_init(ptype: DM.ParamType, endianess: DM.Endianness, data: bytear for i in range(0, entries): val = values[i] - if isinstance(val, float): - result += f"{val:>{type_data.width}.8f}" - elif isinstance(val, bytes): - result += f"0x{val.hex().upper()}" - else: - if type_data.signed: - result += f"{val:>{type_data.width}}" - else: - result += f"0x{val:0{2*type_data.size}X}" + result += ByteConvert.value_to_c(val, type_data) if i < (entries-1): result += ', ' @@ -110,3 +161,40 @@ def bytes_to_c_init(ptype: DM.ParamType, endianess: DM.Endianness, data: bytear result += "\n}" return result + + @staticmethod + def struct_to_c_init(param: DM.Parameter, endianess: DM.Endianness) -> str: + """Get the data for the fields (reverse of fill_strct_from_json()) and parse as a C var init""" + strct = param.datastruct + data_idx = 0 + result = "{" + + for field in strct.fields: + result += "\n " + data = param.value[data_idx: data_idx + field.get_size()] + data_idx += field.get_size() + + if isinstance(field, (DM.Padding, DM.ArrayField)): + type_data = DM.TYPE_DATA[field.type] if isinstance(field, DM.ArrayField) else\ + DM.TYPE_DATA[DM.ParamType.UINT8] + fmt = "<" if endianess == DM.Endianness.LE else ">" + if isinstance(field, DM.Padding): + fmt += type_data.fmt * field.get_size() + else: + fmt += type_data.fmt * field.count + values = struct.unpack(fmt, data) + result += "{" + for i, val in enumerate(values): + result += ByteConvert.value_to_c(val, type_data) + if i < len(values)-1: + result += ', ' + result += "}," + + if isinstance(field, (DM.Field, DM.CrcField)): + fmt = "<" if endianess == DM.Endianness.LE else ">" + fmt += DM.TYPE_DATA[field.type].fmt + value = struct.unpack(fmt, data)[0] + result += ByteConvert.value_to_c(value, DM.TYPE_DATA[field.type]) + "," + + result += "\n}" + return result diff --git a/src/flashcontainer/cfilewriter.py b/src/flashcontainer/cfilewriter.py index ccfb71c..425d5c6 100644 --- a/src/flashcontainer/cfilewriter.py +++ b/src/flashcontainer/cfilewriter.py @@ -36,6 +36,8 @@ import flashcontainer.datamodel as DM from flashcontainer.byteconv import ByteConvert + + class CFileWriter(DM.Walker): """C-Language source and header writer """ @@ -43,21 +45,28 @@ class CFileWriter(DM.Walker): def __init__(self, model: DM.Model, options: Dict[str, any]): super().__init__(model, options) - cfilename = Path.joinpath( + self.cfilename = Path.joinpath( self.options.get("DESTDIR"), self.options.get("BASENAME") + ".c") - hfilename = Path.joinpath( + self.hfilename = Path.joinpath( self.options.get("DESTDIR"), self.options.get("BASENAME") + ".h") - self.cfile = cfilename.open(mode="w") - self.hfile = hfilename.open(mode="w") - def _write_both(self, txt: str) -> None: - """ Write same into h and c file""" + def _write_c(self, txt: str, mode: str = 'a') -> None: + """Append to c file (or overwrite)""" + with open(self.cfilename, mode, encoding='utf-8') as cfile: + cfile.write(txt) - self.hfile.write(txt) - self.cfile.write(txt) + def _write_h(self, txt: str, mode: str = 'a') -> None: + """Append to h file (or overwrite)""" + with open(self.hfilename, mode, encoding='utf-8') as hfile: + hfile.write(txt) + + def _write_both(self, txt: str, mode: str = 'a') -> None: + """ Write same into h and c file""" + self._write_h(txt, mode) + self._write_c(txt, mode) def pre_run(self): print( @@ -67,7 +76,8 @@ def pre_run(self): self._write_both( f"/* AUTOGENERATED by "\ f"{self.options.get('PNAME')} {self.options.get('VERSION')}\n" - f" * cmd: {self.options.get('CMDLINE')}\n") + f" * cmd: {self.options.get('CMDLINE')}\n", + 'w') if self.options.get('STATICOUTPUT') is False: self._write_both( @@ -78,7 +88,7 @@ def pre_run(self): include_guard = f"PARGEN_HEADER_INCLUDED_{self.options.get('BASENAME').upper()}" - self.hfile.write( + self._write_h( f"#ifndef {include_guard}\n#define {include_guard}\n\n" "#ifdef __cplusplus\n" "extern \"C\" {\n" @@ -95,17 +105,14 @@ def pre_run(self): "} pargen_header_type_t;\n\n" ) - self.cfile.write(f'#include "{self.options.get("BASENAME")+".h"}"\n\n') + self._write_c(f'#include "{self.options.get("BASENAME")+".h"}"\n\n') def post_run(self): - self.hfile.write( + self._write_h( "#ifdef __cplusplus\n" "}\n" "#endif\n#endif\n") - self.cfile.close() - self.hfile.close() - def begin_block(self, block: DM.Block) -> None: """Write block comment and header """ @@ -118,13 +125,13 @@ def begin_block(self, block: DM.Block) -> None: for line in block.comment.splitlines(): self._write_both(" * " + line + "\n") - self._write_both(" */\n") + self._write_both(" */\n") if block.header is not None: - self.hfile.write("extern ") + self._write_h("extern ") self._write_both(f"volatile const pargen_header_type_t {self.ctx_block.name}_blkhdr") - self.cfile.write( + self._write_c( " =\n{\n" f" 0x{block.header.block_id:04X},\n" f" 0x{block.header.version.major:04X},\n" @@ -137,7 +144,7 @@ def begin_block(self, block: DM.Block) -> None: self._write_both(";\n\n") def end_block(self, block: DM.Block) -> None: - self._write_both(f"/* END Block {self.ctx_block.name}\n */\n\n") + self._write_both(f"/* END Block {self.ctx_block.name} */\n\n") def begin_parameter(self, param: DM.Parameter) -> None: """Patch parameter bytes into intelhex object""" @@ -155,19 +162,63 @@ def begin_parameter(self, param: DM.Parameter) -> None: self._write_both(" */\n") - self.hfile.write("extern ") - self._write_both( - f"volatile const " - f"{DM.TYPE_DATA[param.ptype].ctype} " - f"{param.name}") - - element_size = ByteConvert.get_type_size(param.ptype) - if (DM.ParamType.UTF8 == param.ptype) or (element_size < len(param.value)): - self._write_both(f"[{int(len(param.value)/ element_size)}]") - - self.cfile.write(" = ") - self.cfile.write(ByteConvert.bytes_to_c_init( - param.ptype, - self.ctx_block.endianess, - param.value)) - self._write_both(";\n\n") + if param.ptype == DM.ParamType.COMPLEX: + self._write_h("extern ") + self._write_both( + f"volatile const " + f"pargen_{param.datastruct.name}_type_t " + f"{param.name}") + + self._write_c(" = ") + self._write_c(ByteConvert.struct_to_c_init(param, self.ctx_block.endianess)) + + self._write_both(";\n\n") + else: + self._write_h("extern ") + self._write_both( + f"volatile const " + f"{DM.TYPE_DATA[param.ptype].ctype} " + f"{param.name}") + + element_size = ByteConvert.get_type_size(param.ptype) + if (DM.ParamType.UTF8 == param.ptype) or (element_size < len(param.value)): + self._write_both(f"[{int(len(param.value)/ element_size)}]") + + self._write_c(" = \n") + self._write_c(ByteConvert.bytes_to_c_init( + param.ptype, + self.ctx_block.endianess, + param.value)) + self._write_both(";\n\n") + + def begin_struct(self, strct: DM.Datastruct) -> None: + # write comment + self._write_h(f"/* Typedef for {strct.name} struct") + if strct.comment is not None: + self._write_h(" *\n") + + for line in strct.comment.splitlines(): + self._write_h(" * " + line + "\n") + self._write_h(" */\n") + + # write typedef + self._write_h( + "#pragma pack(push, 1)\n" + f"typedef struct sruct_pargen_{strct.name}_type\n" + "{\n" + ) + pad_cnt = 0 + for field in strct.fields: + if isinstance(field, DM.Padding): + self._write_h(f" char padding{pad_cnt}[{field.get_size()}];\n") + pad_cnt += 1 + elif isinstance(field, DM.Field): + self._write_h(f" {DM.TYPE_DATA[field.type].ctype} {field.name};\n") + elif isinstance(field, DM.ArrayField): + self._write_h(f" {DM.TYPE_DATA[field.type].ctype} {field.name}[{field.count}];\n") + elif isinstance(field, DM.CrcField): + self._write_h(f" {DM.TYPE_DATA[field.type].ctype} {field.name};\n") + self._write_h( + f"}} pargen_{strct.name}_type_t;\n" + "#pragma pack(pop)\n\n" + ) diff --git a/src/flashcontainer/datamodel.py b/src/flashcontainer/datamodel.py index 5425e1e..cd83e8e 100644 --- a/src/flashcontainer/datamodel.py +++ b/src/flashcontainer/datamodel.py @@ -31,12 +31,14 @@ # from enum import Enum -from typing import Dict, NamedTuple +from typing import Dict, NamedTuple, Optional, List import struct import logging from collections import namedtuple from operator import attrgetter from dataclasses import dataclass +from itertools import chain +from abc import ABC, abstractmethod from flashcontainer.checksum import Crc, CrcConfig @@ -82,10 +84,10 @@ class Endianness(Enum): BE = 2 # big endian (like Motorola 68k) -class Block: # pylint: disable=too-many-instance-attributes +class Block: """Block data container """ - def __init__( # pylint: disable=too-many-arguments + def __init__( self, addr: int, name: str, length: int, endianess: Endianness, fill: int): @@ -234,8 +236,8 @@ def __str__(self): return f"Block({self.name} @ {hex(self.addr)})" -class ParamType(Enum): - """Supported data types""" +class BasicType(Enum): + """Supported basic data types""" UINT32 = 1 UINT8 = 2 UINT16 = 3 @@ -247,21 +249,27 @@ class ParamType(Enum): FLOAT32 = 9 FLOAT64 = 10 UTF8 = 11 + +class SpecialType(Enum): + """Additional types for padding and structs""" GAPFILL = 12 + COMPLEX = 13 +ParamType = Enum('ParamType', [(i.name, i.value) for i in chain(BasicType, SpecialType)]) class Parameter: """Parameter definition data container""" def __init__(self, # pylint: disable=too-many-arguments offset: int, name: str, ptype: ParamType, - value: bytearray, crc: CrcData = None): + value: bytearray, crc: CrcData = None, datastruct: "Datastruct" = None): self.offset = offset self.name = name self.ptype = ptype self.value = value self.comment = None self.crc_cfg = crc + self.datastruct = datastruct @classmethod def as_gap(cls, address: int, length: int, pattern: int): @@ -283,8 +291,11 @@ def set_comment(self, comment: str) -> None: self.comment = comment def __str__(self): - return f"{self.name} @ {hex(self.offset)} = {self.value.hex()} "\ - f"len={len(self.value)}({hex(len(self.value))}) /* {self.comment } */" + if self.datastruct is None: + return f"{self.name} @ {hex(self.offset)} = {self.value.hex()} "\ + f"len={len(self.value)}({hex(len(self.value))}) /* {self.comment } */" + return f"{self.name} @ {hex(self.offset)} of type {self.datastruct} "\ + f"/* {self.comment } */" class Container: @@ -310,12 +321,22 @@ class Model: def __init__(self, name): self.name = name self.container = [] + self.datastructs = [] def add_container(self, container): """Append container to model""" self.container.append(container) + def add_struct(self, strct): + """Append data struct to model""" + self.datastructs.append(strct) + + def get_struct_by_name(self, name: str) -> Optional["Datastruct"]: + """Resturns the struct with the given name if one is present""" + candidates = [s for s in self.datastructs if s.name == name] + return candidates[0] if candidates else None + def __str__(self): return f"Model({self.name} {self.container})" @@ -331,6 +352,108 @@ def validate(self, options: Dict[str, any]) -> bool: return validator.result +@dataclass +class StructElement(ABC): + """Base class for the components in a struct""" + + @abstractmethod + def get_size(self) -> int: + """Returns the size of the element in the struct""" + + +@dataclass +class Field(StructElement): + """Field in a struct""" + name: str + type: BasicType + comment: str = None + + def __post_init__(self): + self.type = ParamType(self.type.value) + + def get_size(self) -> int: + """Returns the size of the basic type and therefore the field""" + return TYPE_DATA[self.type].size + + +@dataclass +class ArrayField(StructElement): + """Field that holds multiple values of the same type""" + name: str + type: BasicType + count: int + comment: str = None + + def __post_init__(self): + self.type = ParamType(self.type.value) + + def get_size(self) -> int: + return TYPE_DATA[self.type].size * self.count + + +@dataclass +class Padding(StructElement): + """Padding element to create gaps between Fields""" + size: int + + def get_size(self) -> int: + return self.size + + +@dataclass +class CrcField(StructElement): + """Crc element to represent CRC in a struct""" + name: str + type: BasicType + cfg: CrcConfig + start: int + end: int + + def __post_init__(self): + self.type = ParamType(self.type.value) + + def get_size(self) -> int: + return TYPE_DATA[self.type].size + + +class Datastruct: + """ Class to hold struct type information """ + + def __init__(self, name: str, filloption: str) -> None: + self.name = name + self.fields = [] + if filloption not in ("parent"): + try: + self.filloption = int(filloption) & 0xFF + except ValueError: + self.filloption = int(filloption, 16) & 0xFF + else: + self.filloption = filloption + self.comment = None + + def set_comment(self, comment: str) -> None: + """Set optional comment""" + self.comment = comment + + def add_field(self, field: StructElement) -> None: + """Add field to the data struct""" + self.fields.append(field) + + def get_size(self) -> int: + """Returns the size of all struct components combined""" + return sum((f.get_size() for f in self.fields)) + + def get_field_names(self, include_crcs: bool = False) -> List[str]: + """Returns a list of all named fields names in the struct""" + if include_crcs: + return [f.name for f in self.fields if isinstance(f, (Field, ArrayField, CrcField))] + return [f.name for f in self.fields if isinstance(f, (Field, ArrayField))] + + def __str__(self) -> str: + """Return a string representation of the struct""" + return f"{self.name} ({self.get_size()} bytes)" + + class Walker: """A data model walker class @@ -368,22 +491,44 @@ def end_block(self, block: Block) -> None: """Run actions when leaving block """ def begin_parameter(self, param: Parameter) -> None: - """ Run begin actions for parameter""" + """Run begin actions for parameter""" def end_parameter(self, param: Parameter) -> None: - """ Run end actions for parameter""" + """Run end actions for parameter""" def begin_gap(self, param: Parameter) -> None: - """ Run begin actions for gaps""" + """Run begin actions for gaps""" def end_gap(self, param: Parameter) -> None: - """ Run end actions for gaps""" + """Run end actions for gaps""" + + def begin_struct(self, strct: Datastruct) -> None: + """Run begin action for structs""" + + def end_struct(self, strct: Datastruct) -> None: + """Run end action for structs""" + + def begin_field(self, field: Field) -> None: + """Run begin action for fields""" + + def end_field(self, field: Field) -> None: + """Run end action for fields""" def run(self): """Walk the data model.""" self.pre_run() + for strct in self.model.datastructs: + logging.debug("begin_struct(%s)", strct) + self.begin_struct(strct) + + for field in strct.fields: + self.begin_field(field) + self.end_field(field) + + self.end_struct(strct) + for container in self.model.container: self.ctx_container = container logging.debug("begin_container(%s)", container) @@ -428,31 +573,46 @@ def __init__(self, model: Model, options: Dict[str, any]): super().__init__(model, options) self.result = True self.last_param = None - self.blocklist = {} - self.paramlist = {} + self.blockdict = {} + self.paramdict = {} + self.structdict = {} + self.fielddict = {} + def begin_container(self, container: Container) -> None: - self.blocklist = {} + self.blockdict = {} + + def begin_struct(self, strct: Datastruct) -> None: + if strct.name in self.structdict: + self.error(f"struct {strct.name} defined more than once in the model") + self.structdict.update({strct.name: strct}) + self.fielddict = {} + + def begin_field(self, field: StructElement) -> None: + if isinstance(field, (Field, ArrayField, CrcField)): + if field.name in self.fielddict: + self.error(f"field {field.name} defined more than once in the same struct") + self.fielddict[field.name] = field def begin_block(self, block: Block): self.last_param = None - self.paramlist = {} + self.paramdict = {} - if block.name in self.blocklist: + if block.name in self.blockdict: self.error( f"block with name {block.name} already exists " - f"@ 0x{self.blocklist[block.name].addr:08X}") + f"@ 0x{self.blockdict[block.name].addr:08X}") else: - self.blocklist[block.name] = block + self.blockdict[block.name] = block def begin_parameter(self, param: Parameter): - if param.name in self.paramlist: + if param.name in self.paramdict: self.error( f"parameter with name {param.name} already exists " - f"@ 0x{self.paramlist[param.name].offset:08X}") + f"@ 0x{self.paramdict[param.name].offset:08X}") else: - self.paramlist[param.name] = param + self.paramdict[param.name] = param block_end = self.ctx_block.addr + self.ctx_block.length @@ -524,6 +684,7 @@ def error(self, msg: str) -> None: # ctype: C-Language type TypeData = namedtuple('TypeData', ['fmt', 'size', 'width', 'signed', 'ctype']) + TYPE_DATA = { ParamType.UINT32: TypeData("L", 4, 10, False, "uint32_t"), ParamType.UINT8: TypeData("B", 1, 4, False, "uint8_t"), @@ -535,5 +696,5 @@ def error(self, msg: str) -> None: ParamType.INT64: TypeData("q", 8, 16, True, "int64_t"), ParamType.FLOAT32: TypeData("f", 4, 12, True, "float"), ParamType.FLOAT64: TypeData("d", 8, 16, True, "double"), - ParamType.UTF8: TypeData("1c", 1, 4, False, "char") + ParamType.UTF8: TypeData("1c", 1, 4, False, "char"), } diff --git a/src/flashcontainer/pargen.py b/src/flashcontainer/pargen.py index ab15f72..0c52d0b 100644 --- a/src/flashcontainer/pargen.py +++ b/src/flashcontainer/pargen.py @@ -114,12 +114,18 @@ def pargen_cli() -> int: parser.add_argument('--version', action='version', version=f'%(prog)s {__version__}') + parser.add_argument('-v', '--verbose', action='store_true', + help="increase logging level") + parser.add_argument( 'file', nargs=1, help='name of the XML parameter definition file (or - for stdin)') args = parser.parse_args() + if args.verbose: + logging.getLogger().setLevel(logging.INFO) + # parse modify option values into string tuple list of (name, value) pairs. modify_values = {} for modval_str in (args.modify or []): diff --git a/src/flashcontainer/pargen_1.1.xsd b/src/flashcontainer/pargen_1.1.xsd new file mode 100644 index 0000000..e830f0f --- /dev/null +++ b/src/flashcontainer/pargen_1.1.xsd @@ -0,0 +1,316 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/flashcontainer/pyhexdumpwriter.py b/src/flashcontainer/pyhexdumpwriter.py index 60824ba..41369c4 100644 --- a/src/flashcontainer/pyhexdumpwriter.py +++ b/src/flashcontainer/pyhexdumpwriter.py @@ -135,6 +135,7 @@ def __init__(self, model: DM.Model, options: Dict[str, any]): super().__init__(model, options) self.dmpfile = None self.elements = [] + self.definded_structs = [] def pre_run(self) -> None: filename = Path.joinpath( @@ -150,9 +151,7 @@ def begin_block(self, block: DM.Block) -> None: if block.header is not None: - subtype = "be" - if self.ctx_block.endianess == DM.Endianness.LE: - subtype = "le" + subtype = "le" if self.ctx_block.endianess == DM.Endianness.LE else "be" element = { "name": f"{self.ctx_block.name}_blkhdr", @@ -165,17 +164,52 @@ def begin_block(self, block: DM.Block) -> None: def begin_parameter(self, param: DM.Parameter) -> None: """Add element to data array """ - - element = { - "name": f"{param.name}", - "addr": f"{hex(param.offset)}", - "dataType": self._TYPE_MAPPING[param.ptype] - [0 if self.ctx_block.endianess == DM.Endianness.LE else 1], - "count": len(param.value) // ByteConvert.get_type_size(param.ptype) - } + if param.ptype != DM.ParamType.COMPLEX: + element = { + "name": f"{param.name}", + "addr": f"{hex(param.offset)}", + "dataType": self._TYPE_MAPPING[param.ptype] + [0 if self.ctx_block.endianess == DM.Endianness.LE else 1], + "count": len(param.value) // ByteConvert.get_type_size(param.ptype) + } + else: + element = { + "name": f"{param.name}", + "addr": f"{hex(param.offset)}", + "dataType": f"pargen_{param.datastruct.name}_" + \ + f"{'le' if self.ctx_block.endianess == DM.Endianness.LE else 'be'}_t", + "count": 1 + } self.elements.append(element) + def begin_struct(self, strct: DM.Datastruct) -> None: + """Add BE and LE versions of the struct to the defined structures""" + structure_dicts = ({ "name": f"pargen_{strct.name}_le_t", "elements": []}, + { "name": f"pargen_{strct.name}_be_t", "elements": []}) + + for i, _ in enumerate(("le", "be")): + offset = 0 + offset_needed = False + for field in strct.fields: + if isinstance(field, (DM.Field, DM.ArrayField, DM.CrcField)): + element = { + "name": f"{field.name}", + "dataType": self._TYPE_MAPPING[field.type][i], + "count": field.count if isinstance(field, DM.ArrayField) else 1 + } + if offset_needed: + element.update({"offset": offset}) + offset_needed = False + offset += field.get_size() + structure_dicts[i]["elements"].append(element) + else: + # padding requires no entry but correct offset for next element + offset += field.get_size() + offset_needed = True + + self.definded_structs.extend(structure_dicts) + def post_run(self): """Close output file""" @@ -191,7 +225,7 @@ def post_run(self): record = { "_comment_": comment, - "structures": _HEADER_STRUCTURES, + "structures": _HEADER_STRUCTURES + self.definded_structs, "elements": self.elements } diff --git a/src/flashcontainer/xmlparser.py b/src/flashcontainer/xmlparser.py index 2d13241..86892b5 100644 --- a/src/flashcontainer/xmlparser.py +++ b/src/flashcontainer/xmlparser.py @@ -32,7 +32,8 @@ import logging import pathlib import os -from typing import Dict +import re +from typing import Dict, Optional, Tuple import lxml.etree as ET @@ -40,29 +41,47 @@ from flashcontainer.byteconv import ByteConvert from flashcontainer.checksum import CrcConfig -schema_file = os.path.join(pathlib.Path(__file__).parent.resolve(), "pargen_1.0.xsd") -NS = 'http://nhjschulz.github.io/1.0/pargen' + class XmlParser: """XML Parser to generate a datamodel from an XML file""" + def __init__(self) -> None: + self.pd_ns = 'http://nhjschulz.github.io/1.0/pargen' + self.model = None + @classmethod - def from_file(cls, file: str, values: Dict[str, str] = None) -> DM.Model: + def from_file(cls, file: str, values: Dict[str, str] = None) -> Optional[DM.Model]: """Parser entry point returning model instance""" - return cls.parse(file, values) + parser = XmlParser() + return parser.parse(file, values) - @staticmethod - def parse(file: str, values: Dict[str, str]) -> DM.Model: + def parse(self, file: str, values: Dict[str, str]) -> Optional[DM.Model]: """ Parse given XML file into data model. """ model = None + + namespaceregex = re.compile(r"http://nhjschulz.github.io/(\d+).(\d+)/pargen") try: + preview = ET.parse(file, ET.XMLParser(remove_comments=True)) + try: + searchresult = namespaceregex.search(preview.getroot().nsmap['pd']) + major = searchresult.group(1) + minor = searchresult.group(2) + + schema_filename = f"pargen_{major}.{minor}.xsd" + schema_file = os.path.join(pathlib.Path(__file__).parent.resolve(), schema_filename) + self.pd_ns = f'http://nhjschulz.github.io/{major}.{minor}/pargen' + + except KeyError as exc: + raise ET.DocumentInvalid("No pd namespace configured on root element.") from exc + logging.info("Loading parameter definitions from %s.", file) schema = ET.XMLSchema(ET.parse(schema_file)) xml_doc = ET.parse(file, ET.XMLParser(remove_comments=True)) schema.assertValid(xml_doc) - XmlParser._update_values(xml_doc.getroot(), values) - model = XmlParser._build_model(xml_doc.getroot(), file) + self._update_values(xml_doc.getroot(), values) + model = self._build_model(xml_doc.getroot(), file) except ET.DocumentInvalid as err: logging.critical("xml validation failed:\n%s", str(err.error_log)) # pylint: disable=no-member @@ -71,15 +90,14 @@ def parse(file: str, values: Dict[str, str]) -> DM.Model: return model - @staticmethod - def _update_values(root, values: Dict[str, str]): + def _update_values(self, root, values: Dict[str, str]): """Update parameter values based on modifier list.""" if values is not None: for param_name, param_value in list(values.items()): xpath = ET.XPath( f"//pd:param[@name='{param_name}']/pd:value", - namespaces={'pd': NS} + namespaces={'pd': self.pd_ns} ) hits = xpath(root) if hits: @@ -90,8 +108,7 @@ def _update_values(root, values: Dict[str, str]): "Unable to modify parameter '%s': name is not defined.", param_name) - @staticmethod - def _get_optional(element: ET.Element, attr: str, default: any) -> str: + def _get_optional(self, element: ET.Element, attr: str, default: any) -> str: """Get optional attribute value.""" if element is None: @@ -103,8 +120,7 @@ def _get_optional(element: ET.Element, attr: str, default: any) -> str: return val - @staticmethod - def _parse_bool(val_str: str) -> bool: + def _parse_bool(self, val_str: str) -> bool: """ Parse input as boolean """ result = False @@ -115,8 +131,7 @@ def _parse_bool(val_str: str) -> bool: return result - @staticmethod - def _parse_int(val_str: str) -> int: + def _parse_int(self, val_str: str) -> int: """ Parse int as decimal or hex.""" try: @@ -124,30 +139,77 @@ def _parse_int(val_str: str) -> int: except ValueError: return int(val_str, base=16) - @staticmethod - def get_alignment(element: ET.Element) -> int: + def get_alignment(self, element: ET.Element) -> int: """Parse alignment argument.""" val_str = element.get("align") - return 1 if (val_str is None) else XmlParser._parse_int(val_str) + return 1 if (val_str is None) else self._parse_int(val_str) - @staticmethod - def get_endianess(element: ET.Element) -> DM.Endianness: + def get_endianess(self, element: ET.Element) -> DM.Endianness: """Parse alignment argument.""" - val_str = XmlParser._get_optional(element, "endianness", "LE") + val_str = self._get_optional(element, "endianness", "LE") return DM.Endianness.LE if val_str == "LE" else DM.Endianness.BE - @staticmethod - def get_fill(element: ET.Element) -> int: + def get_fill(self, element: ET.Element) -> int: """Parse fill argument.""" val_str = element.get("fill") - return 0x00 if (val_str is None) else XmlParser._parse_int(val_str) + return 0x00 if (val_str is None) else self._parse_int(val_str) + + def _parse_crc_config(self, param: ET.Element) -> Tuple[int, int, int, bool, bool, bool]: + """Parse the configuration of a crc parameter or field""" + cfg_element = param.find(f"{{{self.pd_ns}}}config") + + defaults = CrcConfig() # get defaults + + # parse cfg element + width = DM.TYPE_DATA[DM.ParamType[param.get("type").upper()]].size * 8 + poly = self._parse_int( + self._get_optional(cfg_element, 'polynomial', defaults.poly)) + init = self._parse_int( + self._get_optional(cfg_element, 'init', defaults.init)) + revin = self._parse_bool( + self._get_optional(cfg_element, 'rev_in', defaults.revin)) + revout = self._parse_bool( + self._get_optional(cfg_element, 'rev_out', defaults.revout)) + xor = self._parse_bool( + self._get_optional(cfg_element, 'final_xor', defaults.xor)) + return (poly, width, init, revin, revout, xor) + + def _parse_crc_memory(self, param: ET.Element, + offset: int, + block: Optional[DM.Block] = None) -> Tuple[int, int, int, bool]: + """Parse the memory tag of a crc parameter or field""" + mem_element = param.find(f"{{{self.pd_ns}}}memory") + if block is not None: + start = self.calc_addr( + block.addr, + offset, + self._get_optional(mem_element, "from", "0"), + 1) + end = self.calc_addr( + block.addr, + offset, + self._get_optional(mem_element, "to", "."), + 1) + else: + start = self.calc_addr(0x0, offset, self._get_optional(mem_element, "from", "0"), 1) + end = self.calc_addr(0x0, offset, self._get_optional(mem_element, "to", "."), 1) + + defaults = CrcConfig() # get defaults + access = self._parse_int( + self._get_optional(mem_element, 'access', defaults.access)) + swap = self._parse_bool(self._get_optional(mem_element, 'swap', defaults.swap)) + + # special case for CRC: "." means end before current address, not at it. + if "." == self._get_optional(mem_element, "to", "."): + end = end - 1 + + return (start, end, access, swap) - @staticmethod - def _parse_crc_config(param: ET.Element, block: DM.Block, offset: int) -> DM.CrcConfig: - """Parse a crc element. + def _parse_crc_param(self, param: ET.Element, block: DM.Block, offset: int) -> DM.CrcConfig: + """Parse a crc parameter. Args: param (ET.Element): The XML parameter element to read @@ -158,43 +220,8 @@ def _parse_crc_config(param: ET.Element, block: DM.Block, offset: int) -> DM.Crc A CrcConfig from the data model """ - mem_element = param.find(f"{{{NS}}}memory") - cfg_element = param.find(f"{{{NS}}}config") - - defaults = CrcConfig() # get defaults - - # parse cfg element - width = DM.TYPE_DATA[DM.ParamType[param.get("type").upper()]].size * 8 - poly = XmlParser._parse_int( - XmlParser._get_optional(cfg_element, 'polynomial', defaults.poly)) - init = XmlParser._parse_int( - XmlParser._get_optional(cfg_element, 'init', defaults.init)) - revin = XmlParser._parse_bool( - XmlParser._get_optional(cfg_element, 'rev_in', defaults.revin)) - revout = XmlParser._parse_bool( - XmlParser._get_optional(cfg_element, 'rev_out', defaults.revout)) - xor = XmlParser._parse_bool( - XmlParser._get_optional(cfg_element, 'final_xor', defaults.xor)) - - # parse memory element - start = XmlParser.calc_addr( - block.addr, - offset, - XmlParser._get_optional(mem_element, "from", "0"), - 1) - end = XmlParser.calc_addr( - block.addr, - offset, - XmlParser._get_optional(mem_element, "to", "."), - 1) - - access = XmlParser._parse_int( - XmlParser._get_optional(mem_element, 'access', defaults.access)) - swap = XmlParser._parse_bool(XmlParser._get_optional(mem_element, 'swap', defaults.swap)) - - # special case for CRC: "." means end before current address, not at it. - if "." == XmlParser._get_optional(mem_element, "to", "."): - end = end - 1 + poly, width, init, revin, revout, xor = self._parse_crc_config(param) + start, end, access, swap = self._parse_crc_memory(param, offset, block=block) return DM.CrcData( crc_cfg=CrcConfig( @@ -204,39 +231,48 @@ def _parse_crc_config(param: ET.Element, block: DM.Block, offset: int) -> DM.Crc start=start, end=end) - @staticmethod - def _build_parameters(block: DM.Block, element) -> None: - data_element = element.find(f"{{{NS}}}data") + def _build_parameters(self, block: DM.Block, element: ET.Element) -> None: running_addr = block.addr if block.header is not None: running_addr += len(block.get_header_bytes()) - for parameter_element in data_element: + for parameter_element in element.find(f"{{{self.pd_ns}}}data"): - offset = XmlParser.calc_addr( + offset = self.calc_addr( block.addr, running_addr, parameter_element.get("offset"), - XmlParser.get_alignment(parameter_element)) - - name = parameter_element.get("name") + self.get_alignment(parameter_element)) ptype = DM.ParamType[parameter_element.get("type").upper()] crc_cfg = None val_text = None - if f"{{{NS}}}crc" == parameter_element.tag: - crc_cfg = XmlParser._parse_crc_config(parameter_element, block, offset) + if f"{{{self.pd_ns}}}crc" == parameter_element.tag: + crc_cfg = self._parse_crc_param(parameter_element, block, offset) val_text = '0x0' # crc bits get calculated at end of block logging.info(" got CRC data: %s", crc_cfg) else: - value_element = parameter_element.find(f"{{{NS}}}value") + value_element = parameter_element.find(f"{{{self.pd_ns}}}value") val_text = value_element.text - data = ByteConvert.json_to_bytes(ptype, block.endianess, val_text) - - parameter = DM.Parameter(offset, name, ptype, data, crc_cfg) + if ptype == DM.ParamType.COMPLEX: + # get the corresponding struct object + sname = parameter_element.get("struct") + if sname is None: + logging.critical("Parsing complex parameter with no struct attribute") + raise ET.DocumentInvalid("Parsing complex parameter with no struct attribute") + if self.model.datastructs is None or sname not in [s.name for s in self.model.datastructs]: + logging.critical("Parsing complex parameter with undefined struct name") + raise ET.DocumentInvalid("Parsing complex parameter with undefined struct name") + strct = [s for s in self.model.datastructs if s.name == sname][0] + + data = ByteConvert.fill_struct_from_json(strct, val_text, block.endianess, block.fill) + parameter = DM.Parameter(offset, parameter_element.get("name"), ptype, data, crc_cfg, datastruct=strct) + else: + data = ByteConvert.json_to_bytes(ptype, block.endianess, val_text) + parameter = DM.Parameter(offset, parameter_element.get("name"), ptype, data, crc_cfg) - comment = parameter_element.find(f"{{{NS}}}comment") + comment = parameter_element.find(f"{{{self.pd_ns}}}comment") if comment is not None: parameter.set_comment(comment.text) @@ -244,25 +280,32 @@ def _build_parameters(block: DM.Block, element) -> None: logging.info(" Adding %s", parameter) running_addr = offset + len(data) - @staticmethod - def _build_model(root: ET.Element, filename: str) -> DM.Model: - model = DM.Model(filename) + def _build_model(self, root: ET.Element, filename: str) -> DM.Model: + self.model = DM.Model(filename) - # iterate over container list + # iterate over structs and containers for element in root: - address = XmlParser._parse_int(element.get("at")) - name = element.get("name") + if element.tag == f"{{{self.pd_ns}}}container": + address = self._parse_int(element.get("at")) + name = element.get("name") - container = DM.Container(name, address) - logging.info("Loading container definition for %s", name) - XmlParser._build_blocks(container, element) + container = DM.Container(name, address) + logging.info("Loading container definition for %s", name) + self._build_blocks(container, element) - model.add_container(container) + self.model.add_container(container) + elif element.tag == f"{{{self.pd_ns}}}struct": + name = element.get("name") + filloption = element.get("fill") + logging.info("Found struct with name %s and filloption %s!", name, filloption) - return model + strct = DM.Datastruct(name, filloption) + self._build_struct(strct, element) + self.model.add_struct(strct) - @staticmethod - def calc_addr(base_addr: int, running_addr: int, offset_str: str, alignment: int) -> int: + return self.model + + def calc_addr(self, base_addr: int, running_addr: int, offset_str: str, alignment: int) -> int: """Calculate address from address input or '.' Args: @@ -279,7 +322,7 @@ def calc_addr(base_addr: int, running_addr: int, offset_str: str, alignment: int result_addr = running_addr else: - result_addr = base_addr + XmlParser._parse_int(offset_str) + result_addr = base_addr + self._parse_int(offset_str) if 1 < alignment: mod = result_addr % alignment @@ -288,45 +331,71 @@ def calc_addr(base_addr: int, running_addr: int, offset_str: str, alignment: int return result_addr - @staticmethod - def _build_blocks(container: DM.Container, xml_element: ET.Element) -> None: + def _build_blocks(self, container: DM.Container, xml_element: ET.Element) -> None: """ Load block list for given container """ running_addr = container.addr - blocks_element = xml_element.find(f"{{{NS}}}blocks") - for element in blocks_element: - align = XmlParser.get_alignment(element) - block_addr = XmlParser.calc_addr( - container.addr, running_addr, element.get("offset"), align) + for element in xml_element.find(f"{{{self.pd_ns}}}blocks"): + block_addr = self.calc_addr( + container.addr, running_addr, element.get("offset"), self.get_alignment(element)) name = element.get("name") - length = XmlParser._parse_int(element.get("length")) + length = self._parse_int(element.get("length")) - endianess = XmlParser.get_endianess(element) - fill = XmlParser.get_fill(element) + endianess = self.get_endianess(element) + fill = self.get_fill(element) block = DM.Block(block_addr, name, length, endianess, fill) - comment = element.find(f"{{{NS}}}comment") + comment = element.find(f"{{{self.pd_ns}}}comment") if comment is not None: block.set_comment(comment.text) logging.info(" Loading block definition %s", block) # optional block header - header_element = element.find(f"{{{NS}}}header") + header_element = element.find(f"{{{self.pd_ns}}}header") if header_element is not None: - block_id = XmlParser._parse_int(header_element.get("id")) + block_id = self._parse_int(header_element.get("id")) version = DM.Version( - XmlParser._parse_int(header_element.get("major")), - XmlParser._parse_int(header_element.get("minor")), - XmlParser._parse_int(header_element.get("version")) + self._parse_int(header_element.get("major")), + self._parse_int(header_element.get("minor")), + self._parse_int(header_element.get("version")) ) block.set_header(DM.BlockHeader(block_id, version)) - XmlParser._build_parameters(block, element) + self._build_parameters(block, element) block.fill_gaps() block.update_crcs() container.add_block(block) running_addr += length + + def _build_struct(self, strct: DM.Datastruct, xml_element: ET.Element) -> None: + """ Parse the fields of a data structure""" + strct_comment = xml_element.find(f"{{{self.pd_ns}}}comment") + if strct_comment is not None: + strct.set_comment(strct_comment.text) + + for element in xml_element.find(f"{{{self.pd_ns}}}fields"): + if element.tag in (f"{{{self.pd_ns}}}field", + f"{{{self.pd_ns}}}arrayfield", + f"{{{self.pd_ns}}}crc"): + name = element.get("name") + btype = DM.BasicType[element.get("type").upper()] + comment = None + field_comment = element.find(f"{{{self.pd_ns}}}comment") + if field_comment is not None: + comment = field_comment.text + if element.tag == f"{{{self.pd_ns}}}arrayfield": + count = self._parse_int(element.get("size")) + field = DM.ArrayField(name, btype, count, comment=comment) + elif element.tag == f"{{{self.pd_ns}}}field": + field = DM.Field(name, btype, comment=comment) + else: # crcfield + cfargs = self._parse_crc_config(element) + start, end, access, swap = self._parse_crc_memory(element, strct.get_size()) + field = DM.CrcField(name, btype, CrcConfig(*cfargs, access, swap), start, end) + strct.add_field(field) + elif element.tag == f"{{{self.pd_ns}}}padding": + strct.add_field(DM.Padding(self._parse_int(element.get("size")))) diff --git a/tests/collateral/garbage/invalidexample_jsoninp.xml b/tests/collateral/garbage/invalidexample_jsoninp.xml new file mode 100644 index 0000000..a3e2592 --- /dev/null +++ b/tests/collateral/garbage/invalidexample_jsoninp.xml @@ -0,0 +1,59 @@ + + + + + + + This block is used for non-safety related parameters only. + + + + see https://www.boost.org/doc/libs/1_79_0/libs/crc/test/crc_test2.cpp + [0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39] + + + expected: CBF43926 + + + + Integer array example + [-4, -3, -2, -1, 0, 1, 2, 3, 4] + + + block crc32 (IEEE802.3) + + + + + + + + This block is used for any-safety related parameters. + + + + [1.0,-2.1,3.2,4.5,5.4,6.5] + + + "Hello world!" + + + {"Hey": 0x1604} + + + 0.160469 + + + -3.141 + + + block crc32 (IEEE802.3) + + + + + + + diff --git a/tests/collateral/garbage/invalidstructexample_arraycnt.xml b/tests/collateral/garbage/invalidstructexample_arraycnt.xml new file mode 100644 index 0000000..ec138ee --- /dev/null +++ b/tests/collateral/garbage/invalidstructexample_arraycnt.xml @@ -0,0 +1,90 @@ + + + + This struct is super simple + + + + + + + This struct will feature padding and arrays + + + + + I will need so much space + + + + + + + + + This block is used for non-safety related parameters only. + + + + see https://www.boost.org/doc/libs/1_79_0/libs/crc/test/crc_test2.cpp + [0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39] + + + expected: CBF43926 + + + + Integer array example + [-4, -3, -2, -1, 0, 1, 2, 3, 4] + + + block crc32 (IEEE802.3) + + + + + + + + This block is used for any-safety related parameters. + + + + [1.0,-2.1,3.2,4.5,5.4,6.5] + + + "Hello world!" + + + 0x1604 + + + 0.160469 + + + -3.141 + + + block crc32 (IEEE802.3) + + + + + + + This block contains parameters that use structs + + + + { "int1": 3, "int2": 5} + + + {"int1": 1, "int2": 9999999, "intarray": [1, 4, 16, 64, 128]} + + + + + + diff --git a/tests/collateral/garbage/invalidstructexample_arrayinp.xml b/tests/collateral/garbage/invalidstructexample_arrayinp.xml new file mode 100644 index 0000000..bd7504d --- /dev/null +++ b/tests/collateral/garbage/invalidstructexample_arrayinp.xml @@ -0,0 +1,90 @@ + + + + This struct is super simple + + + + + + + This struct will feature padding and arrays + + + + + I will need so much space + + + + + + + + + This block is used for non-safety related parameters only. + + + + see https://www.boost.org/doc/libs/1_79_0/libs/crc/test/crc_test2.cpp + [0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39] + + + expected: CBF43926 + + + + Integer array example + [-4, -3, -2, -1, 0, 1, 2, 3, 4] + + + block crc32 (IEEE802.3) + + + + + + + + This block is used for any-safety related parameters. + + + + [1.0,-2.1,3.2,4.5,5.4,6.5] + + + "Hello world!" + + + 0x1604 + + + 0.160469 + + + -3.141 + + + block crc32 (IEEE802.3) + + + + + + + This block contains parameters that use structs + + + + { "int1": 3, "int2": 5} + + + {"int1": 1, "int2": 9999999, "intarray": 5} + + + + + + diff --git a/tests/collateral/garbage/invalidstructexample_fieldname.xml b/tests/collateral/garbage/invalidstructexample_fieldname.xml new file mode 100644 index 0000000..0b842dd --- /dev/null +++ b/tests/collateral/garbage/invalidstructexample_fieldname.xml @@ -0,0 +1,90 @@ + + + + This struct is super simple + + + + + + + This struct will feature padding and arrays + + + + + I will need so much space + + + + + + + + + This block is used for non-safety related parameters only. + + + + see https://www.boost.org/doc/libs/1_79_0/libs/crc/test/crc_test2.cpp + [0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39] + + + expected: CBF43926 + + + + Integer array example + [-4, -3, -2, -1, 0, 1, 2, 3, 4] + + + block crc32 (IEEE802.3) + + + + + + + + This block is used for any-safety related parameters. + + + + [1.0,-2.1,3.2,4.5,5.4,6.5] + + + "Hello world!" + + + 0x1604 + + + 0.160469 + + + -3.141 + + + block crc32 (IEEE802.3) + + + + + + + This block contains parameters that use structs + + + + { "int1": 3, "int4": 5} + + + {"int1": 1, "int2": 9999999, "intarray": [1, 4, 16, 64]} + + + + + + diff --git a/tests/collateral/garbage/invalidstructexample_nojson.xml b/tests/collateral/garbage/invalidstructexample_nojson.xml new file mode 100644 index 0000000..90caf9e --- /dev/null +++ b/tests/collateral/garbage/invalidstructexample_nojson.xml @@ -0,0 +1,90 @@ + + + + This struct is super simple + + + + + + + This struct will feature padding and arrays + + + + + I will need so much space + + + + + + + + + This block is used for non-safety related parameters only. + + + + see https://www.boost.org/doc/libs/1_79_0/libs/crc/test/crc_test2.cpp + [0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39] + + + expected: CBF43926 + + + + Integer array example + [-4, -3, -2, -1, 0, 1, 2, 3, 4] + + + block crc32 (IEEE802.3) + + + + + + + + This block is used for any-safety related parameters. + + + + [1.0,-2.1,3.2,4.5,5.4,6.5] + + + "Hello world!" + + + 0x1604 + + + 0.160469 + + + -3.141 + + + block crc32 (IEEE802.3) + + + + + + + This block contains parameters that use structs + + + + [3, 5] + + + {"int1": 1, "int2": 9999999, "intarray": [1, 4, 16, 64]} + + + + + + diff --git a/tests/collateral/garbage/invalidstructexample_noname.xml b/tests/collateral/garbage/invalidstructexample_noname.xml new file mode 100644 index 0000000..ce56a7b --- /dev/null +++ b/tests/collateral/garbage/invalidstructexample_noname.xml @@ -0,0 +1,90 @@ + + + + This struct is super simple + + + + + + + This struct will feature padding and arrays + + + + + I will need so much space + + + + + + + + + This block is used for non-safety related parameters only. + + + + see https://www.boost.org/doc/libs/1_79_0/libs/crc/test/crc_test2.cpp + [0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39] + + + expected: CBF43926 + + + + Integer array example + [-4, -3, -2, -1, 0, 1, 2, 3, 4] + + + block crc32 (IEEE802.3) + + + + + + + + This block is used for any-safety related parameters. + + + + [1.0,-2.1,3.2,4.5,5.4,6.5] + + + "Hello world!" + + + 0x1604 + + + 0.160469 + + + -3.141 + + + block crc32 (IEEE802.3) + + + + + + + This block contains parameters that use structs + + + + { "int1": 3, "int2": 5} + + + {"int1": 1, "int2": 9999999, "intarray": [1, 4, 16, 64]} + + + + + + diff --git a/tests/collateral/garbage/invalidstructexample_undefined.xml b/tests/collateral/garbage/invalidstructexample_undefined.xml new file mode 100644 index 0000000..e5cde9e --- /dev/null +++ b/tests/collateral/garbage/invalidstructexample_undefined.xml @@ -0,0 +1,90 @@ + + + + This struct is super simple + + + + + + + This struct will feature padding and arrays + + + + + I will need so much space + + + + + + + + + This block is used for non-safety related parameters only. + + + + see https://www.boost.org/doc/libs/1_79_0/libs/crc/test/crc_test2.cpp + [0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39] + + + expected: CBF43926 + + + + Integer array example + [-4, -3, -2, -1, 0, 1, 2, 3, 4] + + + block crc32 (IEEE802.3) + + + + + + + + This block is used for any-safety related parameters. + + + + [1.0,-2.1,3.2,4.5,5.4,6.5] + + + "Hello world!" + + + 0x1604 + + + 0.160469 + + + -3.141 + + + block crc32 (IEEE802.3) + + + + + + + This block contains parameters that use structs + + + + { "int1": 3, "int2": 5} + + + {"int1": 1, "int2": 9999999, "intarray": [1, 4, 16, 64]} + + + + + + diff --git a/tests/collateral/pyhex_ref.json b/tests/collateral/pyhex_ref.json new file mode 100644 index 0000000..81f3e5c --- /dev/null +++ b/tests/collateral/pyhex_ref.json @@ -0,0 +1,257 @@ +{ + "_comment_": [ + "Configuration file for pyHexDump, see https://github.com/BlueAndi/pyHexDump", + "GENERATED by pargen 0.5.0 ", + "cmd: G://Repos/flashcontainer/src/flashcontainer/pargen.py -v --ihex --pyhexdump --destdir ./gen structexample.xml", + "date: 2023-08-29 08:39:31.162476", + "Buildkey: 14875b7f-7b11-426c-8b60-a487e74c391b" + ], + "structures": [ + { + "name": "pargen_header_le_t", + "elements": [ + { + "name": "id", + "dataType": "uint16le", + "count": 1 + }, + { + "name": "major", + "dataType": "uint16le", + "count": 1 + }, + { + "name": "minor", + "dataType": "uint16le", + "count": 1 + }, + { + "name": "dataver", + "dataType": "uint16le", + "count": 1 + }, + { + "name": "reserved", + "dataType": "uint32le", + "count": 1 + }, + { + "name": "length", + "dataType": "uint32le", + "count": 1 + } + ] + }, + { + "name": "pargen_header_be_t", + "elements": [ + { + "name": "id", + "dataType": "uint16be", + "count": 1 + }, + { + "name": "major", + "dataType": "uint16be", + "count": 1 + }, + { + "name": "minor", + "dataType": "uint16be", + "count": 1 + }, + { + "name": "dataver", + "dataType": "uint16be", + "count": 1 + }, + { + "name": "reserved", + "dataType": "uint32be", + "count": 1 + }, + { + "name": "length", + "dataType": "uint32be", + "count": 1 + } + ] + }, + { + "name": "pargen_SimpleS_le_t", + "elements": [ + { + "name": "int1", + "dataType": "uint8", + "count": 1 + }, + { + "name": "int2", + "dataType": "uint8", + "count": 1 + }, + { + "name": "smallcrc", + "dataType": "uint8", + "count": 1 + } + ] + }, + { + "name": "pargen_SimpleS_be_t", + "elements": [ + { + "name": "int1", + "dataType": "uint8", + "count": 1 + }, + { + "name": "int2", + "dataType": "uint8", + "count": 1 + }, + { + "name": "smallcrc", + "dataType": "uint8", + "count": 1 + } + ] + }, + { + "name": "pargen_ComplexS_le_t", + "elements": [ + { + "name": "int1", + "dataType": "uint8", + "count": 1 + }, + { + "name": "int2", + "dataType": "uint64le", + "count": 1, + "offset": 5 + }, + { + "name": "intarray", + "dataType": "uint16le", + "count": 4, + "offset": 15 + } + ] + }, + { + "name": "pargen_ComplexS_be_t", + "elements": [ + { + "name": "int1", + "dataType": "uint8", + "count": 1 + }, + { + "name": "int2", + "dataType": "uint64be", + "count": 1, + "offset": 5 + }, + { + "name": "intarray", + "dataType": "uint16be", + "count": 4, + "offset": 15 + } + ] + } + ], + "elements": [ + { + "name": "paraBlkQm_blkhdr", + "addr": "0x80000000", + "dataType": "pargen_header_le_t", + "count": 1 + }, + { + "name": "crcTestInput", + "addr": "0x80000010", + "dataType": "uint8", + "count": 9 + }, + { + "name": "crcTestResult", + "addr": "0x80000019", + "dataType": "uint32le", + "count": 1 + }, + { + "name": "tag", + "addr": "0x80000020", + "dataType": "int16le", + "count": 9 + }, + { + "name": "crc", + "addr": "0x800000fc", + "dataType": "uint32le", + "count": 1 + }, + { + "name": "paraBlkSafety_blkhdr", + "addr": "0x80000200", + "dataType": "pargen_header_le_t", + "count": 1 + }, + { + "name": "array", + "addr": "0x80000210", + "dataType": "float32le", + "count": 6 + }, + { + "name": "hello", + "addr": "0x80000300", + "dataType": "utf8", + "count": 13 + }, + { + "name": "val", + "addr": "0x8000030e", + "dataType": "uint16le", + "count": 1 + }, + { + "name": "birthday", + "addr": "0x80000310", + "dataType": "float32le", + "count": 1 + }, + { + "name": "negativePi", + "addr": "0x80000314", + "dataType": "float32le", + "count": 1 + }, + { + "name": "crc", + "addr": "0x800003fc", + "dataType": "uint32le", + "count": 1 + }, + { + "name": "structTestBlock_blkhdr", + "addr": "0x80000400", + "dataType": "pargen_header_le_t", + "count": 1 + }, + { + "name": "simpy", + "addr": "0x80000410", + "dataType": "pargen_SimpleS_le_t", + "count": 1 + }, + { + "name": "biggy", + "addr": "0x80000413", + "dataType": "pargen_ComplexS_le_t", + "count": 1 + } + ] +} \ No newline at end of file diff --git a/tests/example/example.xml b/tests/example/example.xml index 20db82b..f7379de 100644 --- a/tests/example/example.xml +++ b/tests/example/example.xml @@ -16,7 +16,7 @@ expected: CBF43926 - + Integer array example [-4, -3, -2, -1, 0, 1, 2, 3, 4] diff --git a/tests/example/structexample.xml b/tests/example/structexample.xml new file mode 100644 index 0000000..6bff230 --- /dev/null +++ b/tests/example/structexample.xml @@ -0,0 +1,94 @@ + + + + This struct is super simple + + + + + + + + + + + This struct will feature padding and arrays + + + + + I will need so much space + + + + + + + + + This block is used for non-safety related parameters only. + + + + see https://www.boost.org/doc/libs/1_79_0/libs/crc/test/crc_test2.cpp + [0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39] + + + expected: CBF43926 + + + + Integer array example + [-4, -3, -2, -1, 0, 1, 2, 3, 4] + + + block crc32 (IEEE802.3) + + + + + + + + This block is used for any-safety related parameters. + + + + [1.0,-2.1,3.2,4.5,5.4,6.5] + + + "Hello world!" + + + 0x1604 + + + 0.160469 + + + -3.141 + + + block crc32 (IEEE802.3) + + + + + + + This block contains parameters that use structs + + + + { "int1": 3, "int2": 5} + + + {"int1": 1, "int2": 9999999, "intarray": [1, 4, 16, 64]} + + + + + + diff --git a/tests/test_datamodel.py b/tests/test_datamodel.py index e56e653..e7114a3 100644 --- a/tests/test_datamodel.py +++ b/tests/test_datamodel.py @@ -76,3 +76,12 @@ def test_model_str(): "reverse in:True, reverse out:True, final xor:True, access:8, swap:False" assert DM.Version(2,3,5).__str__() == "2.3.5" assert DM.Parameter(0x2, "_2", DM.ParamType.UINT8, b'\x22', None).__str__() == "_2 @ 0x2 = 22 len=1(0x1) /* None */" + + teststrct = DM.Datastruct("testname", "parent") + assert str(DM.Parameter(0x2, "structpar", DM.ParamType.COMPLEX, b'\xFF', datastruct=teststrct)) == \ + "structpar @ 0x2 of type testname (0 bytes) /* None */" + assert str(teststrct) == "testname (0 bytes)" + teststrct.add_field(DM.Field("fieldy", DM.BasicType.INT16)) + teststrct.add_field(DM.Padding(4)) + teststrct.add_field(DM.ArrayField("longus", DM.BasicType.INT16, 2)) + assert str(teststrct) == "testname (10 bytes)" diff --git a/tests/test_model_validate.py b/tests/test_model_validate.py index b045d1d..94f3884 100644 --- a/tests/test_model_validate.py +++ b/tests/test_model_validate.py @@ -12,12 +12,21 @@ def example_model(): return XP.XmlParser.from_file(example_xml) +@pytest.fixture +def structexample_model(): + """Load example including structs""" + sandbox_dir = pathlib.Path(__file__).resolve().parent + sexample_xml = pathlib.Path.joinpath(sandbox_dir, "example", "structexample.xml") + + return XP.XmlParser.from_file(sexample_xml) + + def test_load_example(example_model): """Test that example is loadable.""" assert example_model.validate(None) is True -def test_dublicate_block_name(example_model): - """Trigger dublicate block name error""" +def test_duplicate_block_name(example_model): + """Trigger duplicate block name error""" name = example_model.container[0].blocks[0].name example_model.container[0].blocks[1].name = name assert example_model.validate(None) is False @@ -28,8 +37,8 @@ def test_overlapping_block(example_model): example_model.container[0].blocks[0].addr = addr - 0x99 assert example_model.validate(None) is False -def test_dublicate_parameter_name(example_model): - """Trigger dublicate parameter name error""" +def test_duplicate_parameter_name(example_model): + """Trigger duplicate parameter name error""" name = example_model.container[0].blocks[0].parameter[0].name example_model.container[0].blocks[0].parameter[1].name = name assert example_model.validate(None) is False @@ -55,3 +64,13 @@ def test_parameter_header_overlap(example_model): """Trigger parameter overlaps header error""" example_model.container[0].blocks[0].parameter[0].offset -= 1 assert example_model.validate(None) is False + +def test_duplicate_struct_name(structexample_model): + """Trigger duplicate struct name error""" + structexample_model.datastructs[1].name = structexample_model.datastructs[0].name + assert structexample_model.validate(None) is False + +def test_duplicate_field_name(structexample_model): + """Trigger duplicate field name error""" + structexample_model.datastructs[0].fields[1].name = structexample_model.datastructs[0].fields[0].name + assert structexample_model.validate(None) is False \ No newline at end of file diff --git a/tests/test_pargen.py b/tests/test_pargen.py index 47f9927..bfd7951 100644 --- a/tests/test_pargen.py +++ b/tests/test_pargen.py @@ -1,5 +1,6 @@ import pytest import pathlib +import json5 from flashcontainer import pargen @@ -8,7 +9,7 @@ def test_pargen_errors(tmp_path): sandbox_dir = pathlib.Path(__file__).resolve().parent example_xml = pathlib.Path.joinpath(sandbox_dir, "example", "example.xml") - + # run without writer should succeed result = pargen.pargen( cfgfile=example_xml, @@ -18,7 +19,7 @@ def test_pargen_errors(tmp_path): writers=[]) assert result == pargen.Error.ERROR_OK.value - # invalid model + # invalid model result = pargen.pargen( cfgfile=pathlib.Path.joinpath(sandbox_dir, "collateral", "invalid.xml"), @@ -28,7 +29,7 @@ def test_pargen_errors(tmp_path): writers=[]) assert result == pargen.Error.ERROR_INVALID_FORMAT.value - # invalid filename + # invalid filename result = pargen.pargen( cfgfile=pathlib.Path.joinpath(sandbox_dir, "collateral", "invalidX.xml"), @@ -38,7 +39,7 @@ def test_pargen_errors(tmp_path): writers=[]) assert result == pargen.Error.ERROR_FILE_NOT_FOUND.value - # fail validation + # fail validation result = pargen.pargen( cfgfile=pathlib.Path.joinpath(sandbox_dir, "collateral", "fail_validation.xml"), @@ -68,13 +69,13 @@ def test_pargen_output(tmp_path): # diff content (lines with ":") gen_lines = [] with open(pathlib.Path.joinpath(tmp_path, "pytest.hex"), encoding="utf-8") as file: - for line in file: + for line in file: if line[0] == ":": gen_lines.append(line) reference_lines = [] with open(pathlib.Path.joinpath(arduino_example, "param", "param.hex"), encoding="utf-8") as file: - for line in file: + for line in file: if line[0] == ":": reference_lines.append(line) @@ -90,3 +91,24 @@ def test_pargen_output(tmp_path): print(crc) assert crc == 0x2144DF1C + + +def test_pyhexdump_output(tmp_path): + """Run pargen on struct example""" + sandbox_dir = pathlib.Path(__file__).resolve().parent + + result = pargen.pargen( + cfgfile=pathlib.Path.joinpath(sandbox_dir, "example", "structexample.xml"), + filename="pytest", + outdir=tmp_path, + static=False, + writers=[pargen.PyHexDumpWriter]) + assert result == pargen.Error.ERROR_OK.value + + with open(pathlib.Path.joinpath(tmp_path, "pytest.pyhexdump"), encoding="utf8") as gfp: + generated = json5.load(gfp) + with open(pathlib.Path.joinpath(sandbox_dir, "collateral", "pyhex_ref.json"), encoding="utf8")as rfp: + reference = json5.load(rfp) + + assert generated['structures'] == reference['structures'] + assert generated['elements'] == reference['elements'] diff --git a/tests/test_xmlparser.py b/tests/test_xmlparser.py index 863872c..0411905 100644 --- a/tests/test_xmlparser.py +++ b/tests/test_xmlparser.py @@ -5,42 +5,44 @@ from flashcontainer import datamodel def test_parse_int(): - assert XP.XmlParser._parse_int("0") == 0 - assert XP.XmlParser._parse_int("0x0") == 0 - assert XP.XmlParser._parse_int("0xFF") == 255 - assert XP.XmlParser._parse_int("1") == 1 - assert XP.XmlParser._parse_int("-2") == -2 - assert XP.XmlParser._parse_int("0xFFFFFFFF") == 0xFFFFFFFF - assert XP.XmlParser._parse_int("AFFE") == 0xAFFE + parser = XP.XmlParser() + assert parser._parse_int("0") == 0 + assert parser._parse_int("0x0") == 0 + assert parser._parse_int("0xFF") == 255 + assert parser._parse_int("1") == 1 + assert parser._parse_int("-2") == -2 + assert parser._parse_int("0xFFFFFFFF") == 0xFFFFFFFF + assert parser._parse_int("AFFE") == 0xAFFE with pytest.raises(Exception) as e_info: - XP.XmlParser._parse_int("") + parser._parse_int("") with pytest.raises(Exception) as e_info: - XP.XmlParser._parse_int("banana") + parser._parse_int("banana") with pytest.raises(Exception) as e_info: - XP.XmlParser._parse_int("0x1X") + parser._parse_int("0x1X") def test_calc_addr(): - assert XP.XmlParser.calc_addr(0x100, 0x0, "0x0", 1) == 0x100 # numeric offset applied to base - assert XP.XmlParser.calc_addr(0x100, 0xff, "0x1", 1) == 0x101 # numeric offset applied to base + parser = XP.XmlParser() + assert parser.calc_addr(0x100, 0x0, "0x0", 1) == 0x100 # numeric offset applied to base + assert parser.calc_addr(0x100, 0xff, "0x1", 1) == 0x101 # numeric offset applied to base # with alignment - assert XP.XmlParser.calc_addr(0x101, 0xff, "0x1", 2) == 0x102 # numeric offset applied to base - assert XP.XmlParser.calc_addr(0x101, 0xff, "0x1", 4) == 0x104 # numeric offset applied to base - assert XP.XmlParser.calc_addr(0x101, 0xff, "0x1", 8) == 0x108 # numeric offset applied to base - assert XP.XmlParser.calc_addr(0x101, 0xff, "0x1", 16) == 0x110 # numeric offset applied to base - assert XP.XmlParser.calc_addr(0x102, 0xff, "0x1", 32) == 0x120 # numeric offset applied to base - assert XP.XmlParser.calc_addr(0x103, 0xff, "0x1", 64) == 0x140 # numeric offset applied to base + assert parser.calc_addr(0x101, 0xff, "0x1", 2) == 0x102 # numeric offset applied to base + assert parser.calc_addr(0x101, 0xff, "0x1", 4) == 0x104 # numeric offset applied to base + assert parser.calc_addr(0x101, 0xff, "0x1", 8) == 0x108 # numeric offset applied to base + assert parser.calc_addr(0x101, 0xff, "0x1", 16) == 0x110 # numeric offset applied to base + assert parser.calc_addr(0x102, 0xff, "0x1", 32) == 0x120 # numeric offset applied to base + assert parser.calc_addr(0x103, 0xff, "0x1", 64) == 0x140 # numeric offset applied to base # "." = run + align - assert XP.XmlParser.calc_addr(0x10, 0x101, ".", 1) == 0x101 # offset added to run - assert XP.XmlParser.calc_addr(0x10, 0x101, ".", 2) == 0x102 # offset added to run - assert XP.XmlParser.calc_addr(0x10, 0x102, ".", 2) == 0x102 # offset added to run + assert parser.calc_addr(0x10, 0x101, ".", 1) == 0x101 # offset added to run + assert parser.calc_addr(0x10, 0x101, ".", 2) == 0x102 # offset added to run + assert parser.calc_addr(0x10, 0x102, ".", 2) == 0x102 # offset added to run - assert XP.XmlParser.calc_addr(0xEEEE0000, 0xEEEE0000, ".", 1) == 0xEEEE0000 # run = base and "." means current run + assert parser.calc_addr(0xEEEE0000, 0xEEEE0000, ".", 1) == 0xEEEE0000 # run = base and "." means current run def test_parse_invalid_xml(): sandbox_dir = pathlib.Path(__file__).resolve().parent @@ -99,9 +101,41 @@ def test_parse_safety_example(): def test_modify_value(): sandbox_dir = pathlib.Path(__file__).resolve().parents[1] safety_xml = pathlib.Path.joinpath(sandbox_dir, "examples", "safety", "safety.xml") - model = XP.XmlParser.from_file(safety_xml, {"calibration":"[0,1,3,4,5,6,7,8,9,10]"}) - assert model.validate(None) == True + model = XP.XmlParser.from_file(safety_xml, {"calibration":"[0,1,3,4,5,6,7,8,9,10]", "idontexist": 3}) + assert model.validate(None) is True print(model.container[0].blocks[0].parameter[0].value) assert model.container[0].blocks[0].parameter[0].value == b'\x00\x00\x00\x00\x00\x00\x80?\x00\x00@@\x00\x00\x80@\x00\x00\xa0@\x00\x00\xc0@\x00\x00\xe0@\x00\x00\x00A\x00\x00\x10A\x00\x00 A' - \ No newline at end of file +def test_parse_structs(): + """ Test for the correct parsing of xml defined structs """ + sandbox_dir = pathlib.Path(__file__).resolve().parent + test_xml = pathlib.Path.joinpath(sandbox_dir, "example", "structexample.xml") + model = XP.XmlParser.from_file(test_xml) + assert model.validate(None) is True + + # check parsing of struct tags + assert len(model.datastructs) == 2 + assert len(model.datastructs[0].fields) == 3 + assert "super simple" in model.datastructs[0].comment + assert len(model.datastructs[1].fields) == 5 + assert "space" in model.get_struct_by_name("ComplexS").fields[2].comment + assert model.get_struct_by_name("idonotexist") is None + + # check parsing of complex parameters + assert model.container[0].blocks[2].addr == 0x80000400 + params = model.container[0].blocks[2].parameter + assert params[0].name == "simpy" + assert params[0].offset == model.container[0].blocks[2].addr + 0x10 + assert params[0].value == b'\x03\x05\xd7' + + assert params[1].name == "biggy" + assert params[1].offset == params[0].offset + 3 + assert params[1].value == b'\x01\xFF\xFF\xFF\xFF\x7F\x96\x98\x00\x00\x00\x00\x00' + \ + b'\xFF\xFF\x01\x00\x04\x00\x10\x00\x40\x00' + +def test_parse_invalid_structs(): + """Test invalid struct definitions or parameter values""" + sandbox_dir = pathlib.Path(__file__).resolve().parent + garbage_dir = pathlib.Path.joinpath(sandbox_dir, "collateral", "garbage") + for invalid_xml in garbage_dir.iterdir(): + assert XP.XmlParser.from_file(invalid_xml) is None