From: Manfred Steiner Date: Thu, 31 Oct 2024 16:52:55 +0000 (+0100) Subject: test-software v2024-10-31 X-Git-Url: https://git.htl-mechatronik.at/public/?a=commitdiff_plain;h=36a1a374732130fc4bfcf2e16ff01f86dabdd7b3;p=nano-x-base.git test-software v2024-10-31 --- diff --git a/README.md b/README.md index 1f93262..3f088e7 100644 --- a/README.md +++ b/README.md @@ -58,12 +58,27 @@ Vorne | Hinten ## Test-Software -### Nano-644, Nano-1284 und Arduino Nano +Die Entwicklung der Test-Software wird im Branch *[test-software](https://git.htl-mechatronik.at/public/?p=nano-x-base.git;a=tree;f=software/test-software;hb=refs/heads/test-software)* geführt und von Zeit zu Zeit in den master-Banch übernommen. -Die fertig übersetzten ELF-Dateien sind zu finden unter: -* Nano-644: [test_2024-07-23_nano-644.elf](software/nano-644/test_2024-07-23/release/v2024-08-18_1103/test_2024-07-23_nano-644.elf) -* Nano-1284: [test_2024-07-23_nano-1284p.elf](software/nano-1284/test_2024-07-23/release/v2024-08-18_1118/test_2024-07-23_nano-1284p.elf) -* Ardunino Nano (5V): [test_2024-07-23_nano-5v.elf](software/arduino-nano-5v/test_2024-07-23/release/v2024-08-18_1113/test_2024-07-23_nano-5v.elf) +Makefiles und Scripte gehen von einem Linux (Debian) System als Betriebssystem aus! + +Der Quelltext ist hier zu finden: +[software/test-software/src/](software/test-software/src) + +Aus diesem Quelltext werden drei Varianten erstellt. Diese befinden sich im jeweiligen Unterordner: +* **Nano-1284**: [software/test-software/nano-1284](software/test-software/nano-1284) +* **Nano-644**:[software/test-software/nano-644](software/test-software/nano-644) +* **Arduino Nano**: [software/test-software/nano-328](software/test-software/nano-328) + +Im jeweiligen Unterordner befindet sich das für die jeweilige CPU angepasste Makefile. + +Weiters ist im Unterordner *release* eine freigegebene Version zu finden: +* **Nano-1284**: [software/test-software/nano-1284/release](software/test-software/nano-1284/release) +* **Nano-644**:[software/test-software/nano-644/release](software/test-software/nano-644/release) +* **Arduino Nano**: [software/test-software/nano-328/release](software/test-software/nano-328/release) + +Die Versionsnummer wird aus Datum und Zeit der Übersetzung automatisch gebildet und beim Start des Programmes ausgegeben. +Bei der Erstellung eine Release mittels `make release` wird das Dash-Script [software/test-software/create-release](software/test-software/create-release) verwendet, welches aus der ELF-Datei (dem Ergebnis der Übersetzung) Datum und Zeit extrahiert und im Verzeichnisname abbildet. Entwicklungsumgebung: @@ -71,21 +86,28 @@ Entwicklungsumgebung: * IDE: VS-Code * Betriebssystem: Linux/Debian -Software-Ordner je nach verwendetem µC: -* Nano-644 (3.3V): [software/nano-644/test_2024-07-23/](software/nano-644/test_2024-07-23/) -* Arduino Nano (5V): [software/arduino-nano-5v/test_2024-07-23/](software/arduino-nano-5v/test_2024-07-23/) -* Nano-1284 (3.3V): [software/nano-1284/test_2024-07-23/](software/nano-1284/test_2024-07-23/) +Sofern am Nano ein Bootloader installiert ist kann das Programm mit `make flash` auf das Zielsystem übertragen werden. Bei fehlendem Bootloader kann mit Hilf eines Fischl-Programmieradapter und dem Kommando `isp-flash` eine Übertragung ins Flash der CPU erfolgen. + +Bootloader sind im Git-Repository [https://git.htl-mechatronik.at/public/?p=bootloader-arduino.git;a=home](https://git.htl-mechatronik.at/public/?p=bootloader-arduino.git;a=home) zu finden. -Die Quelltexte sind im Ordner `software/nano-644/test_2024-07-23/src/` zu finden. In den anderen Ordnern ist der Ordner `src` nur ein symbolischer Link zu [software/nano-644/test_2024-07-23/src/](software/nano-644/test_2024-07-23/src/)! +### Nano-1284, Nano-644 -Das Programm kann mit `make flash` auf den jeweiligen Nano übertragen werden. Über die USB-Schnittstelle kann mittels Terminalprogramm (115200/8N1) (`make picocom`) die Verbindung hergestellt werden. +Über die USB-Schnittstelle kann mittels Terminalprogramm (`make picocom`) die Verbindung hergestellt werden. +Die serielle Schnittstelle ist für 115200 Bit/s (8 Data Bits, No parity, 1 stopbit) konfiguriert. -Dort kann mittels Menüfunktion die entsprechende Baugruppe ausgewahlt und getestet werden. Für den Punkt `Modbus` ist der Anschluss eines modbusfähigen Energiezählers *Easton SDM230-Modbus* erforderlich. +Dort kann mittels Menüfunktion die entsprechende Baugruppe ausgewahlt und getestet werden. +* Punkt `b`: es ist der Anschluss eines modbusfähigen Energiezählers *Easton SDM230-Modbus* erforderlich. +* Punkt `f`: es ist der Anschluss eines [Sparkfun Env-Combo](https://www.sparkfun.com/products/22858) erforderlich. +* Punkt `c`: es sind 2 Nano-X-Base Boards, deren Modbus Schnittstellen mit einem Patch-Kabel verbunden sind, erforderlich. ``` -==================================== - ATmega644P / Aug 18 2024 / 11:03:20 -==================================== +Hardware V2a detected (ADC7H=0xEC) + +===================================== + ATmega1284P / Oct 31 2024 / 17:26:33 +===================================== + Hardware: V2a +===================================== Available units: @@ -112,6 +134,49 @@ Available units: Select unit: ``` +### Arduino Nano (ATmega328P) + +Im Gegensatz zum Nano-644 und Nano-1284 fehler dem Arduino Nano folgende Komponenten: +* zweite UART Schnittstelle +* keine Real Time Clock (RTC) +* kein 868MHz-Modem (basierend auf dem CC-1101) + +Daher sind einige der Funktionen im Menü nicht verfügbar. + +Über die USB-Schnittstelle kann mittels Terminalprogramm (`make picocom`) die Verbindung hergestellt werden. +Die serielle Schnittstelle ist für 38400 Bit/s (8 Data Bits, No parity, 1 stopbit) konfiguriert. + +Dort kann mittels Menüfunktion die entsprechende Baugruppe ausgewahlt und getestet werden. +* Punkt `c`: es ist der Anschluss eines modbusfähigen Energiezählers *Easton SDM230-Modbus* erforderlich. + +``` +Hardware V2a detected (ADC7H=0xB4) + +===================================== + ATmega328P / Oct 31 2024 / 17:26:29 +===================================== + Hardware: V2a +===================================== + +Available units: + + 0 ... Led + 1 ... Switch + 2 ... Rgb + 3 ... Seg7 + 4 ... Poti + 5 ... Encoder + 6 ... R2R + 7 ... Motor + 8 ... PortExp + 9 ... Lcd + a ... I2C-Master + b ... I2C-Slave + c ... I2C-Sparkfun Env-Combo + +Select unit: +``` + ### Raspberry Pico Für den Raspberry Pico steht derzeit nur ein kleines bereits übersetztes Programm zur Verfügung. diff --git a/software/arduino-nano-5v/test_2024-07-23/.gdb_history b/software/arduino-nano-5v/test_2024-07-23/.gdb_history deleted file mode 100644 index 3339046..0000000 --- a/software/arduino-nano-5v/test_2024-07-23/.gdb_history +++ /dev/null @@ -1,9 +0,0 @@ -target remote :1234 -layout split -stepi -quit -target remote :1234 -layout split -stepi -b *main+9 -quit diff --git a/software/arduino-nano-5v/test_2024-07-23/.gdbinit b/software/arduino-nano-5v/test_2024-07-23/.gdbinit deleted file mode 100644 index 139597f..0000000 --- a/software/arduino-nano-5v/test_2024-07-23/.gdbinit +++ /dev/null @@ -1,2 +0,0 @@ - - diff --git a/software/arduino-nano-5v/test_2024-07-23/.gitignore b/software/arduino-nano-5v/test_2024-07-23/.gitignore deleted file mode 100644 index a959910..0000000 --- a/software/arduino-nano-5v/test_2024-07-23/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -.depend -**/build -**/dist -**/sim diff --git a/software/arduino-nano-5v/test_2024-07-23/.vscode/c_cpp_properties.json b/software/arduino-nano-5v/test_2024-07-23/.vscode/c_cpp_properties.json deleted file mode 100644 index 93c17af..0000000 --- a/software/arduino-nano-5v/test_2024-07-23/.vscode/c_cpp_properties.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "configurations": [ - { - "name": "Linux AVR", - "includePath": [ - "/usr/lib/avr/include/**", - "/usr/lib/gcc/avr/**" - ], - "defines": [], - "compilerPath": "/usr/bin/avr-gcc", - "compilerArgs": [ "-mmcu=atmega328p", "-DF_CPU=16000000", "-Os" ], - "cStandard": "gnu11", - "cppStandard": "gnu++11", - "intelliSenseMode": "linux-gcc-x64" - } - ], - "version": 4 -} diff --git a/software/arduino-nano-5v/test_2024-07-23/.vscode/launch.json b/software/arduino-nano-5v/test_2024-07-23/.vscode/launch.json deleted file mode 100644 index f29cf2e..0000000 --- a/software/arduino-nano-5v/test_2024-07-23/.vscode/launch.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [ - { - "name": "Build", - // "request": "launch", - "type": "node-terminal", - "preLaunchTask": "build" - },{ - "name": "Flash", - // "request": "launch", - "type": "node-terminal", - "preLaunchTask": "flash" - },{ - "name": "Clean", - // "request": "launch", - "type": "node-terminal", - "preLaunchTask": "clean" - },{ - // es muss mit simuc --board arduino dist/programm.elf der Simulator - // gestartet werden. Dessen gdb-stub öffnet auf localhost:1234 einen Port - "name": "Debug (simuc)", - "type": "cppdbg", - "request": "launch", - "program": "${workspaceFolder}/sim/atmega328p.elf", - "cwd": "${workspaceFolder}", - "externalConsole": false, - "MIMode": "gdb", - "miDebuggerPath": "/usr/bin/avr-gdb", - "miDebuggerServerAddress": ":1234", - "preLaunchTask": "build" - } - ] -} diff --git a/software/arduino-nano-5v/test_2024-07-23/.vscode/settings.json b/software/arduino-nano-5v/test_2024-07-23/.vscode/settings.json deleted file mode 100644 index b2e94c9..0000000 --- a/software/arduino-nano-5v/test_2024-07-23/.vscode/settings.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "[c]": { - "editor.insertSpaces": true, - "editor.tabSize": 3, - "editor.detectIndentation": false - }, - "[cpp]": { - "editor.insertSpaces": true, - "editor.tabSize": 3, - "editor.detectIndentation": false - }, - "[h]": { - "editor.insertSpaces": true, - "editor.tabSize": 3, - "editor.detectIndentation": false - }, - "[hpp]": { - "editor.insertSpaces": true, - "editor.tabSize": 3, - "editor.detectIndentation": false - }, - "cSpell.words": [], - "cSpell.ignorePaths": [ - "**/*.json", "**/*.c", "**/*.h", "**/*.cpp", "**/*.hpp", "**/Makefile" - ] -} diff --git a/software/arduino-nano-5v/test_2024-07-23/.vscode/tasks.json b/software/arduino-nano-5v/test_2024-07-23/.vscode/tasks.json deleted file mode 100644 index 74fb1c7..0000000 --- a/software/arduino-nano-5v/test_2024-07-23/.vscode/tasks.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - // See https://go.microsoft.com/fwlink/?LinkId=733558 - // for the documentation about the tasks.json format - "version": "2.0.0", - "tasks": [{ - "label": "build", - "type": "shell", - "command": "make", - "problemMatcher":[ - "$gcc" - ] - },{ - "label": "clean", - "type": "shell", - "command": "make", - "args": [ "clean" ], - },{ - "label": "flash", - "type": "shell", - "command": "make", - "args": [ "flash" ], - }] -} \ No newline at end of file diff --git a/software/arduino-nano-5v/test_2024-07-23/Makefile b/software/arduino-nano-5v/test_2024-07-23/Makefile deleted file mode 100644 index eb17024..0000000 --- a/software/arduino-nano-5v/test_2024-07-23/Makefile +++ /dev/null @@ -1,125 +0,0 @@ -.PHONY: all info flash picocom clean -$(shell mkdir -p dist >/dev/null) -$(shell mkdir -p build >/dev/null) -$(shell mkdir -p sim >/dev/null) -$(shell mkdir -p sim/build >/dev/null) - -NAME="test_2024-07-23_nano-5v" -SRC= $(wildcard src/*.c src/*.cpp src/*/*.c src/*/*.cpp) -HDR= $(wildcard src/*.h src/*.hpp src/*/*.h src/*/*.hpp) -OBJ_CPP = $(SRC:src/%.cpp=build/%.o) -OBJ = $(OBJ_CPP:src/%.c=build/%.o) -OBJ_SIM_CPP = $(SRC:src/%.cpp=sim/build/%.o) -OBJ_SIM = $(OBJ_SIM_CPP:src/%.c=sim/build/%.o) - -DEVICE=atmega328p - -CC= avr-g++ -CFLAGS= -Wall -mmcu=$(DEVICE) -Os -DF_CPU=16000000 -c -LFLAGS= -Wall -mmcu=$(DEVICE) -Os -DF_CPU=16000000 -Wl,-u,vfprintf -lprintf_flt -lm - -CFLAGS_SIM= -Wall -mmcu=$(DEVICE) -Og -DF_CPU=16000000 -g -c -c -LFLAGS_SIM= -Wall -mmcu=$(DEVICE) -Og -DF_CPU=16000000 -g -Wl,-u,vfprintf -lprintf_flt -lm - - -all: dist/$(NAME).elf dist/$(NAME).s dist/$(NAME).hex sim/$(NAME).elf sim/$(NAME).s info - - -info: - @avr-size --mcu=$(DEVICE) --format=avr dist/$(NAME).elf - -.depend: $(SRC) $(HDR) - $(CC) -mmcu=$(DEVICE) -MM $(SRC) | sed --regexp-extended 's/^(.*\.o)\: src\/(.*)(\.cpp|\.c) (.*)/build\/\2\.o\: src\/\2\3 \4/g' > .depend - --include .depend - -# .depend solte auch auf Header Files achten! - -dist/$(NAME).elf: .depend $(OBJ) - $(CC) $(LFLAGS) -o $@ $(OBJ) - -dist/%.s: dist/%.elf - avr-objdump -d $< > $@ - -dist/%.hex: dist/%.elf - avr-objcopy -O ihex $(HEX_FLASH_FLAGS) $< $@ - -sim/$(NAME).elf: .depend $(OBJ_SIM) - $(CC) $(LFLAGS_SIM) -o $@ $(OBJ_SIM) - -# ensure that __DATE__ and __TIME__ macros are up to date -build/main.o: src/main.cpp $(SRC) $(HDR) - @mkdir -p $(dir $@) - $(CC) $(CFLAGS) -o $@ $< - -build/%.o: src/%.c - @mkdir -p $(dir $@) - $(CC) $(CFLAGS) -o $@ $< - -build/%.o: src/%.cpp - @mkdir -p $(dir $@) - $(CC) $(CFLAGS) -o $@ $< - -sim/build/%.o: src/%.c - @mkdir -p $(dir $@) - $(CC) $(CFLAGS_SIM) -o $@ $< - -sim/build/%.o: src/%.cpp - @mkdir -p $(dir $@) - $(CC) $(CFLAGS_SIM) -o $@ $< - -sim/%.s: sim/%.elf - avr-objdump -d $< > $@ - -simuc: sim/$(NAME).elf - simuc --board arduino $< - -gdb: sim/$(NAME).elf - avr-gdb $< - - -flash: dist/$(NAME).elf all - avrdude -c arduino -P /dev/ttyUSB0 -p m328p -e -U flash:w:$< - -flash0: dist/$(NAME).elf all - avrdude -c arduino -P /dev/ttyUSB0 -p m328p -e -U flash:w:$< - -flash1: dist/$(NAME).elf all - avrdude -c arduino -P /dev/ttyUSB1 -p m328p -e -U flash:w:$< - -flash2: dist/$(NAME).elf all - avrdude -c arduino -P /dev/ttyUSB2 -p m328p -e -U flash:w:$< - -picocom: - # picocom sends CR for ENTER -> convert cr (\r) to lf (\n) - picocom -b 115200 --omap crlf --raise-dtr /dev/ttyUSB0 - -picocom0: - picocom -b 115200 --omap crlf --raise-dtr /dev/ttyUSB0 - -picocom1: - picocom -b 115200 --omap crlf --raise-dtr /dev/ttyUSB1 - -picocom2: - picocom -b 115200 --omap crlf --raise-dtr /dev/ttyUSB2 - - -isp-328p: - avrdude -c usbasp -p m328p - -isp-flash-328p: dist/$(NAME).elf all - avrdude -c usbasp -p m328p -e -U flash:w:$< - -flash-328pp: dist/$(NAME).elf all - avrdude -c arduino -p m328p -P /dev/ttyUSB0 -b 115200 -e -U flash:w:$< - - -isp-fuse-328p: - avrdude -c usbasp -p m328p -U lfuse:w:0xFF:m -U hfuse:w:0xD9:m -U efuse:w:0xFF:m -U lock:w:0xFF:m - -clean: - @rm -r dist - @rm -r build - @rm -r sim - @find . -type f -name ".depend" -exec rm {} \; - @echo "clean done" diff --git a/software/arduino-nano-5v/test_2024-07-23/README.md b/software/arduino-nano-5v/test_2024-07-23/README.md deleted file mode 100644 index c4d5e14..0000000 --- a/software/arduino-nano-5v/test_2024-07-23/README.md +++ /dev/null @@ -1 +0,0 @@ -# Testprogramm diff --git a/software/arduino-nano-5v/test_2024-07-23/release/v2024-08-18_1113/test_2024-07-23_nano-5v.elf b/software/arduino-nano-5v/test_2024-07-23/release/v2024-08-18_1113/test_2024-07-23_nano-5v.elf deleted file mode 100755 index 2f20bd1..0000000 Binary files a/software/arduino-nano-5v/test_2024-07-23/release/v2024-08-18_1113/test_2024-07-23_nano-5v.elf and /dev/null differ diff --git a/software/arduino-nano-5v/test_2024-07-23/src b/software/arduino-nano-5v/test_2024-07-23/src deleted file mode 120000 index 38a7ae1..0000000 --- a/software/arduino-nano-5v/test_2024-07-23/src +++ /dev/null @@ -1 +0,0 @@ -../../nano-644/test_2024-07-23/src \ No newline at end of file diff --git a/software/nano-1284/test_2024-07-23/.gdb_history b/software/nano-1284/test_2024-07-23/.gdb_history deleted file mode 100644 index 3339046..0000000 --- a/software/nano-1284/test_2024-07-23/.gdb_history +++ /dev/null @@ -1,9 +0,0 @@ -target remote :1234 -layout split -stepi -quit -target remote :1234 -layout split -stepi -b *main+9 -quit diff --git a/software/nano-1284/test_2024-07-23/.gdbinit b/software/nano-1284/test_2024-07-23/.gdbinit deleted file mode 100644 index 139597f..0000000 --- a/software/nano-1284/test_2024-07-23/.gdbinit +++ /dev/null @@ -1,2 +0,0 @@ - - diff --git a/software/nano-1284/test_2024-07-23/.gitignore b/software/nano-1284/test_2024-07-23/.gitignore deleted file mode 100644 index a959910..0000000 --- a/software/nano-1284/test_2024-07-23/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -.depend -**/build -**/dist -**/sim diff --git a/software/nano-1284/test_2024-07-23/.vscode/c_cpp_properties.json b/software/nano-1284/test_2024-07-23/.vscode/c_cpp_properties.json deleted file mode 100644 index dda83a0..0000000 --- a/software/nano-1284/test_2024-07-23/.vscode/c_cpp_properties.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "configurations": [ - { - "name": "Linux AVR", - "includePath": [ - "/usr/lib/avr/include/**", - "/usr/lib/gcc/avr/**" - ], - "defines": [], - "compilerPath": "/usr/bin/avr-gcc", - "compilerArgs": [ "-mmcu=atmega1284p", "-DF_CPU=12000000", "-Os" ], - "cStandard": "gnu11", - "cppStandard": "gnu++11", - "intelliSenseMode": "linux-gcc-x64" - } - ], - "version": 4 -} diff --git a/software/nano-1284/test_2024-07-23/.vscode/launch.json b/software/nano-1284/test_2024-07-23/.vscode/launch.json deleted file mode 100644 index f29cf2e..0000000 --- a/software/nano-1284/test_2024-07-23/.vscode/launch.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [ - { - "name": "Build", - // "request": "launch", - "type": "node-terminal", - "preLaunchTask": "build" - },{ - "name": "Flash", - // "request": "launch", - "type": "node-terminal", - "preLaunchTask": "flash" - },{ - "name": "Clean", - // "request": "launch", - "type": "node-terminal", - "preLaunchTask": "clean" - },{ - // es muss mit simuc --board arduino dist/programm.elf der Simulator - // gestartet werden. Dessen gdb-stub öffnet auf localhost:1234 einen Port - "name": "Debug (simuc)", - "type": "cppdbg", - "request": "launch", - "program": "${workspaceFolder}/sim/atmega328p.elf", - "cwd": "${workspaceFolder}", - "externalConsole": false, - "MIMode": "gdb", - "miDebuggerPath": "/usr/bin/avr-gdb", - "miDebuggerServerAddress": ":1234", - "preLaunchTask": "build" - } - ] -} diff --git a/software/nano-1284/test_2024-07-23/.vscode/settings.json b/software/nano-1284/test_2024-07-23/.vscode/settings.json deleted file mode 100644 index 58539af..0000000 --- a/software/nano-1284/test_2024-07-23/.vscode/settings.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "[c]": { - "editor.insertSpaces": true, - "editor.tabSize": 3, - "editor.detectIndentation": false - }, - "[cpp]": { - "editor.insertSpaces": true, - "editor.tabSize": 3, - "editor.detectIndentation": false - }, - "[h]": { - "editor.insertSpaces": true, - "editor.tabSize": 3, - "editor.detectIndentation": false - }, - "[hpp]": { - "editor.insertSpaces": true, - "editor.tabSize": 3, - "editor.detectIndentation": false - }, - "cSpell.words": [], - "cSpell.ignorePaths": [ - "**/*.json", "**/*.c", "**/*.h", "**/*.cpp", "**/*.hpp", "**/Makefile" - ], - "java.project.sourcePaths": [ - "src/units" - ] -} diff --git a/software/nano-1284/test_2024-07-23/.vscode/tasks.json b/software/nano-1284/test_2024-07-23/.vscode/tasks.json deleted file mode 100644 index 74fb1c7..0000000 --- a/software/nano-1284/test_2024-07-23/.vscode/tasks.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - // See https://go.microsoft.com/fwlink/?LinkId=733558 - // for the documentation about the tasks.json format - "version": "2.0.0", - "tasks": [{ - "label": "build", - "type": "shell", - "command": "make", - "problemMatcher":[ - "$gcc" - ] - },{ - "label": "clean", - "type": "shell", - "command": "make", - "args": [ "clean" ], - },{ - "label": "flash", - "type": "shell", - "command": "make", - "args": [ "flash" ], - }] -} \ No newline at end of file diff --git a/software/nano-1284/test_2024-07-23/Makefile b/software/nano-1284/test_2024-07-23/Makefile deleted file mode 100644 index 88e53cd..0000000 --- a/software/nano-1284/test_2024-07-23/Makefile +++ /dev/null @@ -1,124 +0,0 @@ -.PHONY: all info flash picocom clean -$(shell mkdir -p dist >/dev/null) -$(shell mkdir -p build >/dev/null) -$(shell mkdir -p sim >/dev/null) -$(shell mkdir -p sim/build >/dev/null) - -NAME=test_2024-07-23_nano-1284p -SRC= $(wildcard src/*.c src/*.cpp src/*/*.c src/*/*.cpp) -HDR= $(wildcard src/*.h src/*.hpp src/*/*.h src/*/*.hpp) -OBJ_CPP = $(SRC:src/%.cpp=build/%.o) -OBJ = $(OBJ_CPP:src/%.c=build/%.o) -OBJ_SIM_CPP = $(SRC:src/%.cpp=sim/build/%.o) -OBJ_SIM = $(OBJ_SIM_CPP:src/%.c=sim/build/%.o) - -DEVICE=atmega1284p -AVRDUDE_DEVICE=m1284p - -CC= avr-g++ -CFLAGS= -Wall -mmcu=$(DEVICE) -Os -DF_CPU=12000000 -c -LFLAGS= -Wall -mmcu=$(DEVICE) -Os -DF_CPU=12000000 -Wl,-u,vfprintf -lprintf_flt -lm - -CFLAGS_SIM= -Wall -mmcu=$(DEVICE) -Og -DF_CPU=12000000 -g -c -c -LFLAGS_SIM= -Wall -mmcu=$(DEVICE) -Og -DF_CPU=12000000 -g -Wl,-u,vfprintf -lprintf_flt -lm - - -all: dist/$(NAME).elf dist/$(NAME).s dist/$(NAME).hex sim/$(NAME).elf sim/$(NAME).s info - -info: - @avr-size --mcu=$(DEVICE) --format=avr dist/$(NAME).elf - -.depend: $(SRC) $(HDR) - $(CC) -mmcu=$(DEVICE) -MM $(SRC) | sed --regexp-extended 's/^(.*\.o)\: src\/(.*)(\.cpp|\.c) (.*)/build\/\2\.o\: src\/\2\3 \4/g' > .depend - --include .depend - -# .depend solte auch auf Header Files achten! - -dist/$(NAME).elf: .depend $(OBJ) - $(CC) $(LFLAGS) -o $@ $(OBJ) - -dist/%.s: dist/%.elf - avr-objdump -d $< > $@ - -dist/%.hex: dist/%.elf - avr-objcopy -O ihex $(HEX_FLASH_FLAGS) $< $@ - -sim/$(NAME).elf: .depend $(OBJ_SIM) - $(CC) $(LFLAGS_SIM) -o $@ $(OBJ_SIM) - -# ensure that __DATE__ and __TIME__ macros are up to date -build/main.o: src/main.cpp $(SRC) $(HDR) - @mkdir -p $(dir $@) - $(CC) $(CFLAGS) -o $@ $< - -build/%.o: src/%.c - @mkdir -p $(dir $@) - $(CC) $(CFLAGS) -o $@ $< - -build/%.o: src/%.cpp - @mkdir -p $(dir $@) - $(CC) $(CFLAGS) -o $@ $< - -sim/build/%.o: src/%.c - @mkdir -p $(dir $@) - $(CC) $(CFLAGS_SIM) -o $@ $< - -sim/build/%.o: src/%.cpp - @mkdir -p $(dir $@) - $(CC) $(CFLAGS_SIM) -o $@ $< - -sim/%.s: sim/%.elf - avr-objdump -d $< > $@ - -simuc: sim/$(NAME).elf - simuc --board nano-1284 $< - -gdb: sim/$(NAME).elf - avr-gdb $< - - -flash: dist/$(NAME).elf all - avrdude -c arduino -P /dev/ttyUSB0 -p $(AVRDUDE_DEVICE) -e -U flash:w:$< - -flash0: dist/$(NAME).elf all - avrdude -c arduino -P /dev/ttyUSB0 -p $(AVRDUDE_DEVICE) -e -U flash:w:$< - -flash1: dist/$(NAME).elf all - avrdude -c arduino -P /dev/ttyUSB1 -p $(AVRDUDE_DEVICE) -e -U flash:w:$< - -flash2: dist/$(NAME).elf all - avrdude -c arduino -P /dev/ttyUSB2 -p $(AVRDUDE_DEVICE) -e -U flash:w:$< - -picocom: - # picocom sends CR for ENTER -> convert cr (\r) to lf (\n) - picocom -b 115200 --omap crlf --raise-dtr /dev/ttyUSB0 - -picocom0: - picocom -b 115200 --omap crlf --raise-dtr /dev/ttyUSB0 - -picocom1: - picocom -b 115200 --omap crlf --raise-dtr /dev/ttyUSB1 - -picocom2: - picocom -b 115200 --omap crlf --raise-dtr /dev/ttyUSB2 - - -isp-1284p: - avrdude -c usbasp -p $(AVRDUDE_DEVICE) - -isp-flash-1284p: dist/$(NAME).elf all - avrdude -c usbasp -p $(AVRDUDE_DEVICE) -e -U flash:w:$< - -flash-1284p: dist/$(NAME).elf all - avrdude -c arduino -p $(AVRDUDE_DEVICE) -P /dev/ttyUSB0 -b 115200 -e -U flash:w:$< - -isp-fuse-1284p: - avrdude -c usbasp -p $(AVRDUDE_DEVICE) -U lfuse:w:0xFF:m -U hfuse:w:0xD9:m -U efuse:w:0xFF:m -U lock:w:0xFF:m - -clean: - @rm -r dist - @rm -r build - @rm -r sim - @find . -type f -name ".depend" -exec rm {} \; - @echo "clean done" diff --git a/software/nano-1284/test_2024-07-23/README.md b/software/nano-1284/test_2024-07-23/README.md deleted file mode 100644 index 65a0866..0000000 --- a/software/nano-1284/test_2024-07-23/README.md +++ /dev/null @@ -1 +0,0 @@ -# Testprogramm für Nano-1284 diff --git a/software/nano-1284/test_2024-07-23/release/v2024-08-18_1118/test_2024-07-23_nano-1284p.elf b/software/nano-1284/test_2024-07-23/release/v2024-08-18_1118/test_2024-07-23_nano-1284p.elf deleted file mode 100755 index 8c3e007..0000000 Binary files a/software/nano-1284/test_2024-07-23/release/v2024-08-18_1118/test_2024-07-23_nano-1284p.elf and /dev/null differ diff --git a/software/nano-1284/test_2024-07-23/src b/software/nano-1284/test_2024-07-23/src deleted file mode 120000 index 38a7ae1..0000000 --- a/software/nano-1284/test_2024-07-23/src +++ /dev/null @@ -1 +0,0 @@ -../../nano-644/test_2024-07-23/src \ No newline at end of file diff --git a/software/nano-644/test_2024-07-23/.gdb_history b/software/nano-644/test_2024-07-23/.gdb_history deleted file mode 100644 index 3339046..0000000 --- a/software/nano-644/test_2024-07-23/.gdb_history +++ /dev/null @@ -1,9 +0,0 @@ -target remote :1234 -layout split -stepi -quit -target remote :1234 -layout split -stepi -b *main+9 -quit diff --git a/software/nano-644/test_2024-07-23/.gdbinit b/software/nano-644/test_2024-07-23/.gdbinit deleted file mode 100644 index 139597f..0000000 --- a/software/nano-644/test_2024-07-23/.gdbinit +++ /dev/null @@ -1,2 +0,0 @@ - - diff --git a/software/nano-644/test_2024-07-23/.gitignore b/software/nano-644/test_2024-07-23/.gitignore deleted file mode 100644 index a959910..0000000 --- a/software/nano-644/test_2024-07-23/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -.depend -**/build -**/dist -**/sim diff --git a/software/nano-644/test_2024-07-23/.vscode/c_cpp_properties.json b/software/nano-644/test_2024-07-23/.vscode/c_cpp_properties.json deleted file mode 100644 index 3a57c79..0000000 --- a/software/nano-644/test_2024-07-23/.vscode/c_cpp_properties.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "configurations": [ - { - "name": "Linux AVR", - "includePath": [ - "/usr/lib/avr/include/**", - "/usr/lib/gcc/avr/**" - ], - "defines": [], - "compilerPath": "/usr/bin/avr-gcc", - "compilerArgs": [ "-mmcu=atmega644p", "-DF_CPU=12000000", "-Os" ], - "cStandard": "gnu11", - "cppStandard": "gnu++11", - "intelliSenseMode": "linux-gcc-x64" - } - ], - "version": 4 -} diff --git a/software/nano-644/test_2024-07-23/.vscode/launch.json b/software/nano-644/test_2024-07-23/.vscode/launch.json deleted file mode 100644 index f29cf2e..0000000 --- a/software/nano-644/test_2024-07-23/.vscode/launch.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [ - { - "name": "Build", - // "request": "launch", - "type": "node-terminal", - "preLaunchTask": "build" - },{ - "name": "Flash", - // "request": "launch", - "type": "node-terminal", - "preLaunchTask": "flash" - },{ - "name": "Clean", - // "request": "launch", - "type": "node-terminal", - "preLaunchTask": "clean" - },{ - // es muss mit simuc --board arduino dist/programm.elf der Simulator - // gestartet werden. Dessen gdb-stub öffnet auf localhost:1234 einen Port - "name": "Debug (simuc)", - "type": "cppdbg", - "request": "launch", - "program": "${workspaceFolder}/sim/atmega328p.elf", - "cwd": "${workspaceFolder}", - "externalConsole": false, - "MIMode": "gdb", - "miDebuggerPath": "/usr/bin/avr-gdb", - "miDebuggerServerAddress": ":1234", - "preLaunchTask": "build" - } - ] -} diff --git a/software/nano-644/test_2024-07-23/.vscode/settings.json b/software/nano-644/test_2024-07-23/.vscode/settings.json deleted file mode 100644 index 58539af..0000000 --- a/software/nano-644/test_2024-07-23/.vscode/settings.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "[c]": { - "editor.insertSpaces": true, - "editor.tabSize": 3, - "editor.detectIndentation": false - }, - "[cpp]": { - "editor.insertSpaces": true, - "editor.tabSize": 3, - "editor.detectIndentation": false - }, - "[h]": { - "editor.insertSpaces": true, - "editor.tabSize": 3, - "editor.detectIndentation": false - }, - "[hpp]": { - "editor.insertSpaces": true, - "editor.tabSize": 3, - "editor.detectIndentation": false - }, - "cSpell.words": [], - "cSpell.ignorePaths": [ - "**/*.json", "**/*.c", "**/*.h", "**/*.cpp", "**/*.hpp", "**/Makefile" - ], - "java.project.sourcePaths": [ - "src/units" - ] -} diff --git a/software/nano-644/test_2024-07-23/.vscode/tasks.json b/software/nano-644/test_2024-07-23/.vscode/tasks.json deleted file mode 100644 index 74fb1c7..0000000 --- a/software/nano-644/test_2024-07-23/.vscode/tasks.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - // See https://go.microsoft.com/fwlink/?LinkId=733558 - // for the documentation about the tasks.json format - "version": "2.0.0", - "tasks": [{ - "label": "build", - "type": "shell", - "command": "make", - "problemMatcher":[ - "$gcc" - ] - },{ - "label": "clean", - "type": "shell", - "command": "make", - "args": [ "clean" ], - },{ - "label": "flash", - "type": "shell", - "command": "make", - "args": [ "flash" ], - }] -} \ No newline at end of file diff --git a/software/nano-644/test_2024-07-23/Makefile b/software/nano-644/test_2024-07-23/Makefile deleted file mode 100644 index 4ceec53..0000000 --- a/software/nano-644/test_2024-07-23/Makefile +++ /dev/null @@ -1,138 +0,0 @@ -.PHONY: all info flash picocom clean -$(shell mkdir -p dist >/dev/null) -$(shell mkdir -p build >/dev/null) -$(shell mkdir -p sim >/dev/null) -$(shell mkdir -p sim/build >/dev/null) - -NAME=test_2024-07-23_nano-644 -SRC= $(wildcard src/*.c src/*.cpp src/*/*.c src/*/*.cpp) -HDR= $(wildcard src/*.h src/*.hpp src/*/*.h src/*/*.hpp) -OBJ_CPP = $(SRC:src/%.cpp=build/%.o) -OBJ = $(OBJ_CPP:src/%.c=build/%.o) -OBJ_SIM_CPP = $(SRC:src/%.cpp=sim/build/%.o) -OBJ_SIM = $(OBJ_SIM_CPP:src/%.c=sim/build/%.o) - -DEVICE=atmega644p - -CC= avr-g++ -CFLAGS= -Wall -mmcu=$(DEVICE) -Os -DF_CPU=12000000 -c -LFLAGS= -Wall -mmcu=$(DEVICE) -Os -DF_CPU=12000000 -Wl,-u,vfprintf -lprintf_flt -lm - -CFLAGS_SIM= -Wall -mmcu=$(DEVICE) -Og -DF_CPU=12000000 -g -c -c -LFLAGS_SIM= -Wall -mmcu=$(DEVICE) -Og -DF_CPU=12000000 -g -Wl,-u,vfprintf -lprintf_flt -lm - - -all: dist/$(NAME).elf dist/$(NAME).s dist/$(NAME).hex sim/$(NAME).elf sim/$(NAME).s info - -dbg: - @echo --HDR--------------------------------- - @echo $(HDR) - @echo --SRC--------------------------------- - @echo $(SRC) - @echo --OBJ--------------------------------- - @echo $(OBJ) - @echo --OBJ_CPP----------------------------- - @echo $(OBJ_CPP) - @echo --OBJ--------------------------------- - @echo $(OBJ) - @echo =================================== - @echo - -info: - @avr-size --mcu=$(DEVICE) --format=avr dist/$(NAME).elf - -.depend: $(SRC) $(HDR) - $(CC) -mmcu=$(DEVICE) -MM $(SRC) | sed --regexp-extended 's/^(.*\.o)\: src\/(.*)(\.cpp|\.c) (.*)/build\/\2\.o\: src\/\2\3 \4/g' > .depend - --include .depend - -# .depend solte auch auf Header Files achten! - -dist/$(NAME).elf: .depend $(OBJ) - $(CC) $(LFLAGS) -o $@ $(OBJ) - -dist/%.s: dist/%.elf - avr-objdump -d $< > $@ - -dist/%.hex: dist/%.elf - avr-objcopy -O ihex $(HEX_FLASH_FLAGS) $< $@ - -sim/$(NAME).elf: .depend $(OBJ_SIM) - $(CC) $(LFLAGS_SIM) -o $@ $(OBJ_SIM) - -# ensure that __DATE__ and __TIME__ macros are up to date -build/main.o: src/main.cpp $(SRC) $(HDR) - @mkdir -p $(dir $@) - $(CC) $(CFLAGS) -o $@ $< - -build/%.o: src/%.c - @mkdir -p $(dir $@) - $(CC) $(CFLAGS) -o $@ $< - -build/%.o: src/%.cpp - @mkdir -p $(dir $@) - $(CC) $(CFLAGS) -o $@ $< - -sim/build/%.o: src/%.c - @mkdir -p $(dir $@) - $(CC) $(CFLAGS_SIM) -o $@ $< - -sim/build/%.o: src/%.cpp - @mkdir -p $(dir $@) - $(CC) $(CFLAGS_SIM) -o $@ $< - -sim/%.s: sim/%.elf - avr-objdump -d $< > $@ - -simuc: sim/$(NAME).elf - simuc --board arduino $< - -gdb: sim/$(NAME).elf - avr-gdb $< - - -flash: dist/$(NAME).elf all - avrdude -c arduino -P /dev/ttyUSB0 -p m644p -e -U flash:w:$< - -flash0: dist/$(NAME).elf all - avrdude -c arduino -P /dev/ttyUSB0 -p m644p -e -U flash:w:$< - -flash1: dist/$(NAME).elf all - avrdude -c arduino -P /dev/ttyUSB1 -p m644p -e -U flash:w:$< - -flash2: dist/$(NAME).elf all - avrdude -c arduino -P /dev/ttyUSB2 -p m644p -e -U flash:w:$< - -picocom: - # picocom sends CR for ENTER -> convert cr (\r) to lf (\n) - picocom -b 115200 --omap crlf --raise-dtr /dev/ttyUSB0 - -picocom0: - picocom -b 115200 --omap crlf --raise-dtr /dev/ttyUSB0 - -picocom1: - picocom -b 115200 --omap crlf --raise-dtr /dev/ttyUSB1 - -picocom2: - picocom -b 115200 --omap crlf --raise-dtr /dev/ttyUSB2 - - -isp-644p: - avrdude -c usbasp -p m644p - -isp-flash-644p: dist/$(NAME).elf all - avrdude -c usbasp -p m644p -e -U flash:w:$< - -flash-644p: dist/$(NAME).elf all - avrdude -c arduino -p m644p -P /dev/ttyUSB0 -b 115200 -e -U flash:w:$< - - -isp-fuse-644p: - avrdude -c usbasp -p m644p -U lfuse:w:0xFF:m -U hfuse:w:0xD9:m -U efuse:w:0xFF:m -U lock:w:0xFF:m - -clean: - @rm -r dist - @rm -r build - @rm -r sim - @find . -type f -name ".depend" -exec rm {} \; - @echo "clean done" diff --git a/software/nano-644/test_2024-07-23/README.md b/software/nano-644/test_2024-07-23/README.md deleted file mode 100644 index c4d5e14..0000000 --- a/software/nano-644/test_2024-07-23/README.md +++ /dev/null @@ -1 +0,0 @@ -# Testprogramm diff --git a/software/nano-644/test_2024-07-23/release/v2024-08-18_1103/test_2024-07-23_nano-644.elf b/software/nano-644/test_2024-07-23/release/v2024-08-18_1103/test_2024-07-23_nano-644.elf deleted file mode 100755 index 5605578..0000000 Binary files a/software/nano-644/test_2024-07-23/release/v2024-08-18_1103/test_2024-07-23_nano-644.elf and /dev/null differ diff --git a/software/nano-644/test_2024-07-23/src/adafruit/bme280.cpp b/software/nano-644/test_2024-07-23/src/adafruit/bme280.cpp deleted file mode 100644 index 1836c56..0000000 --- a/software/nano-644/test_2024-07-23/src/adafruit/bme280.cpp +++ /dev/null @@ -1,512 +0,0 @@ -#include "bme280.h" -#include -#include - -Adafruit_BME280 theBME280; -Adafruit_BME280_Temp bm280TempSensor; -Adafruit_BME280_Pressure bm280PressureSensor; -Adafruit_BME280_Humidity bm280HumiditySensor; - -Adafruit_BME280::Adafruit_BME280() { - static I2cMaster i2cDevice; - t_fine_adjust = 0; - temp_sensor = &bm280TempSensor; - pressure_sensor = &bm280PressureSensor; - humidity_sensor = &bm280HumiditySensor; - i2c_dev = &i2cDevice; -} - -bool Adafruit_BME280::begin (uint8_t addr) { - if (!i2c_dev->begin(addr)) { - return false; - } - return init(); -} - -bool Adafruit_BME280::init() { - _sensorID = read8(BME280_REGISTER_CHIPID); - if (_sensorID != 0x60) { - return false; - } - write8(BME280_REGISTER_SOFTRESET, 0xB6); - _delay_ms(10); // wait for chip to wake up. - - // if chip is still reading calibration, delay - while (isReadingCalibration()) { - _delay_ms(10); - } - - readCoefficients(); // read trimming parameters, see DS 4.2.2 - setSampling(); // use defaults - _delay_ms(100); - - return true; -} - -/*! - * @brief setup sensor with given parameters / settings - * - * This is simply a overload to the normal begin()-function, so SPI users - * don't get confused about the library requiring an address. - * @param mode the power mode to use for the sensor - * @param tempSampling the temp samping rate to use - * @param pressSampling the pressure sampling rate to use - * @param humSampling the humidity sampling rate to use - * @param filter the filter mode to use - * @param duration the standby duration to use - */ -void Adafruit_BME280::setSampling(sensor_mode mode, - sensor_sampling tempSampling, - sensor_sampling pressSampling, - sensor_sampling humSampling, - sensor_filter filter, - standby_duration duration) { - _measReg.mode = mode; - _measReg.osrs_t = tempSampling; - _measReg.osrs_p = pressSampling; - - _humReg.osrs_h = humSampling; - _configReg.filter = filter; - _configReg.t_sb = duration; - _configReg.spi3w_en = 0; - - // making sure sensor is in sleep mode before setting configuration - // as it otherwise may be ignored - write8(BME280_REGISTER_CONTROL, MODE_SLEEP); - - // you must make sure to also set REGISTER_CONTROL after setting the - // CONTROLHUMID register, otherwise the values won't be applied (see - // DS 5.4.3) - write8(BME280_REGISTER_CONTROLHUMID, _humReg.get()); - write8(BME280_REGISTER_CONFIG, _configReg.get()); - write8(BME280_REGISTER_CONTROL, _measReg.get()); -} - -/*! - * @brief Writes an 8 bit value over I2C or SPI - * @param reg the register address to write to - * @param value the value to write to the register - */ -void Adafruit_BME280::write8(uint8_t reg, uint8_t value) { - uint8_t buffer[2]; - buffer[1] = value; - if (i2c_dev) { - buffer[0] = reg; - i2c_dev->write(buffer, 2); - } -} - -/*! - * @brief Reads an 8 bit value over I2C or SPI - * @param reg the register address to read from - * @returns the data byte read from the device - */ -uint8_t Adafruit_BME280::read8(uint8_t reg) { - uint8_t buffer[1]; - if (i2c_dev) { - buffer[0] = uint8_t(reg); - i2c_dev->write_then_read(buffer, 1, buffer, 1); - } - return buffer[0]; -} - -/*! - * @brief Reads a 16 bit value over I2C or SPI - * @param reg the register address to read from - * @returns the 16 bit data value read from the device - */ -uint16_t Adafruit_BME280::read16(uint8_t reg) { - uint8_t buffer[2]; - - if (i2c_dev) { - buffer[0] = uint8_t(reg); - i2c_dev->write_then_read(buffer, 1, buffer, 2); - } - return uint16_t(buffer[0]) << 8 | uint16_t(buffer[1]); -} - -/*! - * @brief Reads a signed 16 bit little endian value over I2C or SPI - * @param reg the register address to read from - * @returns the 16 bit data value read from the device - */ -uint16_t Adafruit_BME280::read16_LE(uint8_t reg) { - uint16_t temp = read16(reg); - return (temp >> 8) | (temp << 8); -} - -/*! - * @brief Reads a signed 16 bit value over I2C or SPI - * @param reg the register address to read from - * @returns the 16 bit data value read from the device - */ -int16_t Adafruit_BME280::readS16(uint8_t reg) { return (int16_t)read16(reg); } - -/*! - * @brief Reads a signed little endian 16 bit value over I2C or SPI - * @param reg the register address to read from - * @returns the 16 bit data value read from the device - */ -int16_t Adafruit_BME280::readS16_LE(uint8_t reg) { - return (int16_t)read16_LE(reg); -} - -/*! - * @brief Reads a 24 bit value over I2C - * @param reg the register address to read from - * @returns the 24 bit data value read from the device - */ -uint32_t Adafruit_BME280::read24(uint8_t reg) { - uint8_t buffer[3]; - - if (i2c_dev) { - buffer[0] = uint8_t(reg); - i2c_dev->write_then_read(buffer, 1, buffer, 3); - } - return uint32_t(buffer[0]) << 16 | uint32_t(buffer[1]) << 8 | - uint32_t(buffer[2]); -} - -/*! - * @brief Take a new measurement (only possible in forced mode) - @returns true in case of success else false - */ -bool Adafruit_BME280::takeForcedMeasurement(void) { - bool return_value = false; - // If we are in forced mode, the BME sensor goes back to sleep after each - // measurement and we need to set it to forced mode once at this point, so - // it will take the next measurement and then return to sleep again. - // In normal mode simply does new measurements periodically. - if (_measReg.mode == MODE_FORCED) { - return_value = true; - // set to forced mode, i.e. "take next measurement" - write8(BME280_REGISTER_CONTROL, _measReg.get()); - // Store current time to measure the timeout - uint32_t timeout_start = millis(); - // wait until measurement has been completed, otherwise we would read the - // the values from the last measurement or the timeout occurred after 2 sec. - while (read8(BME280_REGISTER_STATUS) & 0x08) { - // In case of a timeout, stop the while loop - if ((millis() - timeout_start) > 2000) { - return_value = false; - break; - } - _delay_ms(1); - } - } - return return_value; -} - -/*! - * @brief Reads the factory-set coefficients - */ -void Adafruit_BME280::readCoefficients(void) { - _bme280_calib.dig_T1 = read16_LE(BME280_REGISTER_DIG_T1); - _bme280_calib.dig_T2 = readS16_LE(BME280_REGISTER_DIG_T2); - _bme280_calib.dig_T3 = readS16_LE(BME280_REGISTER_DIG_T3); - - _bme280_calib.dig_P1 = read16_LE(BME280_REGISTER_DIG_P1); - _bme280_calib.dig_P2 = readS16_LE(BME280_REGISTER_DIG_P2); - _bme280_calib.dig_P3 = readS16_LE(BME280_REGISTER_DIG_P3); - _bme280_calib.dig_P4 = readS16_LE(BME280_REGISTER_DIG_P4); - _bme280_calib.dig_P5 = readS16_LE(BME280_REGISTER_DIG_P5); - _bme280_calib.dig_P6 = readS16_LE(BME280_REGISTER_DIG_P6); - _bme280_calib.dig_P7 = readS16_LE(BME280_REGISTER_DIG_P7); - _bme280_calib.dig_P8 = readS16_LE(BME280_REGISTER_DIG_P8); - _bme280_calib.dig_P9 = readS16_LE(BME280_REGISTER_DIG_P9); - - _bme280_calib.dig_H1 = read8(BME280_REGISTER_DIG_H1); - _bme280_calib.dig_H2 = readS16_LE(BME280_REGISTER_DIG_H2); - _bme280_calib.dig_H3 = read8(BME280_REGISTER_DIG_H3); - _bme280_calib.dig_H4 = ((int8_t)read8(BME280_REGISTER_DIG_H4) << 4) | - (read8(BME280_REGISTER_DIG_H4 + 1) & 0xF); - _bme280_calib.dig_H5 = ((int8_t)read8(BME280_REGISTER_DIG_H5 + 1) << 4) | - (read8(BME280_REGISTER_DIG_H5) >> 4); - _bme280_calib.dig_H6 = (int8_t)read8(BME280_REGISTER_DIG_H6); -} - -/*! - * @brief return true if chip is busy reading cal data - * @returns true if reading calibration, false otherwise - */ -bool Adafruit_BME280::isReadingCalibration(void) { - uint8_t const rStatus = read8(BME280_REGISTER_STATUS); - - return (rStatus & (1 << 0)) != 0; -} - -/*! - * @brief Returns the temperature from the sensor - * @returns the temperature read from the device - */ -float Adafruit_BME280::readTemperature(void) { - int32_t var1, var2; - - int32_t adc_T = read24(BME280_REGISTER_TEMPDATA); - if (adc_T == 0x800000) // value in case temp measurement was disabled - return NAN; - adc_T >>= 4; - - var1 = (int32_t)((adc_T / 8) - ((int32_t)_bme280_calib.dig_T1 * 2)); - var1 = (var1 * ((int32_t)_bme280_calib.dig_T2)) / 2048; - var2 = (int32_t)((adc_T / 16) - ((int32_t)_bme280_calib.dig_T1)); - var2 = (((var2 * var2) / 4096) * ((int32_t)_bme280_calib.dig_T3)) / 16384; - - t_fine = var1 + var2 + t_fine_adjust; - - int32_t T = (t_fine * 5 + 128) / 256; - - return (float)T / 100; -} - -/*! - * @brief Returns the pressure from the sensor - * @returns the pressure value (in Pascal) read from the device - */ -float Adafruit_BME280::readPressure(void) { - int64_t var1, var2, var3, var4; - - readTemperature(); // must be done first to get t_fine - - int32_t adc_P = read24(BME280_REGISTER_PRESSUREDATA); - if (adc_P == 0x800000) // value in case pressure measurement was disabled - return NAN; - adc_P >>= 4; - - var1 = ((int64_t)t_fine) - 128000; - var2 = var1 * var1 * (int64_t)_bme280_calib.dig_P6; - var2 = var2 + ((var1 * (int64_t)_bme280_calib.dig_P5) * 131072); - var2 = var2 + (((int64_t)_bme280_calib.dig_P4) * 34359738368); - var1 = ((var1 * var1 * (int64_t)_bme280_calib.dig_P3) / 256) + - ((var1 * ((int64_t)_bme280_calib.dig_P2) * 4096)); - var3 = ((int64_t)1) * 140737488355328; - var1 = (var3 + var1) * ((int64_t)_bme280_calib.dig_P1) / 8589934592; - - if (var1 == 0) { - return 0; // avoid exception caused by division by zero - } - - var4 = 1048576 - adc_P; - var4 = (((var4 * 2147483648UL) - var2) * 3125) / var1; - var1 = (((int64_t)_bme280_calib.dig_P9) * (var4 / 8192) * (var4 / 8192)) / - 33554432; - var2 = (((int64_t)_bme280_calib.dig_P8) * var4) / 524288; - var4 = ((var4 + var1 + var2) / 256) + (((int64_t)_bme280_calib.dig_P7) * 16); - - float P = var4 / 256.0; - - return P; -} - -/*! - * @brief Returns the humidity from the sensor - * @returns the humidity value read from the device - */ -float Adafruit_BME280::readHumidity(void) { - int32_t var1, var2, var3, var4, var5; - - readTemperature(); // must be done first to get t_fine - - int32_t adc_H = read16(BME280_REGISTER_HUMIDDATA); - if (adc_H == 0x8000) // value in case humidity measurement was disabled - return NAN; - - var1 = t_fine - ((int32_t)76800); - var2 = (int32_t)(adc_H * 16384); - var3 = (int32_t)(((int32_t)_bme280_calib.dig_H4) * 1048576); - var4 = ((int32_t)_bme280_calib.dig_H5) * var1; - var5 = (((var2 - var3) - var4) + (int32_t)16384) / 32768; - var2 = (var1 * ((int32_t)_bme280_calib.dig_H6)) / 1024; - var3 = (var1 * ((int32_t)_bme280_calib.dig_H3)) / 2048; - var4 = ((var2 * (var3 + (int32_t)32768)) / 1024) + (int32_t)2097152; - var2 = ((var4 * ((int32_t)_bme280_calib.dig_H2)) + 8192) / 16384; - var3 = var5 * var2; - var4 = ((var3 / 32768) * (var3 / 32768)) / 128; - var5 = var3 - ((var4 * ((int32_t)_bme280_calib.dig_H1)) / 16); - var5 = (var5 < 0 ? 0 : var5); - var5 = (var5 > 419430400 ? 419430400 : var5); - uint32_t H = (uint32_t)(var5 / 4096); - - return (float)H / 1024.0; -} - -/*! - * Calculates the altitude (in meters) from the specified atmospheric - * pressure (in hPa), and sea-level pressure (in hPa). - * @param seaLevel Sea-level pressure in hPa - * @returns the altitude value read from the device - */ -float Adafruit_BME280::readAltitude(float seaLevel) { - // Equation taken from BMP180 datasheet (page 16): - // http://www.adafruit.com/datasheets/BST-BMP180-DS000-09.pdf - - // Note that using the equation from wikipedia can give bad results - // at high altitude. See this thread for more information: - // http://forums.adafruit.com/viewtopic.php?f=22&t=58064 - - float atmospheric = readPressure() / 100.0F; - return 44330.0 * (1.0 - pow(atmospheric / seaLevel, 0.1903)); -} - -/*! - * Calculates the pressure at sea level (in hPa) from the specified - * altitude (in meters), and atmospheric pressure (in hPa). - * @param altitude Altitude in meters - * @param atmospheric Atmospheric pressure in hPa - * @returns the pressure at sea level (in hPa) from the specified altitude - */ -float Adafruit_BME280::seaLevelForAltitude(float altitude, float atmospheric) { - // Equation taken from BMP180 datasheet (page 17): - // http://www.adafruit.com/datasheets/BST-BMP180-DS000-09.pdf - - // Note that using the equation from wikipedia can give bad results - // at high altitude. See this thread for more information: - // http://forums.adafruit.com/viewtopic.php?f=22&t=58064 - - return atmospheric / pow(1.0 - (altitude / 44330.0), 5.255); -} - -/*! - * Returns Sensor ID found by init() for diagnostics - * @returns Sensor ID 0x60 for BME280, 0x56, 0x57, 0x58 BMP280 - */ -uint32_t Adafruit_BME280::sensorID(void) { return _sensorID; } - -/*! - * Returns the current temperature compensation value in degrees Celsius - * @returns the current temperature compensation value in degrees Celsius - */ -float Adafruit_BME280::getTemperatureCompensation(void) { - return float((t_fine_adjust * 5) >> 8) / 100.0; -}; - -/*! - * Sets a value to be added to each temperature reading. This adjusted - * temperature is used in pressure and humidity readings. - * @param adjustment Value to be added to each temperature reading in Celsius - */ -void Adafruit_BME280::setTemperatureCompensation(float adjustment) { - // convert the value in C into and adjustment to t_fine - t_fine_adjust = ((int32_t(adjustment * 100) << 8)) / 5; -}; - - -/**************************************************************************/ -/*! - @brief Gets the sensor_t data for the BME280's temperature sensor -*/ -/**************************************************************************/ -void Adafruit_BME280_Temp::getSensor(sensor_t *sensor) { - /* Clear the sensor_t object */ - memset(sensor, 0, sizeof(sensor_t)); - - /* Insert the sensor name in the fixed length char array */ - strncpy(sensor->name, "BME280", sizeof(sensor->name) - 1); - sensor->name[sizeof(sensor->name) - 1] = 0; - sensor->version = 1; - sensor->sensor_id = _sensorID; - sensor->type = SENSOR_TYPE_AMBIENT_TEMPERATURE; - sensor->min_delay = 0; - sensor->min_value = -40.0; /* Temperature range -40 ~ +85 C */ - sensor->max_value = +85.0; - sensor->resolution = 0.01; /* 0.01 C */ -} - -/**************************************************************************/ -/*! - @brief Gets the temperature as a standard sensor event - @param event Sensor event object that will be populated - @returns True -*/ -/**************************************************************************/ -bool Adafruit_BME280_Temp::getEvent(sensors_event_t *event) { - /* Clear the event */ - memset(event, 0, sizeof(sensors_event_t)); - - event->version = sizeof(sensors_event_t); - event->sensor_id = _sensorID; - event->type = SENSOR_TYPE_AMBIENT_TEMPERATURE; - event->timestamp = millis(); - event->temperature = theBME280.readTemperature(); - return true; -} - -/**************************************************************************/ -/*! - @brief Gets the sensor_t data for the BME280's pressure sensor -*/ -/**************************************************************************/ -void Adafruit_BME280_Pressure::getSensor(sensor_t *sensor) { - /* Clear the sensor_t object */ - memset(sensor, 0, sizeof(sensor_t)); - - /* Insert the sensor name in the fixed length char array */ - strncpy(sensor->name, "BME280", sizeof(sensor->name) - 1); - sensor->name[sizeof(sensor->name) - 1] = 0; - sensor->version = 1; - sensor->sensor_id = _sensorID; - sensor->type = SENSOR_TYPE_PRESSURE; - sensor->min_delay = 0; - sensor->min_value = 300.0; /* 300 ~ 1100 hPa */ - sensor->max_value = 1100.0; - sensor->resolution = 0.012; /* 0.12 hPa relative */ -} - -/**************************************************************************/ -/*! - @brief Gets the pressure as a standard sensor event - @param event Sensor event object that will be populated - @returns True -*/ -/**************************************************************************/ -bool Adafruit_BME280_Pressure::getEvent(sensors_event_t *event) { - /* Clear the event */ - memset(event, 0, sizeof(sensors_event_t)); - - event->version = sizeof(sensors_event_t); - event->sensor_id = _sensorID; - event->type = SENSOR_TYPE_PRESSURE; - event->timestamp = millis(); - event->pressure = theBME280.readPressure() / 100; // convert Pa to hPa - return true; -} - -/**************************************************************************/ -/*! - @brief Gets the sensor_t data for the BME280's humidity sensor -*/ -/**************************************************************************/ -void Adafruit_BME280_Humidity::getSensor(sensor_t *sensor) { - /* Clear the sensor_t object */ - memset(sensor, 0, sizeof(sensor_t)); - - /* Insert the sensor name in the fixed length char array */ - strncpy(sensor->name, "BME280", sizeof(sensor->name) - 1); - sensor->name[sizeof(sensor->name) - 1] = 0; - sensor->version = 1; - sensor->sensor_id = _sensorID; - sensor->type = SENSOR_TYPE_RELATIVE_HUMIDITY; - sensor->min_delay = 0; - sensor->min_value = 0; - sensor->max_value = 100; /* 0 - 100 % */ - sensor->resolution = 3; /* 3% accuracy */ -} - -/**************************************************************************/ -/*! - @brief Gets the humidity as a standard sensor event - @param event Sensor event object that will be populated - @returns True -*/ -/**************************************************************************/ -bool Adafruit_BME280_Humidity::getEvent(sensors_event_t *event) { - /* Clear the event */ - memset(event, 0, sizeof(sensors_event_t)); - - event->version = sizeof(sensors_event_t); - event->sensor_id = _sensorID; - event->type = SENSOR_TYPE_RELATIVE_HUMIDITY; - event->timestamp = millis(); - event->relative_humidity = theBME280.readHumidity(); - return true; -} diff --git a/software/nano-644/test_2024-07-23/src/adafruit/bme280.h b/software/nano-644/test_2024-07-23/src/adafruit/bme280.h deleted file mode 100644 index aa5aa72..0000000 --- a/software/nano-644/test_2024-07-23/src/adafruit/bme280.h +++ /dev/null @@ -1,373 +0,0 @@ -// https://github.com/adafruit/Adafruit_BME280_Library - -/*! - * @file Adafruit_BME280.h - * - * Designed specifically to work with the Adafruit BME280 Breakout - * ----> http://www.adafruit.com/products/2650 - * - * These sensors use I2C or SPI to communicate, 2 or 4 pins are required - * to interface. - * - * Adafruit invests time and resources providing this open source code, - * please support Adafruit and open-source hardware by purchasing - * products from Adafruit! - * - * Written by Kevin "KTOWN" Townsend for Adafruit Industries. - * - * BSD license, all text here must be included in any redistribution. - * See the LICENSE file for details. - * - */ - -#ifndef __BME280_H__ -#define __BME280_H__ - -// #include "Arduino.h" - -// #include -// #include -// #include - - -#include "../i2cmaster.hpp" -#include "../main.hpp" -// #define byte uint8_t - - - -#include -#include -#include "sensor.h" - -/*! - * @brief default I2C address - */ -#define BME280_ADDRESS (0x77) // Primary I2C Address - /*! - * @brief alternate I2C address - */ -#define BME280_ADDRESS_ALTERNATE (0x76) // Alternate Address - -/*! - * @brief Register addresses - */ -enum { - BME280_REGISTER_DIG_T1 = 0x88, - BME280_REGISTER_DIG_T2 = 0x8A, - BME280_REGISTER_DIG_T3 = 0x8C, - - BME280_REGISTER_DIG_P1 = 0x8E, - BME280_REGISTER_DIG_P2 = 0x90, - BME280_REGISTER_DIG_P3 = 0x92, - BME280_REGISTER_DIG_P4 = 0x94, - BME280_REGISTER_DIG_P5 = 0x96, - BME280_REGISTER_DIG_P6 = 0x98, - BME280_REGISTER_DIG_P7 = 0x9A, - BME280_REGISTER_DIG_P8 = 0x9C, - BME280_REGISTER_DIG_P9 = 0x9E, - - BME280_REGISTER_DIG_H1 = 0xA1, - BME280_REGISTER_DIG_H2 = 0xE1, - BME280_REGISTER_DIG_H3 = 0xE3, - BME280_REGISTER_DIG_H4 = 0xE4, - BME280_REGISTER_DIG_H5 = 0xE5, - BME280_REGISTER_DIG_H6 = 0xE7, - - BME280_REGISTER_CHIPID = 0xD0, - BME280_REGISTER_VERSION = 0xD1, - BME280_REGISTER_SOFTRESET = 0xE0, - - BME280_REGISTER_CAL26 = 0xE1, // R calibration stored in 0xE1-0xF0 - - BME280_REGISTER_CONTROLHUMID = 0xF2, - BME280_REGISTER_STATUS = 0XF3, - BME280_REGISTER_CONTROL = 0xF4, - BME280_REGISTER_CONFIG = 0xF5, - BME280_REGISTER_PRESSUREDATA = 0xF7, - BME280_REGISTER_TEMPDATA = 0xFA, - BME280_REGISTER_HUMIDDATA = 0xFD -}; - -/**************************************************************************/ -/*! - @brief calibration data -*/ -/**************************************************************************/ -typedef struct { - uint16_t dig_T1; ///< temperature compensation value - int16_t dig_T2; ///< temperature compensation value - int16_t dig_T3; ///< temperature compensation value - - uint16_t dig_P1; ///< pressure compensation value - int16_t dig_P2; ///< pressure compensation value - int16_t dig_P3; ///< pressure compensation value - int16_t dig_P4; ///< pressure compensation value - int16_t dig_P5; ///< pressure compensation value - int16_t dig_P6; ///< pressure compensation value - int16_t dig_P7; ///< pressure compensation value - int16_t dig_P8; ///< pressure compensation value - int16_t dig_P9; ///< pressure compensation value - - uint8_t dig_H1; ///< humidity compensation value - int16_t dig_H2; ///< humidity compensation value - uint8_t dig_H3; ///< humidity compensation value - int16_t dig_H4; ///< humidity compensation value - int16_t dig_H5; ///< humidity compensation value - int8_t dig_H6; ///< humidity compensation value -} bme280_calib_data; -/*=========================================================================*/ - -class Adafruit_BME280; - -/** Adafruit Unified Sensor interface for temperature component of BME280 */ -class Adafruit_BME280_Temp : public Adafruit_Sensor { -public: - /** @brief Create an Adafruit_Sensor compatible object for the temp sensor - @param parent A pointer to the BME280 class */ - Adafruit_BME280_Temp() { _sensorID = 280; } - bool getEvent(sensors_event_t *); - void getSensor(sensor_t *); - -private: - int _sensorID; -}; - -/** Adafruit Unified Sensor interface for pressure component of BME280 */ -class Adafruit_BME280_Pressure : public Adafruit_Sensor { -public: - /** @brief Create an Adafruit_Sensor compatible object for the pressure sensor - @param parent A pointer to the BME280 class */ - Adafruit_BME280_Pressure() { _sensorID = 280; } - bool getEvent(sensors_event_t *); - void getSensor(sensor_t *); - -private: - int _sensorID; -}; - -/** Adafruit Unified Sensor interface for humidity component of BME280 */ -class Adafruit_BME280_Humidity : public Adafruit_Sensor { -public: - /** @brief Create an Adafruit_Sensor compatible object for the humidity sensor - @param parent A pointer to the BME280 class */ - Adafruit_BME280_Humidity() { _sensorID = 280;} - bool getEvent(sensors_event_t *); - void getSensor(sensor_t *); - -private: - int _sensorID; -}; - -/**************************************************************************/ -/*! - @brief Class that stores state and functions for interacting with BME280 IC -*/ -/**************************************************************************/ -class Adafruit_BME280 { -public: - /**************************************************************************/ - /*! - @brief sampling rates - */ - /**************************************************************************/ - enum sensor_sampling { - SAMPLING_NONE = 0b000, - SAMPLING_X1 = 0b001, - SAMPLING_X2 = 0b010, - SAMPLING_X4 = 0b011, - SAMPLING_X8 = 0b100, - SAMPLING_X16 = 0b101 - }; - - /**************************************************************************/ - /*! - @brief power modes - */ - /**************************************************************************/ - enum sensor_mode { - MODE_SLEEP = 0b00, - MODE_FORCED = 0b01, - MODE_NORMAL = 0b11 - }; - - /**************************************************************************/ - /*! - @brief filter values - */ - /**************************************************************************/ - enum sensor_filter { - FILTER_OFF = 0b000, - FILTER_X2 = 0b001, - FILTER_X4 = 0b010, - FILTER_X8 = 0b011, - FILTER_X16 = 0b100 - }; - - /**************************************************************************/ - /*! - @brief standby duration in ms - */ - /**************************************************************************/ - enum standby_duration { - STANDBY_MS_0_5 = 0b000, - STANDBY_MS_10 = 0b110, - STANDBY_MS_20 = 0b111, - STANDBY_MS_62_5 = 0b001, - STANDBY_MS_125 = 0b010, - STANDBY_MS_250 = 0b011, - STANDBY_MS_500 = 0b100, - STANDBY_MS_1000 = 0b101 - }; - - // constructors - Adafruit_BME280(); - - bool begin(uint8_t addr = BME280_ADDRESS); - bool init(); - - void setSampling(sensor_mode mode = MODE_NORMAL, - sensor_sampling tempSampling = SAMPLING_X16, - sensor_sampling pressSampling = SAMPLING_X16, - sensor_sampling humSampling = SAMPLING_X16, - sensor_filter filter = FILTER_OFF, - standby_duration duration = STANDBY_MS_0_5); - - bool takeForcedMeasurement(void); - float readTemperature(void); - float readPressure(void); - float readHumidity(void); - - float readAltitude(float seaLevel); - float seaLevelForAltitude(float altitude, float pressure); - uint32_t sensorID(void); - - float getTemperatureCompensation(void); - void setTemperatureCompensation(float); - -protected: - I2cMaster *i2c_dev = NULL; ///< Pointer to I2C bus interface - // Adafruit_SPIDevice *spi_dev = NULL; ///< Pointer to SPI bus interface - - Adafruit_BME280_Temp *temp_sensor; - Adafruit_BME280_Pressure *pressure_sensor; - Adafruit_BME280_Humidity *humidity_sensor; - - void readCoefficients(void); - bool isReadingCalibration(void); - - void write8(uint8_t reg, uint8_t value); - uint8_t read8(uint8_t reg); - uint16_t read16(uint8_t reg); - uint32_t read24(uint8_t reg); - int16_t readS16(uint8_t reg); - uint16_t read16_LE(uint8_t reg); // little endian - int16_t readS16_LE(uint8_t reg); // little endian - - uint8_t _i2caddr; //!< I2C addr for the TwoWire interface - int32_t _sensorID; //!< ID of the BME Sensor - int32_t t_fine; //!< temperature with high resolution, stored as an attribute - //!< as this is used for temperature compensation reading - //!< humidity and pressure - - int32_t t_fine_adjust; //!< add to compensate temp readings and in turn - //!< to pressure and humidity readings - - bme280_calib_data _bme280_calib; //!< here calibration data is stored - - /**************************************************************************/ - /*! - @brief config register - */ - /**************************************************************************/ - struct config { - // inactive duration (standby time) in normal mode - // 000 = 0.5 ms - // 001 = 62.5 ms - // 010 = 125 ms - // 011 = 250 ms - // 100 = 500 ms - // 101 = 1000 ms - // 110 = 10 ms - // 111 = 20 ms - unsigned int t_sb : 3; ///< inactive duration (standby time) in normal mode - - // filter settings - // 000 = filter off - // 001 = 2x filter - // 010 = 4x filter - // 011 = 8x filter - // 100 and above = 16x filter - unsigned int filter : 3; ///< filter settings - - // unused - don't set - unsigned int none : 1; ///< unused - don't set - unsigned int spi3w_en : 1; ///< unused - don't set - - /// @return combined config register - unsigned int get() { return (t_sb << 5) | (filter << 2) | spi3w_en; } - }; - config _configReg; //!< config register object - - /**************************************************************************/ - /*! - @brief ctrl_meas register - */ - /**************************************************************************/ - struct ctrl_meas { - // temperature oversampling - // 000 = skipped - // 001 = x1 - // 010 = x2 - // 011 = x4 - // 100 = x8 - // 101 and above = x16 - unsigned int osrs_t : 3; ///< temperature oversampling - - // pressure oversampling - // 000 = skipped - // 001 = x1 - // 010 = x2 - // 011 = x4 - // 100 = x8 - // 101 and above = x16 - unsigned int osrs_p : 3; ///< pressure oversampling - - // device mode - // 00 = sleep - // 01 or 10 = forced - // 11 = normal - unsigned int mode : 2; ///< device mode - - /// @return combined ctrl register - unsigned int get() { return (osrs_t << 5) | (osrs_p << 2) | mode; } - }; - ctrl_meas _measReg; //!< measurement register object - - /**************************************************************************/ - /*! - @brief ctrl_hum register - */ - /**************************************************************************/ - struct ctrl_hum { - /// unused - don't set - unsigned int none : 5; - - // pressure oversampling - // 000 = skipped - // 001 = x1 - // 010 = x2 - // 011 = x4 - // 100 = x8 - // 101 and above = x16 - unsigned int osrs_h : 3; ///< pressure oversampling - - /// @return combined ctrl hum register - unsigned int get() { return (osrs_h); } - }; - ctrl_hum _humReg; //!< hum register object -}; - -extern Adafruit_BME280 theBME280; - -#endif diff --git a/software/nano-644/test_2024-07-23/src/adafruit/ens160.cpp b/software/nano-644/test_2024-07-23/src/adafruit/ens160.cpp deleted file mode 100644 index 29e3704..0000000 --- a/software/nano-644/test_2024-07-23/src/adafruit/ens160.cpp +++ /dev/null @@ -1,374 +0,0 @@ -/* - ScioSense_ENS160.h - Library for the ENS160 sensor with I2C interface from ScioSense - 2023 Mar 23 v6 Christoph Friese Bugfix measurement routine, prepare next release - 2021 Nov 25 v5 Martin Herold Custom mode timing fixed - 2021 Feb 04 v4 Giuseppe de Pinto Custom mode fixed - 2020 Apr 06 v3 Christoph Friese Changed nomenclature to ScioSense as product shifted from ams - 2020 Feb 15 v2 Giuseppe Pasetti Corrected firmware flash option - 2019 May 05 v1 Christoph Friese Created - based on application note "ENS160 Software Integration.pdf" rev 0.01 -*/ - -#include "ens160.h" -#include "math.h" -#include -#include -#include - -ScioSense_ENS160::ScioSense_ENS160 () { - _revENS16x = 0; - - //Isotherm, HP0 252°C / HP1 350°C / HP2 250°C / HP3 324°C / measure every 1008ms - _seq_steps[0][0] = 0x7c; - _seq_steps[0][1] = 0x0a; - _seq_steps[0][2] = 0x7e; - _seq_steps[0][3] = 0xaf; - _seq_steps[0][4] = 0xaf; - _seq_steps[0][5] = 0xa2; - _seq_steps[0][6] = 0x00; - _seq_steps[0][7] = 0x80; -} - -bool ScioSense_ENS160::begin () { - i2cDevice.begin(ENS160_I2CADDR_1); - _delay_ms(ENS160_BOOTING); - if (reset()) { - if (checkPartID()) { - if (setMode(ENS160_OPMODE_IDLE)) { - if (clearCommand()) { - if (getFirmware()) { - return true; - } - } - } - } - } - return false; - -} - -bool ScioSense_ENS160::write8 (uint8_t reg, uint8_t value) { - uint8_t buffer[2]; - buffer[1] = value; - buffer[0] = reg; - return i2cDevice.write(buffer, 2); -} - -bool ScioSense_ENS160::read8 (uint8_t reg, uint8_t *value) { - uint8_t buffer[1]; - buffer[0] = uint8_t(reg); - return i2cDevice.write_then_read(buffer, 1, value, 1); -} - -bool ScioSense_ENS160::read16 (uint8_t reg, uint16_t *value) { - uint8_t buffer[1]; - buffer[0] = uint8_t(reg); - return i2cDevice.write_then_read(buffer, 1, (uint8_t *)value, 2); -} - -bool ScioSense_ENS160::read16LE (uint8_t reg, uint16_t *value) { - uint16_t tmp; - if (read16(reg, &tmp)) { - *value = ((tmp & 0xff) << 8) | (tmp >> 8); - return true; - } - return false; -} - -bool ScioSense_ENS160::readBytes (uint8_t reg, uint8_t *bytes, uint8_t len) { - uint8_t buffer[1]; - buffer[0] = uint8_t(reg); - return i2cDevice.write_then_read(buffer, 1, buffer, len); -} - - -// Sends a reset to the ENS160. Returns false on I2C problems. -bool ScioSense_ENS160::reset () { - if (write8(ENS160_REG_OPMODE, ENS160_OPMODE_RESET)) { - _delay_ms(ENS160_BOOTING); - return true; - } - _delay_ms(ENS160_BOOTING); - return false; -} - -// Reads the part ID and confirms valid sensor -bool ScioSense_ENS160::checkPartID () { - uint16_t part_id; - - read16(ENS160_REG_PART_ID, &part_id); - _delay_ms(ENS160_BOOTING); - - if (part_id == ENS160_PARTID) { - _revENS16x = 0; - return true; - - } else if (part_id == ENS161_PARTID) { - _revENS16x = 1; - return true; - } - - return false; -} - -// Initialize idle mode and confirms -bool ScioSense_ENS160::clearCommand () { - uint8_t status; - - if (write8(ENS160_REG_COMMAND, ENS160_COMMAND_NOP)) { - if (write8(ENS160_REG_COMMAND, ENS160_COMMAND_CLRGPR)) { - _delay_ms(ENS160_BOOTING); - if (read8(ENS160_REG_DATA_STATUS, &status)) { - return true; - } - } - } - _delay_ms(ENS160_BOOTING); - return false; -} - -// Read firmware revisions -bool ScioSense_ENS160::getFirmware () { - uint8_t i2cbuf[3]; - - if (clearCommand()) { - _delay_ms(ENS160_BOOTING); - if (write8(ENS160_REG_COMMAND, ENS160_COMMAND_GET_APPVER)) { - if (readBytes(ENS160_REG_GPR_READ_4, i2cbuf, 3)) { - _fw_ver_major = i2cbuf[0]; - _fw_ver_minor = i2cbuf[1]; - _fw_ver_build = i2cbuf[2]; - _revENS16x = this->_fw_ver_major > 6 ? 1 : 0; - _delay_ms(ENS160_BOOTING); - return true; - } - } - } - _delay_ms(ENS160_BOOTING); - return false; -} - -// Set operation mode of sensor -bool ScioSense_ENS160::setMode (uint8_t mode) { - //LP only valid for rev>0 - if ((mode == ENS160_OPMODE_LP) and (_revENS16x == 0)) { - return false; - } - if (write8(ENS160_REG_OPMODE, mode)) { - _delay_ms(ENS160_BOOTING); - return true; - } - _delay_ms(ENS160_BOOTING); - return false; -} - -// Initialize definition of custom mode with steps -bool ScioSense_ENS160::initCustomMode (uint16_t stepNum) { - if (stepNum > 0) { - _stepCount = stepNum; - if (setMode(ENS160_OPMODE_IDLE)) { - if (clearCommand()) { - if (write8(ENS160_REG_COMMAND, ENS160_COMMAND_SETSEQ)) { - _delay_ms(ENS160_BOOTING); - return true; - } - } - } - } - _delay_ms(ENS160_BOOTING); - return false; -} - -// Add a step to custom measurement profile with definition of duration, enabled data acquisition and temperature for each hotplate -bool ScioSense_ENS160::addCustomStep (uint16_t time, bool measureHP0, bool measureHP1, bool measureHP2, bool measureHP3, uint16_t tempHP0, uint16_t tempHP1, uint16_t tempHP2, uint16_t tempHP3) { - uint8_t seq_ack; - uint8_t temp; - - _delay_ms(ENS160_BOOTING); - - temp = (uint8_t)(((time / 24) - 1) << 6); - if (measureHP0) { - temp = temp | 0x20; - } - if (measureHP1) { - temp = temp | 0x10; - } - if (measureHP2) { - temp = temp | 0x08; - } - if (measureHP3) { - temp = temp | 0x04; - } - if (!write8(ENS160_REG_GPR_WRITE_0, temp)) { - return false; - } - temp = (uint8_t)(((time / 24) - 1) >> 2); - if (!write8(ENS160_REG_GPR_WRITE_1, temp)) { - return false; - } - if (!write8(ENS160_REG_GPR_WRITE_2, (uint8_t)(tempHP0 / 2))) { - return false; - } - if (!write8(ENS160_REG_GPR_WRITE_3, (uint8_t)(tempHP1 / 2))) { - return false; - } - if (write8(ENS160_REG_GPR_WRITE_4, (uint8_t)(tempHP2 / 2))) { - return false; - } - if (write8(ENS160_REG_GPR_WRITE_5, (uint8_t)(tempHP3 / 2))) { - return false; - } - - if (write8(ENS160_REG_GPR_WRITE_6, (uint8_t)(_stepCount - 1))) { - return false; - } - - if (_stepCount == 1) { - if (!write8(ENS160_REG_GPR_WRITE_7, 128)) { - return false; - } - } else { - if (!write8(ENS160_REG_GPR_WRITE_7, 0)) { - return false; - } - } - _delay_ms(ENS160_BOOTING); - - if (!read8(ENS160_REG_GPR_READ_7, &seq_ack)) { - return false; - } - _delay_ms(ENS160_BOOTING); - - if ((ENS160_SEQ_ACK_COMPLETE | _stepCount) != seq_ack) { - _stepCount++; - return false; - } - - return true; -} - -bool ScioSense_ENS160::readStatus (uint8_t *status) { - return read8(ENS160_REG_DATA_STATUS, status); -} - -bool ScioSense_ENS160::readData (ENS160_DATA *data) { - uint8_t buffer[1] = { 0x21 }; - return i2cDevice.write_then_read(buffer, 1, (uint8_t *)data, sizeof(ENS160_DATA)); -} - -// Perform prediction measurement and stores result in internal variables -bool ScioSense_ENS160::measure (bool waitForNew) { - uint8_t i2cbuf[8]; - uint8_t status; - - // Set default status for early bail out - if (waitForNew) { - do { - if (!read8(ENS160_REG_DATA_STATUS, &status)) { - return false; - } - _delay_ms(1); - } while (!IS_NEWDAT(status)); - } else { - if (!read8(ENS160_REG_DATA_STATUS, &status)) { - return false; - } - } - - - // Read predictions - if (IS_NEWDAT(status)) { - if (!readBytes(ENS160_REG_DATA_AQI, i2cbuf, 7)) { - return false; - } - return false; - _data_aqi = i2cbuf[0]; - _data_tvoc = i2cbuf[1] | ((uint16_t)i2cbuf[2] << 8); - _data_eco2 = i2cbuf[3] | ((uint16_t)i2cbuf[4] << 8); - if (_revENS16x > 0) { - _data_aqi500 = ((uint16_t)i2cbuf[5]) | ((uint16_t)i2cbuf[6] << 8); - } else { - _data_aqi500 = 0; - } - return true; - } - - return false; -} - -// Perfrom raw measurement and stores result in internal variables -bool ScioSense_ENS160::measureRaw (bool waitForNew) { - uint8_t i2cbuf[8]; - uint8_t status; - - // Set default status for early bail out - if (waitForNew) { - do { - _delay_ms(1); - if (!read8(ENS160_REG_DATA_STATUS, &status)) { - return false; - } - } while (!IS_NEWGPR(status)); - } else { - if (!read8(ENS160_REG_DATA_STATUS, &status)) { - return false; - } - } - - if (IS_NEWGPR(status)) { - - // Read raw resistance values - if (!readBytes(ENS160_REG_GPR_READ_0, i2cbuf, 8)) { - return false; - } - _hp0_rs = CONVERT_RS_RAW2OHMS_F((uint32_t)(i2cbuf[0] | ((uint16_t)i2cbuf[1] << 8))); - _hp1_rs = CONVERT_RS_RAW2OHMS_F((uint32_t)(i2cbuf[2] | ((uint16_t)i2cbuf[3] << 8))); - _hp2_rs = CONVERT_RS_RAW2OHMS_F((uint32_t)(i2cbuf[4] | ((uint16_t)i2cbuf[5] << 8))); - _hp3_rs = CONVERT_RS_RAW2OHMS_F((uint32_t)(i2cbuf[6] | ((uint16_t)i2cbuf[7] << 8))); - - // Read baselines - if (!readBytes(ENS160_REG_DATA_BL, i2cbuf, 8)) { - return false; - } - _hp0_bl = CONVERT_RS_RAW2OHMS_F((uint32_t)(i2cbuf[0] | ((uint16_t)i2cbuf[1] << 8))); - _hp1_bl = CONVERT_RS_RAW2OHMS_F((uint32_t)(i2cbuf[2] | ((uint16_t)i2cbuf[3] << 8))); - _hp2_bl = CONVERT_RS_RAW2OHMS_F((uint32_t)(i2cbuf[4] | ((uint16_t)i2cbuf[5] << 8))); - _hp3_bl = CONVERT_RS_RAW2OHMS_F((uint32_t)(i2cbuf[6] | ((uint16_t)i2cbuf[7] << 8))); - - if (!read8(ENS160_REG_DATA_MISR, i2cbuf)) { - return false; - } - _misr = i2cbuf[0]; - return true; - } - - return false; -} - - -// Writes t (degC) and h (%rh) to ENV_DATA. Returns false on I2C problems. -bool ScioSense_ENS160::set_envdata (float t, float h) { - uint16_t t_data = (uint16_t)((t + 273.15f) * 64.0f); - uint16_t rh_data = (uint16_t)(h * 512.0f); - return this->set_envdata210(t_data, rh_data); -} - -// Writes t and h (in ENS210 format) to ENV_DATA. Returns false on I2C problems. -bool ScioSense_ENS160::set_envdata210 (uint16_t t, uint16_t h) { - //uint16_t temp; - uint8_t trh_in[4]; - - //temp = (uint16_t)((t + 273.15f) * 64.0f); - trh_in[0] = t & 0xff; - trh_in[1] = (t >> 8) & 0xff; - - //temp = (uint16_t)(h * 512.0f); - trh_in[2] = h & 0xff; - trh_in[3] = (h >> 8) & 0xff; - - if (!i2cDevice.writeByteAndBuffer(ENS160_REG_TEMP_IN, trh_in, 4)) { - return false; - } - - return true; -} diff --git a/software/nano-644/test_2024-07-23/src/adafruit/ens160.h b/software/nano-644/test_2024-07-23/src/adafruit/ens160.h deleted file mode 100644 index 7f26ba1..0000000 --- a/software/nano-644/test_2024-07-23/src/adafruit/ens160.h +++ /dev/null @@ -1,188 +0,0 @@ -/* - ScioSense_ENS160.h - Library for the ENS160 sensor with I2C interface from ScioSense - 2023 Mar 23 v6 Christoph Friese Bugfix measurement routine, prepare next release - 2021 July 29 v4 Christoph Friese Changed nomenclature to ScioSense as product shifted from ams - 2020 Apr 06 v3 Christoph Friese Changed nomenclature to ScioSense as product shifted from ams - 2020 Feb 15 v2 Giuseppe Pasetti Corrected firmware flash option - 2019 May 05 v1 Christoph Friese Created - based on application note "ENS160 Software Integration.pdf" rev 0.01 -*/ - -#ifndef __SCIOSENSE_ENS160_H_ -#define __SCIOSENSE_ENS160_H_ - -#include "../i2cmaster.hpp" -#include -// #define byte uint8_t - -// #if (ARDUINO >= 100) -// #include "Arduino.h" -// #else -// #include "WProgram.h" -// #endif - -// #include - -// Chip constants -#define ENS160_PARTID 0x0160 -#define ENS161_PARTID 0x0161 -#define ENS160_BOOTING 10 - -// 7-bit I2C slave address of the ENS160 -#define ENS160_I2CADDR_0 0x52 //ADDR low -#define ENS160_I2CADDR_1 0x53 //ADDR high - -// ENS160 registers for version V0 -#define ENS160_REG_PART_ID 0x00 // 2 byte register -#define ENS160_REG_OPMODE 0x10 -#define ENS160_REG_CONFIG 0x11 -#define ENS160_REG_COMMAND 0x12 -#define ENS160_REG_TEMP_IN 0x13 -#define ENS160_REG_RH_IN 0x15 -#define ENS160_REG_DATA_STATUS 0x20 -#define ENS160_REG_DATA_AQI 0x21 -#define ENS160_REG_DATA_TVOC 0x22 -#define ENS160_REG_DATA_ECO2 0x24 -#define ENS160_REG_DATA_BL 0x28 -#define ENS160_REG_DATA_T 0x30 -#define ENS160_REG_DATA_RH 0x32 -#define ENS160_REG_DATA_MISR 0x38 -#define ENS160_REG_GPR_WRITE_0 0x40 -#define ENS160_REG_GPR_WRITE_1 ENS160_REG_GPR_WRITE_0 + 1 -#define ENS160_REG_GPR_WRITE_2 ENS160_REG_GPR_WRITE_0 + 2 -#define ENS160_REG_GPR_WRITE_3 ENS160_REG_GPR_WRITE_0 + 3 -#define ENS160_REG_GPR_WRITE_4 ENS160_REG_GPR_WRITE_0 + 4 -#define ENS160_REG_GPR_WRITE_5 ENS160_REG_GPR_WRITE_0 + 5 -#define ENS160_REG_GPR_WRITE_6 ENS160_REG_GPR_WRITE_0 + 6 -#define ENS160_REG_GPR_WRITE_7 ENS160_REG_GPR_WRITE_0 + 7 -#define ENS160_REG_GPR_READ_0 0x48 -#define ENS160_REG_GPR_READ_4 ENS160_REG_GPR_READ_0 + 4 -#define ENS160_REG_GPR_READ_6 ENS160_REG_GPR_READ_0 + 6 -#define ENS160_REG_GPR_READ_7 ENS160_REG_GPR_READ_0 + 7 - -//ENS160 data register fields -#define ENS160_COMMAND_NOP 0x00 -#define ENS160_COMMAND_CLRGPR 0xCC -#define ENS160_COMMAND_GET_APPVER 0x0E -#define ENS160_COMMAND_SETTH 0x02 -#define ENS160_COMMAND_SETSEQ 0xC2 - -#define ENS160_OPMODE_RESET 0xF0 -#define ENS160_OPMODE_DEP_SLEEP 0x00 -#define ENS160_OPMODE_IDLE 0x01 -#define ENS160_OPMODE_STD 0x02 -#define ENS160_OPMODE_LP 0x03 -#define ENS160_OPMODE_CUSTOM 0xC0 - -#define ENS160_BL_CMD_START 0x02 -#define ENS160_BL_CMD_ERASE_APP 0x04 -#define ENS160_BL_CMD_ERASE_BLINE 0x06 -#define ENS160_BL_CMD_WRITE 0x08 -#define ENS160_BL_CMD_VERIFY 0x0A -#define ENS160_BL_CMD_GET_BLVER 0x0C -#define ENS160_BL_CMD_GET_APPVER 0x0E -#define ENS160_BL_CMD_EXITBL 0x12 - -#define ENS160_SEQ_ACK_NOTCOMPLETE 0x80 -#define ENS160_SEQ_ACK_COMPLETE 0xC0 - -#define IS_ENS160_SEQ_ACK_NOT_COMPLETE(x) (ENS160_SEQ_ACK_NOTCOMPLETE == (ENS160_SEQ_ACK_NOTCOMPLETE & (x))) -#define IS_ENS160_SEQ_ACK_COMPLETE(x) (ENS160_SEQ_ACK_COMPLETE == (ENS160_SEQ_ACK_COMPLETE & (x))) - -#define ENS160_DATA_STATUS_NEWDAT 0x02 -#define ENS160_DATA_STATUS_NEWGPR 0x01 - -#define IS_NEWDAT(x) (ENS160_DATA_STATUS_NEWDAT == (ENS160_DATA_STATUS_NEWDAT & (x))) -#define IS_NEWGPR(x) (ENS160_DATA_STATUS_NEWGPR == (ENS160_DATA_STATUS_NEWGPR & (x))) -#define IS_NEW_DATA_AVAILABLE(x) (0 != ((ENS160_DATA_STATUS_NEWDAT | ENS160_DATA_STATUS_NEWGPR ) & (x))) - -#define CONVERT_RS_RAW2OHMS_I(x) (1 << ((x) >> 11)) -#define CONVERT_RS_RAW2OHMS_F(x) (pow (2, (float)(x) / 2048)) - -typedef struct { - uint8_t aqi; - uint16_t tvoc; - uint16_t eco2; -} ENS160_DATA; - -class ScioSense_ENS160 { - - public: - ScioSense_ENS160(); - - void setI2C(uint8_t sda, uint8_t scl); // Function to redefine I2C pins - - bool begin(); // Init I2C communication, resets ENS160 and checks its PART_ID. Returns false on I2C problems or wrong PART_ID. - uint8_t revENS16x() { return this->_revENS16x; } // Report version of sensor (0: ENS160, 1: ENS161) - bool setMode(uint8_t mode); // Set operation mode of sensor - - bool initCustomMode(uint16_t stepNum); // Initialize definition of custom mode with steps - bool addCustomStep(uint16_t time, bool measureHP0, bool measureHP1, bool measureHP2, bool measureHP3, uint16_t tempHP0, uint16_t tempHP1, uint16_t tempHP2, uint16_t tempHP3); - // Add a step to custom measurement profile with definition of duration, enabled data acquisition and temperature for each hotplate - - bool readData (ENS160_DATA *data); - bool readStatus(uint8_t *status); - bool measure(bool waitForNew); // Perform measurement and stores result in internal variables - bool measureRaw(bool waitForNew); // Perform raw measurement and stores result in internal variables - bool set_envdata(float t, float h); // Writes t (degC) and h (%rh) to ENV_DATA. Returns "0" if I2C transmission is successful - bool set_envdata210(uint16_t t, uint16_t h); // Writes t and h (in ENS210 format) to ENV_DATA. Returns "0" if I2C transmission is successful - uint8_t getMajorRev() { return this->_fw_ver_major; } // Get major revision number of used firmware - uint8_t getMinorRev() { return this->_fw_ver_minor; } // Get minor revision number of used firmware - uint8_t getBuild() { return this->_fw_ver_build; } // Get build revision number of used firmware - - uint8_t getAQI() { return this->_data_aqi; } // Get AQI value of last measurement - uint16_t getTVOC() { return this->_data_tvoc; } // Get TVOC value of last measurement - uint16_t geteCO2() { return this->_data_eco2; } // Get eCO2 value of last measurement - uint16_t getAQI500() { return this->_data_aqi500; } // Get AQI500 value of last measurement - uint32_t getHP0() { return this->_hp0_rs; } // Get resistance of HP0 of last measurement - uint32_t getHP1() { return this->_hp1_rs; } // Get resistance of HP1 of last measurement - uint32_t getHP2() { return this->_hp2_rs; } // Get resistance of HP2 of last measurement - uint32_t getHP3() { return this->_hp3_rs; } // Get resistance of HP3 of last measurement - uint32_t getHP0BL() { return this->_hp0_bl; } // Get baseline resistance of HP0 of last measurement - uint32_t getHP1BL() { return this->_hp1_bl; } // Get baseline resistance of HP1 of last measurement - uint32_t getHP2BL() { return this->_hp2_bl; } // Get baseline resistance of HP2 of last measurement - uint32_t getHP3BL() { return this->_hp3_bl; } // Get baseline resistance of HP3 of last measurement - uint8_t getMISR() { return this->_misr; } // Return status code of sensor - - private: - I2cMaster i2cDevice; - bool reset(); // Sends a reset to the ENS160. Returns false on I2C problems. - bool checkPartID(); // Reads the part ID and confirms valid sensor - bool clearCommand(); // Initialize idle mode and confirms - bool getFirmware(); // Read firmware revisions - - uint8_t _revENS16x; // ENS160 or ENS161 connected? (FW >7) - - uint8_t _fw_ver_major; - uint8_t _fw_ver_minor; - uint8_t _fw_ver_build; - - uint16_t _stepCount; // Counter for custom sequence - - uint8_t _data_aqi; - uint16_t _data_tvoc; - uint16_t _data_eco2; - uint16_t _data_aqi500; - uint32_t _hp0_rs; - uint32_t _hp0_bl; - uint32_t _hp1_rs; - uint32_t _hp1_bl; - uint32_t _hp2_rs; - uint32_t _hp2_bl; - uint32_t _hp3_rs; - uint32_t _hp3_bl; - uint16_t _temp; - int _slaveaddr; // Slave address of the ENS160 - uint8_t _misr; - - uint8_t _seq_steps[1][8]; - - bool write8(uint8_t reg, uint8_t value); - bool read8 (uint8_t reg, uint8_t *value); - bool read16 (uint8_t reg, uint16_t *value); - bool read16LE (uint8_t reg, uint16_t *value); - bool readBytes (uint8_t reg, uint8_t *bytes, uint8_t len); -}; - - -#endif diff --git a/software/nano-644/test_2024-07-23/src/adafruit/sensor.h b/software/nano-644/test_2024-07-23/src/adafruit/sensor.h deleted file mode 100644 index ac7e454..0000000 --- a/software/nano-644/test_2024-07-23/src/adafruit/sensor.h +++ /dev/null @@ -1,224 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software< /span> - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* Update by K. Townsend (Adafruit Industries) for lighter typedefs, and - * extended sensor support to include color, voltage and current */ - -#ifndef _ADAFRUIT_SENSOR_H -#define _ADAFRUIT_SENSOR_H - -#ifndef ARDUINO -#include -#elif ARDUINO >= 100 -#include "Arduino.h" -#include "Print.h" -#else -#include "WProgram.h" -#endif - -/* Constants */ -#define SENSORS_GRAVITY_EARTH (9.80665F) /**< Earth's gravity in m/s^2 */ -#define SENSORS_GRAVITY_MOON (1.6F) /**< The moon's gravity in m/s^2 */ -#define SENSORS_GRAVITY_SUN (275.0F) /**< The sun's gravity in m/s^2 */ -#define SENSORS_GRAVITY_STANDARD (SENSORS_GRAVITY_EARTH) -#define SENSORS_MAGFIELD_EARTH_MAX \ - (60.0F) /**< Maximum magnetic field on Earth's surface */ -#define SENSORS_MAGFIELD_EARTH_MIN \ - (30.0F) /**< Minimum magnetic field on Earth's surface */ -#define SENSORS_PRESSURE_SEALEVELHPA \ - (1013.25F) /**< Average sea level pressure is 1013.25 hPa */ -#define SENSORS_DPS_TO_RADS \ - (0.017453293F) /**< Degrees/s to rad/s multiplier \ - */ -#define SENSORS_RADS_TO_DPS \ - (57.29577793F) /**< Rad/s to degrees/s multiplier */ -#define SENSORS_GAUSS_TO_MICROTESLA \ - (100) /**< Gauss to micro-Tesla multiplier */ - -/** Sensor types */ -typedef enum { - SENSOR_TYPE_ACCELEROMETER = (1), /**< Gravity + linear acceleration */ - SENSOR_TYPE_MAGNETIC_FIELD = (2), - SENSOR_TYPE_ORIENTATION = (3), - SENSOR_TYPE_GYROSCOPE = (4), - SENSOR_TYPE_LIGHT = (5), - SENSOR_TYPE_PRESSURE = (6), - SENSOR_TYPE_PROXIMITY = (8), - SENSOR_TYPE_GRAVITY = (9), - SENSOR_TYPE_LINEAR_ACCELERATION = - (10), /**< Acceleration not including gravity */ - SENSOR_TYPE_ROTATION_VECTOR = (11), - SENSOR_TYPE_RELATIVE_HUMIDITY = (12), - SENSOR_TYPE_AMBIENT_TEMPERATURE = (13), - SENSOR_TYPE_OBJECT_TEMPERATURE = (14), - SENSOR_TYPE_VOLTAGE = (15), - SENSOR_TYPE_CURRENT = (16), - SENSOR_TYPE_COLOR = (17), - SENSOR_TYPE_TVOC = (18), - SENSOR_TYPE_VOC_INDEX = (19), - SENSOR_TYPE_NOX_INDEX = (20), - SENSOR_TYPE_CO2 = (21), - SENSOR_TYPE_ECO2 = (22), - SENSOR_TYPE_PM10_STD = (23), - SENSOR_TYPE_PM25_STD = (24), - SENSOR_TYPE_PM100_STD = (25), - SENSOR_TYPE_PM10_ENV = (26), - SENSOR_TYPE_PM25_ENV = (27), - SENSOR_TYPE_PM100_ENV = (28), - SENSOR_TYPE_GAS_RESISTANCE = (29), - SENSOR_TYPE_UNITLESS_PERCENT = (30), - SENSOR_TYPE_ALTITUDE = (31) -} sensors_type_t; - -/** struct sensors_vec_s is used to return a vector in a common format. */ -typedef struct { - union { - float v[3]; ///< 3D vector elements - struct { - float x; ///< X component of vector - float y; ///< Y component of vector - float z; ///< Z component of vector - }; ///< Struct for holding XYZ component - /* Orientation sensors */ - struct { - float roll; /**< Rotation around the longitudinal axis (the plane body, 'X - axis'). Roll is positive and increasing when moving - downward. -90 degrees <= roll <= 90 degrees */ - float pitch; /**< Rotation around the lateral axis (the wing span, 'Y - axis'). Pitch is positive and increasing when moving - upwards. -180 degrees <= pitch <= 180 degrees) */ - float heading; /**< Angle between the longitudinal axis (the plane body) - and magnetic north, measured clockwise when viewing from - the top of the device. 0-359 degrees */ - }; ///< Struct for holding roll/pitch/heading - }; ///< Union that can hold 3D vector array, XYZ components or - ///< roll/pitch/heading - int8_t status; ///< Status byte - uint8_t reserved[3]; ///< Reserved -} sensors_vec_t; - -/** struct sensors_color_s is used to return color data in a common format. */ -typedef struct { - union { - float c[3]; ///< Raw 3-element data - /* RGB color space */ - struct { - float r; /**< Red component */ - float g; /**< Green component */ - float b; /**< Blue component */ - }; ///< RGB data in floating point notation - }; ///< Union of various ways to describe RGB colorspace - uint32_t rgba; /**< 24-bit RGBA value */ -} sensors_color_t; - -/* Sensor event (36 bytes) */ -/** struct sensor_event_s is used to provide a single sensor event in a common - * format. */ -typedef struct { - int32_t version; /**< must be sizeof(struct sensors_event_t) */ - int32_t sensor_id; /**< unique sensor identifier */ - int32_t type; /**< sensor type */ - int32_t reserved0; /**< reserved */ - int32_t timestamp; /**< time is in milliseconds */ - union { - float data[4]; ///< Raw data */ - sensors_vec_t acceleration; /**< acceleration values are in meter per second - per second (m/s^2) */ - sensors_vec_t - magnetic; /**< magnetic vector values are in micro-Tesla (uT) */ - sensors_vec_t orientation; /**< orientation values are in degrees */ - sensors_vec_t gyro; /**< gyroscope values are in rad/s */ - float temperature; /**< temperature is in degrees centigrade (Celsius) */ - float distance; /**< distance in centimeters */ - float light; /**< light in SI lux units */ - float pressure; /**< pressure in hectopascal (hPa) */ - float relative_humidity; /**< relative humidity in percent */ - float current; /**< current in milliamps (mA) */ - float voltage; /**< voltage in volts (V) */ - float tvoc; /**< Total Volatile Organic Compounds, in ppb */ - float voc_index; /**< VOC (Volatile Organic Compound) index where 100 is - normal (unitless) */ - float nox_index; /**< NOx (Nitrogen Oxides) index where 100 is normal - (unitless) */ - float CO2; /**< Measured CO2 in parts per million (ppm) */ - float eCO2; /**< equivalent/estimated CO2 in parts per million (ppm - estimated from some other measurement) */ - float pm10_std; /**< Standard Particulate Matter <=1.0 in parts per million - (ppm) */ - float pm25_std; /**< Standard Particulate Matter <=2.5 in parts per million - (ppm) */ - float pm100_std; /**< Standard Particulate Matter <=10.0 in parts per - million (ppm) */ - float pm10_env; /**< Environmental Particulate Matter <=1.0 in parts per - million (ppm) */ - float pm25_env; /**< Environmental Particulate Matter <=2.5 in parts per - million (ppm) */ - float pm100_env; /**< Environmental Particulate Matter <=10.0 in parts per - million (ppm) */ - float gas_resistance; /**< Proportional to the amount of VOC particles in - the air (Ohms) */ - float unitless_percent; /** -#include -#include - -#include "i2cmaster.hpp" - -I2cMaster::I2cMaster () { - address = 0; - timer = 0; -} - -void I2cMaster::tick1ms () { - if (timer > 0) { - timer--; - } -} - -bool I2cMaster::begin (uint8_t addr) { - this->address = addr; - // TWBR = 13; // 100kHz (TWPS1:0 = 00), TWBR = (F_CPU - 16 * 100000) / (2 * 100000 * 4); - TWBR = 100; // 50kHz (TWPS1:0 = 00), TWBR = (F_CPU - 16 * 50000) / (2 * 50000 * 4); - TWCR = (1 << TWEN); - return true; -} - -void I2cMaster::end () { - TWCR = (1 << TWEN); - TWBR = 0; -} - -bool I2cMaster::read (uint8_t *buffer, uint8_t len) { - if (start(true)) { - if (readBytes(buffer, len)) { - if (stop()) { - return true; - } - } - } - return false; -} - - -bool I2cMaster::write (const uint8_t *buffer, uint8_t len) { - if (start(false)) { - if (writeBytes(buffer, len, false)) { - if (stop()) { - return true; - } - } - } - return false; -} - -bool I2cMaster::write_P (const uint8_t *buffer, uint8_t len) { - if (start(false)) { - if (writeBytes(buffer, len, true)) { - if (stop()) { - return true; - } - } - } - return false; -} - - -bool I2cMaster::writeByteAndBuffer (uint8_t byte, const uint8_t *buffer, uint8_t len) { - if (start(false)) { - do { - TWDR = byte; - TWCR = (1 << TWINT) | (1 << TWEN); // send byte - while (!(TWCR & (1 << TWINT))) {}; // wait until last action done - if ((TWSR & 0xf8) != 0x28) { - return false; - } - byte = *buffer++; - } while (len-- > 0); - return true; - } - return false; -} - - -bool I2cMaster::write_then_read (const uint8_t *write_buffer, uint8_t write_len, uint8_t *read_buffer, uint8_t read_len) { - if (start(false)) { - if (writeBytes(write_buffer, write_len, false)) { - if (start(true)) { - if (readBytes(read_buffer, read_len)) { - if (stop()) { - return true; - } - } - } - } - } - return false; -} - -// ------------------------------------------------------------- - -bool I2cMaster::readBytes (uint8_t *buffer, uint8_t len) { - while (len-- > 0) { - if (len > 0) { - TWCR = (1 << TWEA) | (1 << TWINT) | (1 << TWEN); // read data byte with ACK enabled - } else { - TWCR = (1 << TWINT) | (1 << TWEN); // read data byte with ACK disabled - } - while (!(TWCR & (1 << TWINT))) {}; // wait until last action done - uint8_t sr = TWSR & 0xf8; - if ((len > 0 && sr != 0x50) || (len == 0 && sr != 0x58)) { - return false; - } - *buffer++ = TWDR; - } - return true; -} - -bool I2cMaster::writeBytes (const uint8_t *buffer, uint8_t len, bool fromFlash) { - while (len-- > 0) { - // printf_P(PSTR("[wB:len=%d, byte=%02x]"), len + 1, *buffer); - TWDR = fromFlash ? pgm_read_byte(buffer++) : *buffer++; - TWCR = (1 << TWINT) | (1 << TWEN); // send data byte - timer = 5; - while (timer > 0 && !(TWCR & (1 << TWINT))) {}; // wait until last action done - if (!timer || (TWSR & 0xf8) != 0x28) { - return false; - } - } - return true; -} - -bool I2cMaster::start (bool read) { - TWCR = (1 << TWINT) | (1 << TWSTA) | (1 << TWEN); // send START condition - timer = 5; - while (timer > 0 && !(TWCR & (1 << TWINT))) {}; // wait until last action done - uint8_t sr = TWSR & 0xf8; - if (!timer || (sr != 0x08 && sr != 0x10)) { - return false; - } - TWDR = (address << 1) | (read ? 1 : 0); // address + R/nW - TWCR = (1 << TWINT) | (1 << TWEN); // send address/RW - timer = 5; - while (timer > 0 && !(TWCR & (1 << TWINT))) {}; // wait until last action done - sr = TWSR & 0xf8; - if (!timer || (!read && sr != 0x18) || (read && sr != 0x40)) { - return false; - } - return true; -} - -bool I2cMaster::stop () { - TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWSTO); - while (TWCR & ( 1 << TWSTO)); - return true; -} - diff --git a/software/nano-644/test_2024-07-23/src/i2cmaster.hpp b/software/nano-644/test_2024-07-23/src/i2cmaster.hpp deleted file mode 100644 index 89b1e46..0000000 --- a/software/nano-644/test_2024-07-23/src/i2cmaster.hpp +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef I2C_MASTER -#define I2C_MASTER - -#include - -class I2cMaster { - public: - static void end (); - - public: - I2cMaster (); - void tick1ms (); - bool begin (uint8_t addr); - bool read (uint8_t *buffer, uint8_t len); - bool write (const uint8_t *buffer, uint8_t len); - bool write_P (const uint8_t *buffer, uint8_t len); - bool write_then_read (const uint8_t *write_buffer, uint8_t write_len, uint8_t *read_buffer, uint8_t read_len); - bool writeByteAndBuffer (uint8_t byte, const uint8_t *buffer, uint8_t len); - - private: - uint8_t address; - uint8_t timer; - bool start (bool read); - bool stop (); - bool writeBytes (const uint8_t *buffer, uint8_t len, bool fromFlash); - bool writeBytes_P (const uint8_t *buffer); - bool readBytes (uint8_t *buffer, uint8_t len); -}; - -#endif \ No newline at end of file diff --git a/software/nano-644/test_2024-07-23/src/i2cslave.cpp b/software/nano-644/test_2024-07-23/src/i2cslave.cpp deleted file mode 100644 index 2bf6ac2..0000000 --- a/software/nano-644/test_2024-07-23/src/i2cslave.cpp +++ /dev/null @@ -1,92 +0,0 @@ -#include -#include -#include - -#include "i2cslave.hpp" - -I2cSlave::I2cSlave () { - timer = 0; - fromMaster.rIndex = 0; - fromMaster.wIndex = 0; - toMaster.rIndex = 0; - toMaster.wIndex = 0; -} - -void I2cSlave::tick1ms () { - if (timer > 0) { - timer--; - } -} - -bool I2cSlave::begin (uint8_t addr, bool acceptGeneralCalls) { - if (addr > 127) { - return false; - } - TWAR = addr << 1 | (acceptGeneralCalls ? 1 : 0); - TWBR = 100; // 50kHz (TWPS1:0 = 00), TWBR = (F_CPU - 16 * 50000) / (2 * 50000 * 4); - TWCR = (1 << TWEA) | (1 << TWEN) | (1 << TWIE); - return true; -} - -void I2cSlave::end () { - TWCR = (1 << TWEN); - TWBR = 0; -} - -int I2cSlave::read () { - return getByte(fromMaster); -} - -void I2cSlave::write (uint8_t byte) { - putByte(toMaster, byte); -} - - -void I2cSlave::putByte (RingBuffer& buffer, uint8_t byte) { - ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { - buffer.data[buffer.wIndex++] = byte; - if (buffer.wIndex >= sizeof(buffer.data)) { - buffer.wIndex = 0; - } - if (buffer.wIndex == buffer.rIndex) { - buffer.rIndex++; - if (buffer.rIndex >= sizeof(buffer.data)) { - buffer.rIndex = 0; - } - } - } -} - -int I2cSlave::getByte (RingBuffer& buffer) { - uint8_t b; - ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { - if (buffer.rIndex == buffer.wIndex) { - return EOF; - } - b = buffer.data[buffer.rIndex++]; - if (buffer.rIndex >= sizeof(buffer.data)) { - buffer.rIndex = 0; - } - } - return b; -} - -void I2cSlave::handleTWIIsr () { - uint8_t sr = TWSR & 0xf8; - switch (sr) { - case 0x80: { // Previously addressed with own SLA+W; data has been received; ACK has been returned - putByte(fromMaster, TWDR); - TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWIE); // no TWEA -> only one byte accepted - break; - } - case 0xa8: { // Own SLA+R has been received; ACK has been returned - int response = getByte(toMaster);; - TWDR = response < 0 ? 0x00 : (uint8_t)response; - TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWIE); // no TWEA -> only one byte accepted - break; - } - default: TWCR = (1 << TWINT) | (1 << TWEA) | (1 << TWEN) | (1 << TWIE); break; - } - -} - diff --git a/software/nano-644/test_2024-07-23/src/i2cslave.hpp b/software/nano-644/test_2024-07-23/src/i2cslave.hpp deleted file mode 100644 index 2fe2dc7..0000000 --- a/software/nano-644/test_2024-07-23/src/i2cslave.hpp +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef I2C_SLAVE -#define I2C_SLAVE - -#include - -class I2cSlave { - private: - typedef struct { - uint8_t rIndex; - uint8_t wIndex; - uint8_t data[8]; - } RingBuffer; - - public: - I2cSlave (); - void tick1ms (); - bool begin (uint8_t addr, bool acceptGeneralCalls); - void end (); - void handleTWIIsr (); - int read (); - void write (uint8_t byte); - - private: - uint8_t timer; - RingBuffer fromMaster; - RingBuffer toMaster; - void putByte (RingBuffer& buffer, uint8_t byte); - int getByte (RingBuffer& buffer); - -}; - -#endif \ No newline at end of file diff --git a/software/nano-644/test_2024-07-23/src/main.cpp b/software/nano-644/test_2024-07-23/src/main.cpp deleted file mode 100644 index 2971b6e..0000000 --- a/software/nano-644/test_2024-07-23/src/main.cpp +++ /dev/null @@ -1,361 +0,0 @@ -#include -#include -#include -#include - -#include -#include - -#include "main.hpp" -#include "units/encoder.hpp" -#include "units/i2c.hpp" -#include "units/led.hpp" -#include "units/ieee485.hpp" -#include "units/led.hpp" -#include "units/lcd.hpp" -#include "units/switch.hpp" -#include "units/rgb.hpp" -#include "units/seg7.hpp" -#include "units/poti.hpp" -#include "units/r2r.hpp" -#include "units/motor.hpp" -#include "units/portexp.hpp" -#include "units/uart1.hpp" -#include "units/modbus.hpp" -#include "units/rtc8563.hpp" -#include "units/cc1101.hpp" - -const char MAIN_CPP_DATE[] PROGMEM = __DATE__; -const char MAIN_CPP_TIME[] PROGMEM = __TIME__; -#ifdef __AVR_ATmega328P__ - const char MAIN_CPP_PART_NAME[] PROGMEM = "ATmega328P"; -#endif -#ifdef __AVR_ATmega644P__ - const char MAIN_CPP_PART_NAME[] PROGMEM = "ATmega644P"; -#endif -#ifdef __AVR_ATmega1284P__ - const char MAIN_CPP_PART_NAME[] PROGMEM = "ATmega1284P"; -#endif - -const char PSTR_DIVIDER[] PROGMEM = "\n====================================\n "; -const char PSTR_LINEFEED[] PROGMEM = "\n"; -const char PSTR_ERROR[] PROGMEM = "ERROR"; -const char PSTR_Done[] PROGMEM = "Done"; - -extern "C" { - void __cxa_pure_virtual () {} - int __cxa_guard_acquire(uint8_t *g) { return 0; } - void __cxa_guard_release(uint8_t *g) {} - void __cxa_guard_abort(uint8_t *g) {} - void __gxx_personality_sj0 () {} - void __cxa_rethrow () {} - void __cxa_begin_catch () {} - void __cxa_end_catch () {} - - int uart_putchar(char c, FILE *stream) { - if (c == '\n') { - uart_putchar('\r', stream); - } - if (stream == stdout) { - loop_until_bit_is_set(UCSR0A, UDRE0); - UDR0 = c; - } - return 0; - } - - - uint64_t volatile systemMillis = 0; - uint8_t volatile uartBuffer[32]; - uint8_t volatile rIndex = 0; - uint8_t volatile wIndex = 0; - - int uart_getchar (FILE *stream) { - // if (rIndex == wIndex) { - // // nothing in buffer - // return EOF; - // } - // printf_P(PSTR(" r%d"), rIndex); - while (rIndex == wIndex) { - // wait for character - } - - // don't use "char c" because german special characters would lead to negative return -> stream error - // char c = uartBuffer[rIndex++]; - - uint8_t c = uartBuffer[rIndex++]; - // printf_P(PSTR("(%02x) "), c); - if (c == '\r') { - c = '\n'; - } - putchar(c); // echo on terminal - return c; - } - - static FILE mystdout = { 0, 0, _FDEV_SETUP_WRITE , 0, 0, uart_putchar, NULL, 0 }; - static FILE mystdin = { 0, 0, _FDEV_SETUP_READ , 0, 0, NULL, uart_getchar, 0 }; - - #if defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__) - static volatile uint16_t timerFlashGreenLed = 0; - static volatile uint16_t timerFlashRedLed = 0; - void flashRedLed (uint16_t ms) { - ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { - if (timerFlashRedLed == 0) { - PORTC |= (1 << PC2); - if (ms < 0xff80) { - ms += 0x80; // at least 128ms OFF after - } - timerFlashRedLed = ms; - } - } - } - void flashGreenLed (uint16_t ms) { - ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { - if (timerFlashGreenLed == 0) { - PORTC |= (1 << PC4); - if (ms < 0xff80) { - ms += 0x80; // at least 128ms OFF after - } - timerFlashGreenLed = ms; - } - } - } - #endif - - static volatile uint32_t timer1ms = 0; - static volatile int keyUart0 = EOF; - - Led led; - Switch sw; - Rgb rgb; - Seg7 seg7; - Poti poti; - Encoder encoder; - R2r r2r; - Motor motor; - PortExp portExp; - Lcd lcd; - Uart1 uart1; - Modbus modbus; - Ieee485 ieee485; - I2c i2cSparkfun(I2c::SparkFunEnvCombo); - I2c i2cMaster(I2c::Master); - I2c i2cSlave(I2c::Slave); - Rtc8563 rtc8563(Rtc8563::NORMAL); - Cc1101 cc1101Send(Cc1101::Send); - Cc1101 cc1101Receive(Cc1101::Receive); -} - -void setTimer (uint32_t ms) { - ATOMIC_BLOCK(ATOMIC_FORCEON) { - timer1ms = ms; - } -} - -int wait (uint32_t ms) { - setTimer(ms); - do { - ATOMIC_BLOCK(ATOMIC_FORCEON) { - ms = timer1ms; - } - } while (ms > 0 && keyUart0 == EOF); - return keyUart0; -} - -int waitAndReadKey (uint32_t ms) { - keyUart0 = EOF; - int key = wait(ms); - keyUart0 = EOF; - return key; -} - -int main () { - - #if defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__) - // Nano-644 LEDs (Green, Orange, Red) - DDRC |= (1 << PC7) | (1 << PC4) | (1 << PC3) | (1 << PC2); - PORTC &= ~((1 << PC7) | (1 << PC4) | (1 << PC3) | (1 << PC2)); - - // Nano-644 push button SW2 - DDRC &= ~(1 << PC5); - PORTC |= (1 << PC5); // enable internal pullup resistor - #endif - - #ifdef __AVR_ATmega328P__ - DDRB |= (1 << PB5); - PORTB &= ~(1 << PB5); - #endif - - // UART0 interface on Nano-644 - UCSR0A = (1 << U2X0); - UCSR0B = (1 << RXCIE0) | (1 << RXEN0) | (1 <getName()); - printf_P(PSTR_LINEFEED); - } - printf_P(PSTR("\nSelect unit: ")); - rIndex = 0; wIndex = 0; - fgets(s, sizeof(s), stdin); - } while (sscanf(s, "%x", &i) != 1 || i < 0 || i >= sizeof(unit) / sizeof(unit[0]) ); - - TestUnit *pu = unit[i]; - printf_P(PSTR("\n\n[")); printf_P(pu->getName()); printf_P(PSTR("]: ")); - keyUart0 = EOF; - - pu->init(); - for (uint8_t subtest = 0; subtest < 0xff; subtest++) { - printf_P(PSTR("\n%4d: "), subtest); - if (pu->run(subtest) < 0) { - break; - } - if (keyUart0 == 27) { - keyUart0 = EOF; - break; - } - keyUart0 = EOF; - } - pu->cleanup(); - } -} - -uint64_t millis () { - volatile uint64_t millis = systemMillis; - ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { - millis = systemMillis; - } - return millis; -} - -#ifndef USART0_RX_vect - #define USART0_RX_vect USART_RX_vect -#endif -ISR (USART0_RX_vect) { - uint8_t b = UDR0; - keyUart0 = b; - uartBuffer[wIndex++] = b; - // printf_P(PSTR(" w%d(%02x)"), wIndex, b); - if (wIndex == rIndex) { - // buffer overflow, kick out oldest byte - rIndex++; - } -} - -#ifdef USART1_RX_vect - ISR (USART1_RX_vect) { - uint8_t b = UDR1; - if (modbus.enabled) { - modbus.handleRxByte(b); - } - if (uart1.enabled) { - uart1.handleRxByte(b); - } - if (ieee485.enabled) { - ieee485.handleRxByte(b); - } - } -#endif - -ISR (TWI_vect) { - if (i2cMaster.enabled) { - i2cMaster.handleTwiIrq(); - } else if (i2cSlave.enabled) { - i2cSlave.handleTwiIrq(); - } else if (i2cSparkfun.enabled) { - i2cSparkfun.handleTwiIrq(); - } else { - TWCR = (1 << TWINT); // clear interrupt request bit and disable TWI - } -} - -ISR (TIMER2_COMPA_vect) { // every 100us - static uint16_t timer500ms = 0; - static uint8_t timer100us = 0; - - if (encoder.enabled) { - encoder.tick100us(); - } - if (motor.enabled) { - motor.tick100us(); - } - - timer100us++; - if (timer100us >= 10) { - timer100us = 0; - if (timer1ms > 0) { - timer1ms--; - } - systemMillis++; - i2cMaster.tick1ms(); - i2cSlave.tick1ms(); - i2cSparkfun.tick1ms(); - cc1101Send.tick1ms(); - cc1101Receive.tick1ms(); - #if defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__) - if (timerFlashRedLed > 0) { - if (--timerFlashRedLed < 128) { - PORTC &= ~(1 << PC2); // red LED - } - } - if (timerFlashGreenLed > 0) { - if (--timerFlashGreenLed < 128 ) { - PORTC &= ~(1 << PC4); // green LED - } - } - #endif - } - - timer500ms++; - if (timer500ms >= 5000) { - #if defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__) - PORTC ^= (1 << PC3); // orange LED blinking - #endif - #ifdef __AVR_ATmega328P__ - if (!seg7.enabled) { - PORTB ^= (1 << PB5); // LED L - } - #endif - timer500ms = 0; - } -} - diff --git a/software/nano-644/test_2024-07-23/src/main.hpp b/software/nano-644/test_2024-07-23/src/main.hpp deleted file mode 100644 index a7f2ae8..0000000 --- a/software/nano-644/test_2024-07-23/src/main.hpp +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef MAIN_HPP -#define MAIN_HPP - -#include -#include - -#define ENTER '\r' -#define CTRLC '\003' -#define ESCAPE 0x1b - -extern int wait (uint32_t ms); -extern int waitAndReadKey (uint32_t ms); -extern uint64_t millis (); - -extern const char PSTR_DIVIDER[]; -extern const char PSTR_LINEFEED[]; -extern const char PSTR_ERROR[]; -extern const char PSTR_Done[]; - -#if defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__) - extern "C" { - extern void flashRedLed (uint16_t ms); - extern void flashGreenLed (uint16_t ms); - } -#endif - - -class TestUnit { - public: - virtual int8_t run (uint8_t subtest) = 0; - virtual void init () = 0; - virtual void cleanup () = 0; - virtual PGM_P getName () = 0; -}; - -#endif \ No newline at end of file diff --git a/software/nano-644/test_2024-07-23/src/units/cc1101.cpp b/software/nano-644/test_2024-07-23/src/units/cc1101.cpp deleted file mode 100644 index d53ecf2..0000000 --- a/software/nano-644/test_2024-07-23/src/units/cc1101.cpp +++ /dev/null @@ -1,741 +0,0 @@ -#include -#include -#include -#include - -#include "cc1101.hpp" -#include "../main.hpp" - -// 868MHz Modem E07-900MM1DS (chipset CC1101) -// https://jlcpcb.com/partdetail/Chengdu_Ebyte_ElecTech-E07900MM10S/C5844212 - -#ifdef __AVR_ATmega328P__ - - // Arduino-Nano-5V - // ------------------------------------ - // not available - - void Cc1101::init () {} - void Cc1101::cleanup () {} - void Cc1101::setChipEnableLow () {} - void Cc1101::setChipEnableHigh () {} - int8_t Cc1101::run (uint8_t subtest) { return -1; } - PGM_P Cc1101::getName () { return PSTR("?"); } - -#endif - - -#if defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__) - - // Nano-644 - // -------------------------------------------------------- - // PA4 ... nCS - // PB4 ... nSS (not used, but must be high, otherwise AVR SPI master not working) - // PB5 ... MOSI - // PB6 ... MISO - // PB7 ... SCK - - // -------------------------------------------------------- - - // Output power table from CC1101 datasheet page 59 - const Cc1101::PATABLE_INIT_ITEM_t PMEM_CC1101_PATABLE_INIT[] PROGMEM = { - { 0xc6, "9.6" }, // 9.6 dBm / 29.4mA (default value) - { 0xc0, "11" }, // 11 dBm / 34.2mA - { 0xc5, "10" }, // 10 dBm / 30.0mA - { 0xcd, "7" }, // 7 dBm / 25.8mA - { 0x86, "5" }, // 5 dBm / 19.9mA - { 0x50, "0" }, // 0 dBm / 16.8mA - { 0x37, "-6" }, // -6 dBm / 16.4mA - { 0x26, "-10" }, // 10 dBm / 14.5mA - { 0x1d, "-15" }, // 15 dBm / 13.3mA - { 0x17, "-20" }, // 20 dBm / 12.6mA - { 0x03, "-30" }, // 30 dBm / 12.0mA - }; - const Cc1101::Register_t PMEM_CC1101_REGISTER_INIT PROGMEM = { - /* 0x00: iocfg2 0x0b (----) */ { Cc1101::CHIP_NOT_READY, 0, 0 }, // GDO2 - /* 0x01: iocfg1 0x2e (----) */ { Cc1101::HIGH_IMPEDANCE_WHEN_CHIP_SELECT_HIGH, 0, 0 }, // GDO1/MISO - /* 0x02: iocfg0 0x06 (----) */ { Cc1101::SYNC_SENT_OR_RECEIVED_UNTIL_END_OF_PACKET, 0, 0 }, // GDO0 -> PA5 - /* 0x03: fifothr 0x47 (0x07) */ { 7, 0, 1, 0 }, // fifo_thr = 0b111, close_in_rx=0, adc_retention = 1, (bit7=0) - /* 0x04: sync1 0x7a (0xd3) */ 0x7a, - /* 0x05: sync0 0x0e (0x91) */ 0x0e, - /* 0x06: pktlen 0x14 (0x3d) */ PACKET_LENGTH, - /* 0x07: pktctrl1 0x04 (----) */ { Cc1101::NO_ADDR_CHECK, 1, 0, 0, 0 }, // adr_chk=0b00, append_status=1, crc_autoflush=0, (bit4=0), pqt=0b000 - /* 0x08: pktctrl0 0x05 (----) */ { Cc1101::FIXED, 1, 0, Cc1101::NORMAL_USE_FIFO, 0, 0 }, // length_config=0b01, crc_en=1, (bit3=0), pkt_format=0b00, white_data=0, (bit7=0) - /* 0x09: addr 0x00 (----) */ 0x00, - /* 0x0a: channr 0x00 (----) */ 0x00, - /* 0x0b: fsctrl1 0x06 (0x08) */ { 6, 0, 0 }, // frqu_if=6, (bit5=0), (bit76=0b00) - /* 0x0c: fsctrl0 0x00 (----) */ { 0 }, // freqoff = 0 - /* 0x0d: frequ2 0x21 (----) */ 0x21, - /* 0x0e: frequ1 0x62 (----) */ 0x62, - /* 0x0f: frequ0 0x76 (----) */ 0x76, - /* 0x10: mdmcfg4 0xca (0x5b) */ { 0x0a, 0, 3 }, // drate_e=0x0a, chanbw_m=0, chanbw_e=3 - /* 0x11: mdmcfg3 0xf8 (----) */ { 0xf8 }, // drate_m=0xf8 - /* 0x12: mdmcfg2 0x16 (0x03) */ { Cc1101::SYNC_16_16_CARRIER_SENSE, 0, Cc1101::GFSK, 0}, // sync_mode=0b110, manchester_en=0, mod_format=0b001, dem_dcfilt_off=0 - /* 0x13: mdmcfg1 0x22 (----) */ { 2, 0, Cc1101::FOUR, 0 }, // chanspc_e=0b10, bit32=0, num_preamble=0b010, fec_en=0 - /* 0x14: mdmcfg0 0xf8 (----) */ { 0xf8 }, // chanspc_m = 0x08 - /* 0x15: deviatn 0x40 (0x47) */ { 0, 0, 4, 0 }, // deviation_m=0, (bit3=0), deviation_e=4, (bit7=0) - /* 0x16: mcsm2 0x07 (----) */ { 7, 0, 0, 0 }, // rx_time=7 (NA), rx_time_qual=0, rx_time_rssi=0, (bit76=0b00) - /* 0x17: mcsm1 0x30 (----) */ { Cc1101::TXOFF_IDLE, Cc1101::RXOFF_IDLE, Cc1101::RSSI_BELOW_THRESHOLD__UNLESS_RECEIVE_PACKET, 0 }, // mcsm1 (txoff_mode=0b00, rxoff_mode=0b00, cca_mode=0b11, (bit76=0b00) ) - /* 0x18: mcsm0 0x18 (----) */ { 0, 0, 2, Cc1101::IDLE_TO_RX_OR_TX, 0 }, // xosc_force_on=0, pin_ctrl_en=0, po_timeout=2 (149-155us), fs_autocal=0b01, (bit76=0b00) - /* 0x19: foccfg 0x16 (0x1d) */ 0x16, - /* 0x1a: bscfg 0x6c (0x1c) */ 0x6c, - /* 0x1b: agcctrl2 0x43 (0xc7) */ 0x43, - /* 0x1c: agcctrl1 0x49 (0x00) */ 0x49, - /* 0x1d: agcctrl0 0x91 (0xb2) */ 0x91, - /* 0x1e: worevt1 0x87 (----) */ 0x87, - /* 0x1f: worevt0 0x6b (----) */ 0x6b, - /* 0x20: worctrl 0xfb (0xf8) */ 0xfb, - /* 0x21: frend1 0x56 (0xb6) */ 0x56, - /* 0x22: frend0 0x10 (----) */ { 0, 0, 1, 0 }, // pa_power = 0, (bit3 = 0), lodiv_buf_current = 1, (bit76=0b00) - /* 0x23: fscal3 0xe9 (0xea) */ 0xe9, - /* 0x24: fscal2 0x2a (----) */ 0x2a, - /* 0x25: fscal1 0x00 (----) */ 0x00, - /* 0x26: fscal0 0x1f (0x11) */ 0x1f, - /* 0x27: rcctrl1 0x41 (----) */ 0x41, - /* 0x28: rcctrl0 0x00 (----) */ 0x00, - /* 0x29: fstest 0x59 (----) */ 0x59, - /* 0x2a: ptest 0x7f (----) */ 0x7f, - /* 0x2b: agctest 0x3f (----) */ 0x3f, - /* 0x2c: test2 0x81 (0x88) */ 0x81, - /* 0x2d: test1 0x35 (0x31) */ 0x35, - /* 0x2e: test0 0x09 (0x0b) */ 0x09 - }; - - // -------------------------------------------------------------------------------------- - - int8_t Cc1101::runSend (uint8_t subtest) { - if (subtest == 0) { - bool ok = true; - GDOx_CFG_t cfg0 = SYNC_SENT_OR_RECEIVED_UNTIL_END_OF_PACKET; - ok &= writeRegister(0x02, cfg0); - return ok; - } else if (subtest > 1) { - return -1; - } - - printf_P(PSTR(" use + and - for power change (other key -> back to default)")); - - uint16_t cnt = 0; - uint8_t paIndex = 0; - uint8_t pa_power; - int key = EOF; - do { - // if ((cnt & 0x0f) == 0) { - // paIndex = (cnt >> 4) & 0x07; - // union { FREND0_t value; uint8_t byte; } frend0 = { paIndex, 0, 1, 0 }; - // printf_P(PSTR("\n switch power ")); - // if (writeRegister(FREND0, frend0.byte )) { - // printf_P(PSTR("to %d (FREND0 = 0x%02X)"), frend0.value.pa_power, frend0.byte); - // } else { - // printf_P(PSTR("fails")); - // } - // } - if (key != EOF) { - uint8_t max = (sizeof(PMEM_CC1101_PATABLE_INIT) / sizeof(PMEM_CC1101_PATABLE_INIT[0])) - 1; - switch (key) { - case '+': if (paIndex == 0) paIndex = 1; else if (paIndex > 1) paIndex--; break; - case '-': if (paIndex == 0) paIndex = max; else if (paIndex < max) paIndex++; break; - default: paIndex = 0; break; // default value - } - - const PATABLE_INIT_ITEM_t *values = PMEM_CC1101_PATABLE_INIT; - - memcpy_P(&pa_power, &((values[paIndex]).pa_power), 1); - PGM_P info = (values[paIndex]).dbm; - printf_P(PSTR("\n switch power to ")); printf_P(info); - printf_P(PSTR("dBm ")); - if (writeRegister(0x3e, pa_power )) { - printf_P(PSTR("(PATABLE = 0x%02X)"), pa_power); - } else { - printf_P(PSTR("fails")); - } - } - - MainRadioControlState state = UNKNOWN; - uint8_t data[PACKET_LENGTH]; - printf_P(PSTR("\n [%04x]: state="), cnt++); - if (!readStatusRegister(MARCSTATE, (uint8_t *)&state)) { - printf_P(PSTR("E1")); - } else { - printf_P(PSTR("0x%02x"), state); - } - data[0] = pa_power; - printf_P(PSTR(" --> send %d bytes (HEX: %02X"), sizeof(data), paIndex); - for (uint8_t i = 1; i < sizeof(data); i++) { - data[i] = uint8_t((cnt + i - 1) & 0xff); - printf_P(PSTR(" %02X"), data[i]); - } - printf_P(PSTR("] -> ")); - - if (!sendData(data, sizeof(data))) { - flashRedLed(100); - printf_P(PSTR("E1")); - continue; - } - flashGreenLed(100); - key = waitAndReadKey(2000); - printf_P(PSTR("OK")); - - } while (key == EOF || (key != ESCAPE)); - - return 0; - } - - int8_t Cc1101::runReceive (uint8_t subtest) { - if (subtest == 0) { - bool ok = true; - GDOx_CFG_t cfg0 = SYNC_SENT_OR_RECEIVED_UNTIL_END_OF_PACKET; - ok &= writeRegister(0x02, cfg0); - return ok; - } else if (subtest > 1) { - return -1; - } - - int key = EOF; - uint16_t cnt = 0; - MainRadioControlState state; - while (key == EOF) { - printf_P(PSTR("\n [%04x] => start ... "), cnt++); - strobe(SRX); - do { - state = UNKNOWN; - if (!readStatusRegister(MARCSTATE, (uint8_t *)&state)) { - printf_P(PSTR("E1")); - _delay_ms(500); - break; - } - if (wait(0) != EOF) { - printf_P(PSTR("cancelled")); - _delay_ms(500); - break; - } - if (state == IDLE) { - printf_P(PSTR("? (IDLE)")); - _delay_ms(500); - break; - } - - } while (state != RX && state != RXFIFO_OVERFLOW); - - if (state != RX && state != RXFIFO_OVERFLOW) { - continue; - } - printf_P(PSTR("OK, receive ... ")); - - uint8_t length; - uint8_t lastLength = 0xff; - do { - uint8_t data[PACKET_LENGTH]; - if (!readStatusRegister(MARCSTATE, (uint8_t *)&state)) { - printf_P(PSTR("E2")); - _delay_ms(500); - continue; - } - if (wait(0) != EOF) { - printf_P(PSTR("cancelled")); - _delay_ms(500); - return -1; - } - if (!readStatusRegister(RXBYTES, (uint8_t *)&length)) { - printf_P(PSTR("E2")); - _delay_ms(500); - continue; - } - if (lastLength != length) { - lastLength = length; - } - if (length >= PACKET_LENGTH) { - if (receiveData(data, &length, sizeof(data))) { - if (length > 0) { - flashGreenLed(100); - printf_P(PSTR(" -> ")); - if (status.receivePacketStatusValid) { - printf_P(PSTR(" RSSI=%d, LQI=%d, CRC "), status.receivedPacketStatus.value.rssi, status.receivedPacketStatus.value.lqi); - if (status.receivedPacketStatus.value.crcOk) { - printf_P(PSTR("OK, ")); - } else { - printf_P(PSTR("ERROR, ")); - } - } - printf_P(PSTR("%d data bytes (HEX): "), length); - for (uint8_t i = 0; i < length; i++) { - printf_P(PSTR(" %02X"), data[i]); - } - printf_P(PSTR(" ... ")); - } - } - } - - } while (state == RX || state == RXFIFO_OVERFLOW); - - printf_P(PSTR("done (state=0x%02x)"), state); - } - return -1; - } - - int8_t Cc1101::runTest (uint8_t subtest) { - if (subtest > 0) { - return -1; - } - while (wait(0) == EOF) {} - return -1; - } - - - int8_t Cc1101::run (uint8_t subtest) { - switch (mode) { - case Send: return runSend(subtest); - case Receive: return runReceive(subtest); - case Test: return runTest(subtest); - default: return -1; - } - } - - uint8_t Cc1101::sendSpiByte (uint8_t b) { - SPDR = b; - while (!(SPSR & (1< "), addr, value); - if (ok && status.receivePacketStatusValid) { - printf_P(PSTR("status=0x%02x]"), status.spiResponse.byte); - } else { - printf_P(PSTR("ERR]")); - } - } - - return ok; - } - - bool Cc1101::writeRegisters (uint8_t addr, uint8_t *buffer, uint8_t length) { - bool ok = true; - uint8_t l = length; - uint8_t *p = buffer; - - addr = (addr & 0x3f) | 0x40; // write burst - setChipEnableLow(); - ok &= waitForMisoLow(); - sendSpiByte(addr); - while (length-- > 0) { - sendSpiByte(*buffer++); - } - setChipEnableHigh(); - - if (debugPrint.print.writeRegisters) { - printf_P(PSTR("\n [writeRegisters(0x%02x): "), addr & 0x3f); - while (l-- > 0) { - printf_P(PSTR(" 0x%02x"), *p++); - } - printf_P(PSTR(" -> ")); - if (ok && status.receivePacketStatusValid) { - printf_P(PSTR("status=0x%02x]"), status.spiResponse.byte); - } else { - printf_P(PSTR("ERR]")); - } - } - - return ok; - } - - - bool Cc1101::readRegister (uint8_t addr, uint8_t *value) { - bool ok = true; - addr = (addr & 0x3f) | 0x80; - setChipEnableLow(); - ok &= waitForMisoLow(); - status.spiResponse.byte = sendSpiByte(addr); - status.spiResponseValid = 1; - *value = sendSpiByte(0); - setChipEnableHigh(); - - if (debugPrint.print.readRegister) { - printf_P(PSTR("\n [readRegister(0x%02x) -> "), addr & 0x3f); - if (ok && status.spiResponseValid) { - printf_P(PSTR("0x%02x,status=0x%02x]"), *value, status.spiResponse.byte); - } else { - printf_P(PSTR("ERR]")); - } - } - return ok; - } - - bool Cc1101::readRegisters (uint8_t addr, uint8_t *buffer, uint8_t length) { - bool ok = true; - - uint8_t l = length; - uint8_t *p = buffer; - - addr |= 0xc0; // read burst - setChipEnableLow(); - ok &= waitForMisoLow(); - sendSpiByte(addr); - while (length-- > 0) { - *buffer++ = sendSpiByte(0); - } - setChipEnableHigh(); - - if (debugPrint.print.readRegisters) { - printf_P(PSTR("\n [readRegisters(0x%02x, ..., %d)] -> "), addr & 0x3f, l); - if (ok) { - while (l-- > 0) { - printf_P(PSTR(" 0x%02x"), *p++); - } - printf_P(PSTR("]")); - } else { - printf_P(PSTR("ERR]")); - } - } - - return ok; - } - - bool Cc1101::readStatusRegister (StatusAddress_t addr, uint8_t *value) { - if (addr < 0x30 || addr > 0x3d) { - return false; - } else { - return readRegisters(addr, value, 1); - } - } - - bool Cc1101::sendData (uint8_t *buffer, uint8_t length) { - timer = 10; - uint8_t ok = true; - uint8_t txbytes; - uint8_t states[16]; uint8_t statesIndex = 0; - // ok &= writeRegister(0x3f, length); - ok &= writeRegisters(0x3f, buffer, length); - ok &= readStatusRegister(TXBYTES, &txbytes); - ok &= (txbytes == 20); - if (ok) { - ok &= strobe(STX); // start sending bytes - // ok &= waitForGD0High(); // wait for start of SYNC - if (ok) { - uint8_t lastState = 0; - uint8_t state; - do { - ok &= readStatusRegister(MARCSTATE, &state); - if (state != lastState && statesIndex < 16) { - states[statesIndex++] = state; - } - lastState = state; - } while (ok && state != 0x13 && timer > 0); - ok &= state == 0x13; // check if in state TX - } - if (ok) { - uint8_t lastTxbytes = 20; - do { - ok &= readStatusRegister(TXBYTES, &txbytes); - if (lastTxbytes != txbytes) { - lastTxbytes = txbytes; - } - } while (ok && txbytes > 0 && timer > 0); - ok &= txbytes == 0; - } - } - if (!ok) { - strobe(SFTX); // flush TXfifo - } else { - uint8_t state; - uint8_t lastState = 0; - do { - ok &= readStatusRegister(MARCSTATE, &state); - if (lastState != state) { - lastState = state; - } - } while (ok && state != 0x01 && timer > 0); - ok &= state == 0x01; // check if in state IDLE - } - // ok &= waitForGD0Low(); // wait for end of package - - if (ok) { - printf_P(PSTR(" States[")); - for (uint8_t i = 0; i < statesIndex; i++) { - printf_P(PSTR(" 0x%02X"), states[i]); - } - printf_P(PSTR("] ")); - } - - return ok; - } - - bool Cc1101::receiveData (uint8_t *buffer, uint8_t *receivedLength, uint8_t maxBufferSize) { - bool ok = true; - STATUS_RXBYTES_t status; - uint8_t lastLength = 0; - uint8_t length = 0; - *receivedLength = 0; - timer = 50; - - this->status.receivePacketStatusValid = 0; - ok &= readStatusRegister(RXBYTES, &status.byte); - if (ok && status.rxbytes.num_rxbytes > 0) { - length = status.rxbytes.num_rxbytes; - - do { - _delay_us(400); // 20 Bytes in 4ms -> 200us/Byte -> CC1101 datasheet page 56: "twice that of which RF bytes are recived" - lastLength = length; - ok &= readStatusRegister(RXBYTES, &status.byte); - if (ok) { - // printf_P(PSTR(" [rxbytes=%d] "), status.byte); - length = status.byte & 0x7f; - } - ok &= timer > 0; - } while (ok && lastLength != length); - - if (ok) { - uint8_t extraBytesCount = this->status.receivePacketStatusEnabled ? 2 : 0; - if ((PACKET_LENGTH + extraBytesCount) != length) { - printf_P(PSTR(" ERROR[receive %d bytes, expect %d bytes] "), *receivedLength, PACKET_LENGTH + extraBytesCount); - *receivedLength = 0; - ok = false; - } else { - printf_P(PSTR(" OK[receive %d bytes] "), length); - *receivedLength = PACKET_LENGTH < maxBufferSize ? length - extraBytesCount : maxBufferSize; - ok &= readRegisters(0xff, buffer, *receivedLength); - if (!ok) { - *receivedLength = 0; - } else { - length -= *receivedLength; - if (length > extraBytesCount) { - printf_P(PSTR(" [WARN: buffer to small] ")); - while (length > extraBytesCount) { - uint8_t byte; - ok &= readRegister(0xff, &byte); - ok = false; - length--; - } - } - if (length > 0) { - ok &= readRegisters(0xff, this->status.receivedPacketStatus.byte, 2); - if (ok) { - this->status.receivePacketStatusValid = 1; - } - } - } - } - } - } - ok &= strobe(SFRX); - - return ok; - } - - - void Cc1101::printRegisters () { - const Register_t *regValues = &PMEM_CC1101_REGISTER_INIT; - printf_P(PSTR("\n")); - for (uint8_t addr = 0; addr < sizeof(Register_t); addr++) { - bool ok = true; - uint8_t regValue, value; - memcpy_P(®Value, ((const uint8_t *)regValues) + addr, 1); - ok &= readRegister(addr, &value); - if (value != regValue) { printf_P(PSTR(" != 0x%02x"), regValue); } - } - uint8_t data[8]; - for (uint8_t addr = 0x30; addr <= 0x3d; addr++) { - readStatusRegister((StatusAddress_t)addr, data); - } - readRegisters(0x3e, data, 8); // PATABLE - } - - bool Cc1101::resetCC1101 () { - bool ok = true; - setChipEnableLow(); - _delay_us(10); - setChipEnableHigh(); - _delay_us(50); - setChipEnableLow(); - ok &= waitForMisoLow(); - ok &= strobe(SRES); - ok &= waitForMisoLow(); - - - return ok; - } - - bool Cc1101::initRegister () { - const Register_t *regValues = &PMEM_CC1101_REGISTER_INIT; - bool ok = true; - // DebugPrint_t tmp = debugPrint.print; - // debugPrint.byte = 0xff; // print all - // printRegisters(); - - for (uint8_t addr = 0; ok && addr < sizeof(Register_t); addr++) { - uint8_t regValue; - memcpy_P(®Value, ((const uint8_t *)regValues) + addr, 1); - ok &= writeRegister(addr, regValue); - if ((addr == 0x07) && (regValue & 0x04)) { - status.receivePacketStatusEnabled = true; - } - } - - // debugPrint.print = tmp; - return ok; - } - - bool Cc1101::initPaTable () { - const PATABLE_INIT_ITEM_t *values = PMEM_CC1101_PATABLE_INIT; - uint8_t patable[8]; - uint8_t initValuesIndex = 0; - for (uint8_t i = 0; i < 8; i++) { - memcpy_P(&patable[i], &(values[initValuesIndex++].pa_power), 1); - if (initValuesIndex >= (sizeof(PMEM_CC1101_PATABLE_INIT) / sizeof(PATABLE_INIT_ITEM_t))) { - initValuesIndex = 0; - } - if (debugPrint.print.writePaTable) { - printf_P(PSTR("\nPTABLE %d: 0x%02x"), i, patable[i]); - } - } - return writeRegisters(0x3e, patable, 8); - } - -#endif - - diff --git a/software/nano-644/test_2024-07-23/src/units/cc1101.hpp b/software/nano-644/test_2024-07-23/src/units/cc1101.hpp deleted file mode 100644 index a861f09..0000000 --- a/software/nano-644/test_2024-07-23/src/units/cc1101.hpp +++ /dev/null @@ -1,281 +0,0 @@ -#ifndef CC1101_HPP -#define CC1101_HPP - -#include -#include "../main.hpp" -#include - -class Cc1101 : public TestUnit { - public: - #define PACKET_LENGTH 20 - - public: - typedef enum { Test, Send, Receive } Cc1101Mode; - typedef enum { _IDLE = 0, _RX = 1, _TX = 2, _FSTXON = 3, _CALIBRATE = 4, _SETTLING = 5, _RXFIFO_OVFL = 6, _TXFIFO_UNFL = 7 } StatusState_t; - typedef struct { uint8_t fifoBytes:4; StatusState_t state:3; uint8_t chipNotReady:1; } Status_t; - typedef struct { int8_t rssi:8; uint8_t lqi:7; uint8_t crcOk:1; } ReceivedPacketStatus_t; // CC1101 datasheet page 37 - union { - struct { - union { - Status_t value; - uint8_t byte; - } spiResponse; - union { - ReceivedPacketStatus_t value; - uint8_t byte [2]; - } receivedPacketStatus; - uint8_t spiResponseValid: 1; - uint8_t receivePacketStatusEnabled:1; - uint8_t receivePacketStatusValid:1; - }; - uint32_t dword; - } status; - - public: - Cc1101 (Cc1101Mode mode) { timer = 0; this->mode = mode; status.dword = 0; } - virtual void init (); - virtual void cleanup (); - virtual int8_t run (uint8_t subtest); - virtual PGM_P getName (); - - public: - void tick1ms () { if (timer > 0) timer--; }; - - private: - typedef enum { SRES = 0x30, SCAL = 0x33, SRX = 0x34, STX = 0x35, SFRX = 0x3a, SFTX = 0x3b, SIDLE = 0x36 } StrobeCommand_t; - typedef enum { MARCSTATE = 0x35, TXBYTES = 0x3A, RXBYTES = 0x3B } StatusAddress_t; - typedef struct { uint8_t writeRegister:1; uint8_t writeRegisters:1; uint8_t readRegister:1; uint8_t readRegisters:1; uint8_t writePaTable:1; } DebugPrint_t; - - private: - int8_t runSend (uint8_t subtest); - int8_t runReceive (uint8_t subtest); - int8_t runTest (uint8_t subtest); - uint8_t sendSpiByte (uint8_t b); - void triggerOn(); - void triggerOff(); - void triggerToggle (); - void setChipEnableLow (); - void setChipEnableHigh (); - bool isMisoHigh (); - bool isGd0High (); - bool waitForMisoLow (); - bool waitForGD0High (); - bool waitForGD0Low (); - bool strobe (StrobeCommand_t strobe); - bool writeRegister (uint8_t addr, uint8_t value); - bool writeRegisters (uint8_t addr, uint8_t *buffer, uint8_t length); - bool readRegister (uint8_t addr, uint8_t *value); - bool readRegisters (uint8_t addr, uint8_t *buffer, uint8_t length); - bool readStatusRegister (StatusAddress_t addr, uint8_t *value); - bool sendData (uint8_t *buffer, uint8_t length); - bool receiveData (uint8_t *buffer, uint8_t *receivedLength, uint8_t maxBufferSize); - void printRegisters (); - - bool resetCC1101 (); - bool initRegister (); - bool initPaTable (); - - - private: - Cc1101Mode mode; - uint8_t timer; - union { - DebugPrint_t print; - uint8_t byte; - } debugPrint; - - - public: - typedef enum { - IOCFG2 = 0x00, IOCFG1 = 0x01, IOCFG0 = 0x02, - FIFOTHR = 0x03, - SYNC1 = 0x04, SYNC0 = 0x05, - PKTLEN = 0x06, - PKTCTRL1 = 0x07, PKTCTRL0 = 0x08, - ADDR = 0x00, CHANNR = 0x0a, - FSCTRL1 = 0x0b, FSCTRL0 = 0x0c, - FREQU2 = 0x0d, FREQU1 = 0x0e, FREQU0 = 0x0f, - MDMCFG4 = 0x10, MDMCFG3 = 0x11, MDMCFG2 = 0x12, MDMCFG1 = 0x13, MDMCFG0 = 0x14, - DEVIATN = 0x15, - MCSM2 = 0x16, MCSM1 = 0x17, MCSM0 = 0x18, - FOCCFG = 0x19, BSCFG = 0x1a, - AGCCTRL2 = 0x1b, AGCCTRL1 = 0x1c, AGCCTRL0 = 0x1d, - WOREVT1 = 0x1e, WOREVT0 = 0x1f, WORCTRL = 0x20, - FREND1 = 0x21, FREND0 = 0x22, - FSCAL3 = 0x23, FSCAL2 = 0x24, FSCAL1 = 0x25, FSCAL0 = 0x26, - RCCTRL1 = 0x27, RCCTRL0 = 0x28, - FSTEST = 0x29, PTEST = 0x2a, AGCTEST = 0x2b, - TEST2 = 0x2c, TEST1 = 0x2d, TEST0 = 0x2e - } RegisterAddress_t; - - typedef enum { - RX_FIFO_FILLED_OR_ABOVE_THRESHHOLD = 0x00, - RX_FIFO_FILLED_OR_ABOVE_THRESHHOLD_OR_END_OF_PACKAGE_UNTIL_FIFO_EMPTY = 0x01, - TX_FIFO_FILLED_OR_ABOVE_THRESHHOLD = 0x02, - TX_FIFO_FULL_UNTIL_BELOW_THRESHHOLD = 0x03, - RX_FIFO_OVERFLOW_UNTIL_FIFO_FLUSHED = 0x04, - TX_FIFO_UNDERFLOW_UNTIL_FIFO_FLUSHED = 0x05, - SYNC_SENT_OR_RECEIVED_UNTIL_END_OF_PACKET = 0x06, - PACKET_RECEIVED_WITH_CRC_OK_UNTIL_FIRST_BYTE_READ_FROM_RXFIFO = 0x07, - PREAMBLE_QUALITY_REACHED_UNTIL_REENTER_RX = 0x08, - RSSI_LEVEL_BELOW_THRESHOLD = 0x09, - LOCK_DETECTOR_OUTPUT = 0x0a, - SERIAL_CLOCK = 0x0b, - SERIAL_SYNCHRONOUS_DATA_OUTPUT = 0x0c, - SERIAL_ASYNC_DATA_OUTPUT = 0x0d, - CARRIER_DETECTED_UNTIL_ENTER_IDLE = 0x0e, - CRC_OK_UNTIL_REENTER_RX = 0x0f, - RX_HARD_DATA_1 = 0x16, - RX_HARD_DATA_0 = 0x17, - PA_PD = 0x1b, - LNA_PD = 0x1c, - RX_SYMBOL_TICK = 0x1d, - WAKEUP_ON_RECEIVE_EVENT0 = 0x24, - WAKEUP_ON_RECEIVE_EVENT1 = 0x25, - CLK_256 = 0x26, - CLK_32K = 0x27, - CHIP_NOT_READY = 0x29, - XOSC_STABLE = 0x2b, - HIGH_IMPEDANCE_WHEN_CHIP_SELECT_HIGH = 0x2e, - HW_TO_0 = 0x2f, - CLK_XOSC = 0x30, - CLK_XOSC_DIV_1P5 = 0x31, - CLK_XOSC_DIV_2 = 0x32, - CLK_XOSC_DIV_3 = 0x33, - CLK_XOSC_DIV_4 = 0x34, - CLK_XOSC_DIV_6 = 0x35, - CLK_XOSC_DIV_8 = 0x36, - CLK_XOSC_DIV_12 = 0x37, - CLK_XOSC_DIV_16 = 0x38, - CLK_XOSC_DIV_24 = 0x39, - CLK_XOSC_DIV_32 = 0x3a, - CLK_XOSC_DIV_48 = 0x3b, - CLK_XOSC_DIV_64 = 0x3c, - CLK_XOSC_DIV_96 = 0x3d, - CLK_XOSC_DIV_128 = 0x3e, - CLK_XOSC_DIV_192 = 0x3f - } GDOx_CFG_t; - - typedef enum { - SLEEP = 0, - IDLE = 1, - XOFF = 2, - MANCAL_VCOON = 3, - MANCAL_REGON = 4, - MANCAL = 5, - FS_WAKEUP_VCOON = 6, - FS_WAKEUP_REGON = 7, - CALIBRATE_START = 8, - SETTLING_BWBOOST = 9, - SETTLING_FS_LOCK = 10, - SETTLIN_IFADCON = 11, - CALIBRATE_END = 12, - RX = 13, - RX_END = 14, - RX_RST = 15, - TXRX_SETTLING = 16, - RXFIFO_OVERFLOW = 17, - FXTXON = 18, - TX = 19, - TX_END = 20, - RXTX_SETTLING = 21, - TXFIFO_UNDERFLOW = 22, - UNKNOWN = 255 - } MainRadioControlState; - - typedef struct { uint8_t pa_power; const char dbm[4]; } PATABLE_INIT_ITEM_t; - - typedef enum { NO_ADDR_CHECK = 0, CHECK_NO_BROADCAST = 1, CHECK_WITH_BROADCAST_0 = 2, CHECK_WITH_BROADCAST_0_AND_255 = 3 } ADR_CHK_t; - typedef enum { FIXED = 0, VARIABLE = 1, INFINITE = 2 } LENGTH_CONFIG_t; - typedef enum { NORMAL_USE_FIFO = 0, SYNC_SERIAL = 1, RANDOM_TX = 2, ASYNC_SERIAL = 3 } PKT_FORMAT_t; - typedef enum { FSK2 = 0, GFSK = 1, ASK_OOK = 3, FSK4 = 4, MSK = 7 } MOD_FORMAT_t; - typedef enum { NO_SYNC = 0, SYNC_15_16 = 1, SYNC_16_16 = 2, SYNC_30_32 = 3, CARRIER_SENSE = 4, SYNC_15_16_CARRIER_SENSE = 5, SYNC_16_16_CARRIER_SENSE = 6 , SYNC_30_326_CARRIER_SENSE = 7} SYNC_MODE_t; - typedef enum { TWO = 0, THREE = 1, FOUR = 2, SIX = 3, EIGHT = 4, TWELVE = 5, SIXTEEN = 6, TWENTYFOUR = 7 } NUM_PREAMBLE_t; - typedef enum { TXOFF_IDLE = 0, TXOFF_FSTXON = 1, STAY_IN_TX = 2, TXOFF_RX = 3 } TXOFF_MODE_t; - typedef enum { RXOFF_IDLE = 0, RXOFF_FSTXON = 1, RXOFF_TX = 2, STAY_IN_RX = 3 } RXOFF_MODE_t; - typedef enum { ALWAYS = 0, RSSI_BELOW_THRESHOLD = 1, UNLESS_RECEIVE_PACKET = 2, RSSI_BELOW_THRESHOLD__UNLESS_RECEIVE_PACKET = 3 } CCA_MODE_t; - typedef enum { NEVER = 0, IDLE_TO_RX_OR_TX = 1, RX_OR_TX_TO_IDLE = 2, RX_OR_TX_TO_IDLE_EVERY_4_TIME = 3 } FS_AUTOCAL_t; - - typedef struct { GDOx_CFG_t gdo0_cfg:6; uint8_t gdo0_inv:1; uint8_t bit7:1; } IOCFG0_t; - typedef struct { GDOx_CFG_t gdo1_cfg:6; uint8_t gdo1_inv:1; uint8_t bit7:1; } IOCFG1_t; - typedef struct { GDOx_CFG_t gdo2_cfg:6; uint8_t gdo2_inv:1; uint8_t bit7:1; } IOCFG2_t; - typedef struct { uint8_t fifo_thr:4; uint8_t close_in_rx:2; uint8_t adc_retention:1; uint8_t bit7:1; } FIFOTHR_t; - typedef struct { ADR_CHK_t adr_chk:2; uint8_t append_status:1; uint8_t crc_autoflush:1; uint8_t bit4:1; uint8_t pqt:3; } PKTCTRL1_t; - typedef struct { LENGTH_CONFIG_t length_config:2; uint8_t crc_en:1; uint8_t bit3:1; PKT_FORMAT_t pkt_format:2; uint8_t white_data:1; uint8_t bit7:1; } PKTCTRL0_t; - typedef struct { uint8_t frequ_if:5; uint8_t bit5:1; uint8_t bit76:2; } FSCTRL1_t; - typedef struct { uint8_t frequoff:8; } FSCTRL0_t; - typedef struct { uint8_t drate_e:4; uint8_t chanbw_m:2; uint8_t chanbw_e:2; } MDMCFG4_t; - typedef struct { uint8_t drate_m:8; } MDMCFG3_t; - typedef struct { SYNC_MODE_t sync_mode:3; uint8_t manchester_en:1; MOD_FORMAT_t mod_format:3; uint8_t dem_dcfilt_off:1; } MDMCFG2_t; - typedef struct { uint8_t chanspc_e:2; uint8_t bit32:2; NUM_PREAMBLE_t num_preamble:3; uint8_t fec_en:1; } MDMCFG1_t; - typedef struct { uint8_t chanspc_m:8; } MDMCFG0_t; - typedef struct { uint8_t deviation_m:3; uint8_t bit3:1; uint8_t deviation_e:3; uint8_t bit7:1; } DEVIATN_t; - typedef struct { uint8_t rx_time:3; uint8_t rx_time_qual:1; uint8_t rx_time_rssi:1; uint8_t bit765:3; } MCSM2_t; - typedef struct { TXOFF_MODE_t txoff_mode:2; RXOFF_MODE_t rxoff_mode:2; CCA_MODE_t cca_mode:2; uint8_t bit76:2; } MCSM1_t; - typedef struct { uint8_t xosc_force_on:1; uint8_t pin_ctrl_en:1; uint8_t po_timeout:2; FS_AUTOCAL_t fs_autocal:2; uint8_t bit76:2; } MCSM0_t; - typedef struct { uint8_t pa_power:3; uint8_t bit3:1; uint8_t lodiv_buf_current:2; uint8_t bit76:2; } FREND0_t; - - typedef union { - uint8_t byte; - struct { - uint8_t num_rxbytes:7; - uint8_t rxfifo_overflow:1; - } rxbytes; - } STATUS_RXBYTES_t; - - typedef struct { - IOCFG2_t iocfg2; - IOCFG1_t iocfg1; - IOCFG0_t iocfg0; - FIFOTHR_t fifothr; - uint8_t sync1; - uint8_t sync0; - uint8_t pktlen; - PKTCTRL1_t pktctrl1; - PKTCTRL0_t pktctrl0; - uint8_t addr; - uint8_t channr; - FSCTRL1_t fsctrl1; - FSCTRL0_t fsctrl0; - uint8_t frequ2; - uint8_t frequ1; - uint8_t frequ0; - MDMCFG4_t mdmcfg4; - MDMCFG3_t mdmcfg3; - MDMCFG2_t mdmcfg2; - MDMCFG1_t mdmcfg1; - MDMCFG0_t mdmcfg0; - DEVIATN_t deviatn; - MCSM2_t mcsm2; - MCSM1_t mcsm1; - MCSM0_t mcsm0; - uint8_t foccfg; - uint8_t bscfg; - uint8_t agcctrl2; - uint8_t agcctrl1; - uint8_t agcctrl0; - uint8_t worevt1; - uint8_t worevt0; - uint8_t worctrl; - uint8_t frend1; - FREND0_t frend0; - uint8_t fscal3; - uint8_t fscal2; - uint8_t fscal1; - uint8_t fscal0; - uint8_t rcctrl1; - uint8_t rcctrl0; - uint8_t fstest; - uint8_t ptest; - uint8_t agctest; - uint8_t test2; - uint8_t test1; - uint8_t test0; - - } Register_t; - - - -}; - -#endif \ No newline at end of file diff --git a/software/nano-644/test_2024-07-23/src/units/encoder.cpp b/software/nano-644/test_2024-07-23/src/units/encoder.cpp deleted file mode 100644 index 7b33b76..0000000 --- a/software/nano-644/test_2024-07-23/src/units/encoder.cpp +++ /dev/null @@ -1,138 +0,0 @@ -#include -#include - -#include "encoder.hpp" -#include "../main.hpp" - -// Encoder signals on rotation clockwise 1 step: -// A -----____------ one char app. 1ms..2ms (rotation speed) -// B -------___----- -// one step when: A = 0, B= 1->0 - -// Encoder signals on rotation counterclockwise 1 step: -// A -----____------ one char app. 1ms..2ms (rotation speed) -// B --______----- -// one step when: A = 0, B= 0->1 - -#if defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__) - - // Nano-644 - // --------------------------------------------------------------- - // PB0/T0 ... Encoder A - // PB1/T1 ... Encoder B - // PB2/INT2 ... push switch of encoder (pushed = 0) - - void Encoder::init () { - DDRB &= ~((1 << PB2) | (1 << PB1) | (1 << PB0)); - PORTB |= (1 << PORTB2) | (1 << PORTB1) | (1 << PORTB0); // enable pullup - enabled = 1; - } - - void Encoder::cleanup () { - enabled = 0; - DDRB &= ~((1 << PB2) | (1 << PB1) | (1 << PB0)); - PORTB &= ~((1 << PORTB2) | (1 << PORTB1) | (1 << PORTB0)); - } - - bool Encoder::isPressed () { - return (PINB & (1 << PB2)) == 0; - } - - bool Encoder::getA () { - return (PINB & (1 << PB0)) == 0; - } - - bool Encoder::getB () { - return (PINB & (1 << PB1)) == 0; - } - - -#endif - -#ifdef __AVR_ATmega328P__ - - // Arduino-Nano-5V - // --------------------------------------------------------------- - // PD4/T0 ... Encoder A - // PB0 ... Encoder B - // PD7 ... push switch of encoder (pushed = 0) - - void Encoder::init () { - DDRB &= ~(1 << PB0); - DDRD &= ~((1 << PD7) | (1 << PD4)); - PORTB |= (1 << PB0); // enable pullup - PORTD |= (1 << PD7) | (1 << PD4); // enable pullup - enabled = 1; - } - - void Encoder::cleanup () { - enabled = 0; - PORTB &= ~(1 << PB0); - PORTD &= ~((1 << PD7) | (1 << PD4)); - DDRB &= ~(1 << PB0); - DDRD &= ~((1 << PD7) | (1 << PD4)); - } - - bool Encoder::isPressed () { - return (PIND & (1 << PD7)) == 0; - } - - bool Encoder::getA () { - return (PIND & (1 << PD4)) == 0; - } - - bool Encoder::getB () { - return (PINB & (1 << PB0)) == 0; - } - -#endif - - -int8_t Encoder::run (uint8_t subtest) { - switch (subtest) { - case 0: { - while (wait(10) == EOF) { - printf_P(PSTR("\r => Encoder (push to clear): ")); - printf_P(PSTR("%5d (0x%02x) "), count, (uint8_t)count); - if (isPressed()) { - reset(); - } - } - return 0; - } - } - - return -1; -} - -struct EncoderState { - int8_t a:1; // signal A - int8_t b:1; // signal B -}; - -void Encoder::tick100us () { - static EncoderState lastState = { 1, 1 }; - static EncoderState lastStableState = { 1, 1 }; - - if (!enabled) { - count = 0; - return; - } - EncoderState nextState; - nextState.a = getA() ? 1 : 0; - nextState.b = getB() ? 1 : 0; - if (nextState.a == lastState.a && nextState.b == lastState.b) { - if (lastStableState.a == 0 && nextState.b != lastStableState.b) { - if (nextState.b == 0) { - count = count < 127 ? count + 1 : 127; - } else { - count = count > -128 ? count - 1 : -128; - } - } - lastStableState.a = nextState.a; - lastStableState.b = nextState.b; - } - lastState.a = nextState.a; - lastState.b = nextState.b; -} - diff --git a/software/nano-644/test_2024-07-23/src/units/encoder.hpp b/software/nano-644/test_2024-07-23/src/units/encoder.hpp deleted file mode 100644 index 9b0861b..0000000 --- a/software/nano-644/test_2024-07-23/src/units/encoder.hpp +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef ENCODER_HPP -#define ENCODER_PP - -#include -#include "../main.hpp" -#include - -class Encoder : public TestUnit { - public: - uint8_t enabled; - int8_t count; - - public: - Encoder () { reset(); enabled = 0; }; - virtual void init (); - virtual void cleanup (); - virtual int8_t run (uint8_t subtest); - virtual PGM_P getName () { return PSTR("Encoder"); } - void reset () { count = 0; } - void tick100us (); - bool isPressed (); - - private: - bool getA (); - bool getB (); -}; - -#endif \ No newline at end of file diff --git a/software/nano-644/test_2024-07-23/src/units/i2c.cpp b/software/nano-644/test_2024-07-23/src/units/i2c.cpp deleted file mode 100644 index 60dd22d..0000000 --- a/software/nano-644/test_2024-07-23/src/units/i2c.cpp +++ /dev/null @@ -1,216 +0,0 @@ -#include -#include -#include -#include -#include - -#include "i2c.hpp" -#include "../adafruit/bme280.h" -#include "../main.hpp" - -// Sparkfun https://www.sparkfun.com/products/22858 -// ENS160 address 0x53 (air quality sensor) -// BME280 address 0x77 /humidity/temperature sensor) -// register 0xfe: humidity_7:0 -// register 0xfd: humidity_15:8 - -PGM_P I2c::getName () { - switch (mode) { - case SparkFunEnvCombo: return PSTR("I2C-Sparkfun Env-Combo"); - case Master: return PSTR("I2C-Master"); - case Slave: return PSTR("I2C-Slave"); - } - return "?"; -} - -void I2c::init () { - TWBR = 13; // 100kHz (TWPS1:0 = 00), TWBR = (F_CPU - 16 * 100000) / (2 * 100000 * 4); - TWBR = 28; // 50kHz (TWPS1:0 = 00), TWBR = (F_CPU - 16 * 50000) / (2 * 50000 * 4); - TWBR = 100; // 50kHz (TWPS1:0 = 00), TWBR = (F_CPU - 16 * 50000) / (2 * 50000 * 4); - TWCR = (1 << TWEN); - ADMUX = (1 << ADLAR) | (1 << REFS0); // ADC0, VREF=AVCC=3.3V - ADCSRA = (1 << ADEN) | 7; // ADC Enable, Prescaler 128 - enabled = true; -} - -void I2c::cleanup () { - enabled = false; - TWCR = (1 << TWEN); - TWBR = 0; - ADMUX = 0; - ADCSRA = 0; -} - -int8_t I2c::run (uint8_t subtest) { - if (subtest == 0 && mode == I2c::SparkFunEnvCombo) { - printf_P(PSTR(" BM280 ... ")); - if (!bm280.begin()) { - printf_P(PSTR("E1")); - return -1; - } - printf_P(PSTR("OK, ENS160 ... ")); - if (!ens160.begin()) { - printf_P(PSTR("E2")); - return -1; - } - if (!ens160.setMode(ENS160_OPMODE_STD)) { - printf_P(PSTR("E3")); - return -1; - } - if (!ens160.set_envdata(25.0, 65)) { - printf_P(PSTR("E4")); - return -1; - } - - printf_P(PSTR("OK")); - float accTemp = 0, accHumidity = 0; - int8_t accCount = -1; - - do { - // BME280 - float p = bm280.readPressure(); - printf_P(PSTR("\n => BM280: P= %.3fbar"), (double)p / 100000.0); - float t = bm280.readTemperature(); - printf_P(PSTR(", T= %.2f°C"), (double)t); - float h = bm280.readHumidity(); - printf_P(PSTR(", H= %.2f%%"), (double)h); - - if (accCount >= 0 && !isnanf(h) && !isnan(t)) { - accTemp += t; - accHumidity += h; - accCount++; - } - - bm280.setSampling( - Adafruit_BME280::MODE_NORMAL, - Adafruit_BME280::SAMPLING_X16, - Adafruit_BME280::SAMPLING_X16, - Adafruit_BME280::SAMPLING_X16, - Adafruit_BME280::FILTER_OFF, - Adafruit_BME280::STANDBY_MS_1000 - ); - - // ENS160 only activated every 32s to avoid wrong temperature measuerment - // if ES160 would be continously active, the temperature would be 4°C higher - // -> ES160 has not enough distance to BM280 - // This solution causes only a +0.3°C higher temperatur value - if (accCount < 0 || accCount >= 32) { - printf_P(PSTR(" | ENS160 (")); - if (accCount > 0) { - h = accHumidity / accCount; - t = accTemp / accCount; - accTemp = 0; - accHumidity = 0; - } - accCount = 0; - if (!ens160.set_envdata(t, h)) { - printf_P(PSTR("E1)")); - } else { - printf_P(PSTR("%.1f°C/%.1f%%): "), (double)t, (double)h); - if (!ens160.setMode(ENS160_OPMODE_STD)) { - printf_P(PSTR("E2")); - } else { - for (uint8_t i = 0; i < 100; i++) { - _delay_ms(15); - uint8_t status; - if (ens160.readStatus(&status)) { - if (status & ENS160_DATA_STATUS_NEWDAT) { - ENS160_DATA data; - if (ens160.readData(&data)) { - printf_P(PSTR(" aqi=%d("), data.aqi); - switch(data.aqi) { - case 1: printf_P(PSTR("excellent")); break; - case 2: printf_P(PSTR("good")); break; - case 3: printf_P(PSTR("moderate")); break; - case 4: printf_P(PSTR("poor")); break; - case 5: printf_P(PSTR("unhealthy")); break; - default: printf_P(PSTR("?")); break; - } - printf_P(PSTR("), tvoc=%dppb"), data.tvoc); - printf_P(PSTR(", eco2=%d("), data.eco2); - if (data.eco2 < 400) { - printf_P(PSTR("?")); - } else if (data.eco2 < 600) { - printf_P(PSTR("excellent")); - } else if (data.eco2 < 800) { - printf_P(PSTR("good")); - } else if (data.eco2 < 1000) { - printf_P(PSTR("fair")); - } else if (data.eco2 < 1500) { - printf_P(PSTR("poor")); - } else { - printf_P(PSTR("bad")); - } - printf_P(PSTR(")")); - } - break; - } - } - } - } - if (!ens160.setMode(ENS160_OPMODE_IDLE)) { - printf_P(PSTR("E3")); - } - } - } - - } while (wait(1000) == EOF); - - } else if (subtest == 0 && mode == I2c::Master) { - if (!master.begin(0x01)) { - printf_P(PSTR("E1")); - return -1; - } - do { - uint8_t buffer[1]; - // read poti - ADCSRA |= (1 << ADSC); // start ADC - while (ADCSRA & (1 << ADSC)) {} // wait for result - buffer[0] = ADCH; - printf_P(PSTR("\n I2C-MASTER: to slave: 0x%02x"), buffer[0]); - if (!master.write(buffer, 1)) { - printf_P(PSTR(" -> ERROR")); - } - printf_P(PSTR(", from slave: ")); - if (master.read(buffer, 1)) { - printf_P(PSTR("0x%02x"), buffer[0]); - } else { - printf_P(PSTR(" -> ERROR")); - } - } while (wait(1000) == EOF); - master.end(); - - } else if (subtest == 0 && mode == I2c::Slave) { - if (!slave.begin(0x01, false)) { - printf_P(PSTR("E1")); - return -1; - } - do { - int fromMaster = slave.read(); - if (fromMaster != EOF) { - ADCSRA |= (1 << ADSC); // start ADC - while (ADCSRA & (1 << ADSC)) {} // wait for result - slave.write(ADCH); - printf_P(PSTR("\n I2C SLAVE: from master: 0x%02x -> to master: 0x%02x"), fromMaster, ADCH); - } - } while (wait(0) == EOF); - slave.end(); - - } else { - printf_P(PSTR("end")); - return -1; - } - wait(500); - return 0; -} - -void I2c::handleTwiIrq () { - if (mode == I2c::Slave) { - DDRD |= (1 << PD7); - PORTD |= (1 << PD7); - slave.handleTWIIsr(); - PORTD &= ~(1 << PD7); - } else { - TWCR |= (1 << TWINT); // clear Interrupt Request - } -} diff --git a/software/nano-644/test_2024-07-23/src/units/i2c.hpp b/software/nano-644/test_2024-07-23/src/units/i2c.hpp deleted file mode 100644 index 2148cc0..0000000 --- a/software/nano-644/test_2024-07-23/src/units/i2c.hpp +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef I2C_HPP -#define I2C_HPP - -#include -#include "../main.hpp" -#include "../adafruit/bme280.h" -#include "../adafruit/ens160.h" -#include "../i2cmaster.hpp" -#include "../i2cslave.hpp" - - -class I2c : public TestUnit { - public: - typedef enum I2cMode { SparkFunEnvCombo, Master, Slave } I2cMode; - - private: - I2cMode mode; - Adafruit_BME280 bm280; - ScioSense_ENS160 ens160; - I2cMaster master; - I2cSlave slave; - - public: - bool enabled; - - public: - I2c (I2cMode mode) { enabled = false; this->mode = mode; } - void tick1ms () { master.tick1ms(); slave.tick1ms(); } - virtual void init (); - virtual void cleanup (); - virtual int8_t run (uint8_t subtest); - virtual PGM_P getName (); - void handleTwiIrq (); - // uint16_t startRead (uint8_t address); - // uint16_t startWrite (uint8_t address); - // void stop (); - // uint16_t writeByte (uint8_t data); - // uint16_t writeData (uint8_t size, const uint8_t *data); - // uint16_t readData (uint8_t size, uint8_t *data); - // int32_t compensateBm280T (int32_t adcT); -}; - -#endif \ No newline at end of file diff --git a/software/nano-644/test_2024-07-23/src/units/ieee485.cpp b/software/nano-644/test_2024-07-23/src/units/ieee485.cpp deleted file mode 100644 index 8fcb67a..0000000 --- a/software/nano-644/test_2024-07-23/src/units/ieee485.cpp +++ /dev/null @@ -1,111 +0,0 @@ -#include -#include -#include -#include - -#include "ieee485.hpp" -#include "../main.hpp" - -#ifdef __AVR_ATmega328P__ - -// Nano-328P -// ------------------------------------ -// IEE485 not supported (no UART1) - -void Ieee485::init () {} -void Ieee485::cleanup () {} -int8_t Ieee485::run (uint8_t subtest) { - return -1; -} - -#endif - - -#if defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__) - -// Nano-644 -// ------------------------------------ -// PB0 ... nRE .. Read enable -// PB1 ... DE .. Data enable - -#define SET_nRE (PORTB |= (1 << PB0)) -#define CLR_nRE (PORTB &= ~(1 << PB0)) -#define SET_DE (PORTB |= (1 << PB1)) -#define CLR_DE (PORTB &= ~(1 << PB1)) - -void Ieee485::init () { - // Poti - ADMUX = (1 << ADLAR) | (1 << REFS0); // ADC0, VREF=AVCC=3.3V - ADCSRA = (1 << ADEN) | 7; // ADC Enable, Prescaler 128 - - // Modbus - SET_nRE; - CLR_DE; - DDRB |= (1 << PB1) | (1 << PB0); - - // UART1 interface on Nano-644 - PORTD |= (1 << PD2); // enable RxD1 pullup - UCSR1A = (1 << U2X1); - UCSR1B = (1 << RXCIE1) | (1 << RXEN1) | (1 < send Byte 0x%02x"), ADCH); - int b; - ATOMIC_BLOCK(ATOMIC_FORCEON) { - b = receivedByte; - receivedByte = -1; - } - if (b >= 0) { - printf_P(PSTR("\n => receive Byte: 0x%02x"), b); - } - } - - } else { - printf_P(PSTR("end")); - return -1; - } - - return 0; -} - -void Ieee485::handleRxByte (uint8_t b) { - receivedByte = b; -} - -#endif \ No newline at end of file diff --git a/software/nano-644/test_2024-07-23/src/units/ieee485.hpp b/software/nano-644/test_2024-07-23/src/units/ieee485.hpp deleted file mode 100644 index ffbb15c..0000000 --- a/software/nano-644/test_2024-07-23/src/units/ieee485.hpp +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef IEEE485_HPP -#define IEEE485_HPP - -#include -#include "../main.hpp" -#include - -class Ieee485 : public TestUnit { - public: - uint8_t enabled; - int16_t receivedByte; - - public: - Ieee485 () { enabled = 0; receivedByte = -1; } - virtual void init (); - virtual void cleanup (); - virtual int8_t run (uint8_t subtest); - virtual const char *getName () { return PSTR("IEEE485"); } - void handleRxByte (uint8_t); -}; - -#endif \ No newline at end of file diff --git a/software/nano-644/test_2024-07-23/src/units/lcd.cpp b/software/nano-644/test_2024-07-23/src/units/lcd.cpp deleted file mode 100644 index 8640690..0000000 --- a/software/nano-644/test_2024-07-23/src/units/lcd.cpp +++ /dev/null @@ -1,264 +0,0 @@ -#include -#include -#include - -#include "lcd.hpp" -#include "../main.hpp" - -#if defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__) - - // Nano-644 - // --------------------------------------------------------------- - // PA3 ..... E --> LCD Enable (Verbindung via J25 erforderlich) - // PD6 ..... R/W --> Read/Write: Read=1, Write=0 - // PD7 ..... RS --> Register Select: Command=0, Data=1 - // PB7:0 ... Data --> Achtung von 5V LCD nicht lesen! - - - // #define LCD_3V3 - #ifdef LCD_3V3 - #define DATA_PIN PINB - #endif - - void Lcd::init () { - DDRA |= (1 << PA3); - DDRB = 0xff; - DDRD |= (1 << PD7) | (1 << PD6); - initLcd(); - #ifdef LCD_3V3 - printf_P(PSTR("init 3.3V LCD")); - #else - printf_P(PSTR("init 5V LCD")); - #endif - } - - void Lcd::cleanup () { - DDRA &= ~(1 << PA3); - DDRB = 0; - DDRD &= ~((1 << PD7) | (1 << PD6)); - } - - void Lcd::setRS () { PORTD |= (1 << PD7); } - void Lcd::clrRS () { PORTD &= ~(1 << PD7); } - void Lcd::setRW () { PORTD |= (1 << PD6); } - void Lcd::clrRW () { PORTD &= ~(1 << PD6); } - void Lcd::setE () { PORTA |= (1 << PA3); } - void Lcd::clrE () { PORTA &= ~(1 << PA3); } - - void Lcd::setData (uint8_t data) { - PORTB = data; - } -#endif - -#ifdef __AVR_ATmega328P__ - - // Arduino Nano (5V) - // --------------------------------------------------------------- - // PC3 ..... E --> LCD Enable (Verbindung via J25 erforderlich) - // PD3 ..... R/W --> Read/Write: Read=1, Write=0 - // PD2 ..... RS --> Register Select: Command=0, Data=1 - // PD4 ..... Data0 - // PB0 ..... Data1 - // PD7 ..... Data2 - // PD6 ..... Data3 - // PB2 ..... Data4 - // PB3 ..... Data5 - // PB4 ..... Data6 - // PB5 ..... Data7 - - void Lcd::init () { - clrRW(); - clrRS(); - clrE(); - setData(0); - DDRB |= (1 << PB5) | (1 << PB4) | (1 << PB3) | (1 << PB2) | (1 << PB0); - DDRC |= (1 << PC3); - DDRD |= (1 << PD7) | (1 << PD6) | (1 << PD4) | (1 << PD3) | (1 << PD2); - initLcd(); - #ifdef LCD_3V3 - printf_P(PSTR("init 3.3V LCD")); - #else - printf_P(PSTR("init 5V LCD")); - #endif - } - - void Lcd::cleanup () { - clrRW(); - clrRS(); - clrE(); - setData(0); - DDRB &= ~((1 << PB5) | (1 << PB4) | (1 << PB3) | (1 << PB2) | (1 << PB0)); - DDRC &= ~(1 << PC3); - DDRD &= ~((1 << PD7) | (1 << PD6) | (1 << PD4) | (1 << PD3) | (1 << PD2)); - } - - void Lcd::setRS () { PORTD |= (1 << PD2); } - void Lcd::clrRS () { PORTD &= ~(1 << PD2); } - void Lcd::setRW () { PORTD |= (1 << PD3); } - void Lcd::clrRW () { PORTD &= ~(1 << PD3); } - void Lcd::setE () { PORTC |= (1 << PC3); } - void Lcd::clrE () { PORTC &= ~(1 << PC3); } - - void Lcd::setData (uint8_t data) { - if (data & 0x01) PORTD |= (1 << PD4); else PORTD &= ~((1 << PD4)); - if (data & 0x02) PORTB |= (1 << PB0); else PORTB &= ~((1 << PB0)); - if (data & 0x04) PORTD |= (1 << PD7); else PORTD &= ~((1 << PD7)); - if (data & 0x08) PORTD |= (1 << PD6); else PORTD &= ~((1 << PD6)); - if (data & 0x10) PORTB |= (1 << PB2); else PORTB &= ~((1 << PB2)); - if (data & 0x20) PORTB |= (1 << PB3); else PORTB &= ~((1 << PB3)); - if (data & 0x40) PORTB |= (1 << PB4); else PORTB &= ~((1 << PB4)); - if (data & 0x80) PORTB |= (1 << PB5); else PORTB &= ~((1 << PB5)); - } -#endif - -// Befehle für das Display - -#define DISP_CLEAR 0b00000001 // Display clear -#define DISP_ON 0b00001111 // Display on -#define DISP_OFF 0b00001011 // Display off -#define CURSOR_ON 0b00001111 // Cursor on -#define CURSOR_OFF 0b00001101 // Cursor off -#define BLINK_ON 0b00001111 // Cursor Blink -#define BLINK_OFF 0b00001110 // Cursor No Blink - -int8_t Lcd::run (uint8_t subtest) { - if (subtest == 0) { - for (uint8_t i = 0; i < 20 * 4; i++) { - char c = (char)(i + 32); - if (i % 20 == 0) { - setCursor(i / 20 + 1, 1); - } - writeData(c); - while (isBusy()) {}; - } - // setCursor(1, 1); - // writeString(" 1234567890<>,;.:-_#+"); - // setCursor(2, 1); - // writeString("abcdefghijklmnopqrst"); - // setCursor(3, 1); - // writeString("uvwxyzABCDEFGHIJKLMN"); - // setCursor(4, 1); - // writeString("OPQRSTUVWXYZ "); - printf_P(PSTR("LCD beschrieben")); - while (wait(1) == EOF) { - } - - } else { - printf_P(PSTR("end")); - return -1; - } - wait(500); - return 0; -} - -void Lcd::initLcd () { - _delay_ms(16); // min 15ms warten für Reset des Displays - - setData( 0b00111011 ); // 8bit Modus, 5x7 Zeichen, Mehrzeilen Display - clrRW(); // write - clrRS(); // command - setE(); // E = 1 (transfer start) - _delay_us(10); // min. 10us - clrE(); // E = 0 (transfer end) - _delay_ms(5); // min. 4.1ms - - setData( 0b00111011 ); // 8bit Modus, 5x7 Zeichen, Mehrzeilen Display - clrRW(); // write - clrRS(); // command - setE(); // E = 1 (transfer start) - _delay_us(10); // min. 10us - clrE(); // E = 0 (transfer end) - _delay_us(100); // min. 100us - - setData( 0b00111011 ); // 8bit Modus, 5x7 Zeichen, Mehrzeilen Display - clrRW(); // write - clrRS(); // command - setE(); // E = 1 (transfer start) - _delay_us(10); // min. 10us - clrE(); // E = 0 (transfer end) - _delay_us(100); // min. 100us - - writeCommand(DISP_OFF); // Display aus - while(isBusy()) {}; - writeCommand(DISP_ON); // Display ein - while(isBusy()) {}; - writeCommand( BLINK_OFF & CURSOR_OFF); // Blink aus und Cursor aus - while(isBusy()) {}; - writeCommand(DISP_CLEAR);// Clear display - while(isBusy()) {}; -} - -uint8_t Lcd::isBusy () { - #ifdef LCD_3V3 - // DIR_DATA_PORT = 0; - // SET_RW_PIN; // read - // CLR_RS_PIN; // command - // SET_E_PIN; // E = 1 (transfer start) - // _delay_us(10); - // uint8_t busy = DATA_PIN & 0x80; // read bit 7 (busy bit) - // CLR_E_PIN; // E = 0 (transfer end) - // CLR_RW_PIN; - // DIR_DATA_PORT = 0xff; - // return busy != 0; - _delay_us(200); - #else - _delay_us(200); - #endif - return 0; -} - -void Lcd::writeCommand (uint8_t cmd) { - setData(cmd); - clrRW(); // write - clrRS(); // command - setE(); // E = 1 (transfer start) - _delay_us(10); // min. 10us - clrE(); // E = 0 (transfer end) - setData(0); -} - -void Lcd::setDDRamAddr (uint8_t address) { - setData(address | 0x80); - clrRW(); // write - clrRS(); // command - setE(); // E = 1 (transfer start) - _delay_us(10); // min. 10us - clrE(); // E = 0 (transfer end) - _delay_us(10); // min. 10us - setData(0); -} - -void Lcd::writeString (const char *s) { - while (*s) { - writeData(*s++); - while (isBusy()) {}; - } -} - -void Lcd::writeData (uint8_t data) { - setData(data); - setRS(); // data - clrRW(); // write - setE(); // E = 1 (transfer start) - _delay_us(10); // min. 10us - clrE(); // E = 0 (transfer end) - _delay_us(10); // min. 10us - clrRS(); - setData(0); -} - -void Lcd::setCursor (uint8_t row, uint8_t column) { - uint8_t b; - if (column > 20) { - return; - } - switch (row) { - case 1: b = 0x00 + column - 1; break; - case 2: b = 0x40 + column - 1; break; - case 3: b = 0x14 + column - 1; break; - case 4: b = 0x54 + column - 1; break; - default: return; - } - setDDRamAddr(b); - while (isBusy()) {}; -} diff --git a/software/nano-644/test_2024-07-23/src/units/lcd.hpp b/software/nano-644/test_2024-07-23/src/units/lcd.hpp deleted file mode 100644 index 3eb4456..0000000 --- a/software/nano-644/test_2024-07-23/src/units/lcd.hpp +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef LCD_HPP -#define LCD_HPP - -#include -#include "../main.hpp" -#include - -class Lcd : public TestUnit { - public: - Lcd () {}; - virtual void init (); - virtual void cleanup (); - virtual int8_t run (uint8_t subtest); - virtual PGM_P getName () { return PSTR("Lcd"); } - - private: - void initLcd (); - uint8_t isBusy (); - void writeCommand (uint8_t); - void setDDRamAddr (uint8_t); - void writeString (const char *s); - void writeData (uint8_t); - void setCursor (uint8_t row, uint8_t column); - void setRS (); - void clrRS (); - void setRW (); - void clrRW (); - void setE (); - void clrE (); - void setData (uint8_t data); - -}; - -#endif \ No newline at end of file diff --git a/software/nano-644/test_2024-07-23/src/units/led.cpp b/software/nano-644/test_2024-07-23/src/units/led.cpp deleted file mode 100644 index 5a56665..0000000 --- a/software/nano-644/test_2024-07-23/src/units/led.cpp +++ /dev/null @@ -1,133 +0,0 @@ -#include -#include -#include - -#include "led.hpp" -#include "../main.hpp" - -#if defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__) - - // Nano-644 - // --------------------------------------------------------------- - // PD4 ..... Red - // PD5 ..... Orange/Yellow - // PD6 ..... Green - // PD7 ..... Blue - - void Led::init () { - PORTD &= ~((1 << PD7) | (1 << PD6) | (1 << PD5) | (1 << PD4)); - DDRD |= (1 << PD7) | (1 << PD6) | (1 << PD5) | (1 << PD4); - } - - void Led::cleanup () { - DDRD &= ~((1 << PD7) | (1 << PD6) | (1 << PD5) | (1 << PD4)); - PORTD &= ~((1 << PD7) | (1 << PD6) | (1 << PD5) | (1 << PD4)); - } - - void Led::setLed (LED led, bool on) { - if (on) { - switch(led) { - case RED: PORTD |= (1 << PD4); break; - case ORANGE: PORTD |= (1 << PD5); break; - case GREEN: PORTD |= (1 << PD6); break; - case BLUE: PORTD |= (1 << PD7); break; - } - } else { - switch(led) { - case RED: PORTD &= ~(1 << PD4); break; - case ORANGE: PORTD &= ~(1 << PD5); break; - case GREEN: PORTD &= ~(1 << PD6); break; - case BLUE: PORTD &= ~(1 << PD7); break; - } - } - } - - void Led::ledToggle (LED led) { - switch(led) { - case RED: PORTD ^= (1 << PD4); break; - case ORANGE: PORTD ^= (1 << PD5); break; - case GREEN: PORTD ^= (1 << PD6); break; - case BLUE: PORTD ^= (1 << PD7); break; - } - } - -#endif - -#ifdef __AVR_ATmega328P__ - - // Arduino-Nano-5V - // --------------------------------------------------------------- - // PD5 ..... Red - // PB1 ..... Orange/Yellow - // PD3 ..... Green - // PD2 ..... Blue - - void Led::init () { - PORTD &= ~((1 << PD5) | (1 << PD3) | (1 << PD2)); - PORTB &= ~(1 << PB1); - DDRD |= (1 << PD5) | (1 << PD3) | (1 << PD2); - DDRB |= (1 << PB1); - } - - void Led::cleanup () { - DDRD &= ~((1 << PD5) | (1 << PD3) | (1 << PD2)); - DDRB &= ~(1 << PB1); - PORTD &= ~((1 << PD5) | (1 << PD3) | (1 << PD2)); - PORTB &= ~(1 << PB1); - } - - void Led::setLed (LED led, bool on) { - if (on) { - switch(led) { - case RED: PORTD |= (1 << PD5); break; - case ORANGE: PORTB |= (1 << PB1); break; - case GREEN: PORTD |= (1 << PD3); break; - case BLUE: PORTD |= (1 << PD2); break; - } - } else { - switch(led) { - case RED: PORTD &= ~(1 << PD5); break; - case ORANGE: PORTB &= ~(1 << PB1); break; - case GREEN: PORTD &= ~(1 << PD3); break; - case BLUE: PORTD &= ~(1 << PD2); break; - } - } - } - - void Led::ledToggle (LED led) { - switch(led) { - case RED: PORTD ^= (1 << PD5); break; - case ORANGE: PORTB ^= (1 << PB1); break; - case GREEN: PORTD ^= (1 << PD3); break; - case BLUE: PORTD ^= (1 << PD2); break; - } - } - -#endif - -void Led::ledOn (LED led) { - setLed(led, true); -} - -void Led::ledOff (LED led) { - setLed(led, false); -} - - -int8_t Led::run (uint8_t subtest) { - if (subtest <= 15) { - subtest = (subtest) % 4; - switch (subtest) { - case 0: ledOff(BLUE); ledOn(RED); break; - case 1: ledOff(RED); ledOn(ORANGE); break; - case 2: ledOff(ORANGE); ledOn(GREEN); break; - case 3: ledOff(GREEN); ledOn(BLUE); break; - } - printf_P(PSTR("Test LED D%d"), subtest + 1); - wait(500); - return 0; - } - - return -1; -} - diff --git a/software/nano-644/test_2024-07-23/src/units/led.hpp b/software/nano-644/test_2024-07-23/src/units/led.hpp deleted file mode 100644 index 780827f..0000000 --- a/software/nano-644/test_2024-07-23/src/units/led.hpp +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef LED_HPP -#define LED_HPP - -#include -#include "../main.hpp" -#include - -class Led : public TestUnit { - public: - enum LED { RED, ORANGE, GREEN, BLUE }; - - public: - Led () {}; - virtual void init (); - virtual void cleanup (); - virtual int8_t run (uint8_t subtest); - virtual PGM_P getName () { return PSTR("Led"); } - - void setLed (LED led, bool on); - void ledOn (LED led); - void ledOff (LED led); - void ledToggle (LED led); -}; - -#endif \ No newline at end of file diff --git a/software/nano-644/test_2024-07-23/src/units/modbus.cpp b/software/nano-644/test_2024-07-23/src/units/modbus.cpp deleted file mode 100644 index abbe36d..0000000 --- a/software/nano-644/test_2024-07-23/src/units/modbus.cpp +++ /dev/null @@ -1,160 +0,0 @@ -#include -#include -#include - -#include "modbus.hpp" -#include "../main.hpp" - - -#ifdef __AVR_ATmega328P__ -void Modbus::init () {} -void Modbus::cleanup () {} -int8_t Modbus::run (uint8_t subtest) { return -1; } -void Modbus::handleRxByte (uint8_t b) {} -#endif - -#if defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__) - -// PB0 ... nRE .. Read enable -// PB1 ... DE .. Data enable - -#define SET_nRE (PORTB |= (1 << PB0)) -#define CLR_nRE (PORTB &= ~(1 << PB0)) -#define SET_DE (PORTB |= (1 << PB1)) -#define CLR_DE (PORTB &= ~(1 << PB1)) - - -void Modbus::init () { -} - -void Modbus::cleanup () { - enabled = 0; - UCSR1A = 0; - UCSR1B = 0; - UCSR1C = 0; - UBRR1H = 0; - UBRR1L = 0; - PORTD &= ~(1 << PD2); - DDRB &= ~((1 << PB1) | (1 << PB0)); - PORTB &= ~((1 << PB1) | (1 << PB0)); -} - -int8_t Modbus::run (uint8_t subtest) { - if (subtest == 0) { - SET_nRE; - CLR_DE; - DDRB |= (1 << PB1) | (1 << PB0); - - // UART1 interface on Nano-644 - PORTD |= (1 << PD2); // enable RxD1 pullup - UCSR1A = (1 << U2X1); - UCSR1B = (1 << RXCIE1) | (1 << RXEN1) | (1 <= 1 && subtest <= 4) { - uint8_t nre, de, b; - switch (subtest) { - case 1: nre = 1; de = 0; b = 0x01; break; - case 2: nre = 1; de = 1; b = 0x8e; break; - case 3: nre = 0; de = 0; b = 0x55; break; - case 4: nre = 0; de = 1; b = 0xaa; break; - default: return -1; - } - printf_P(PSTR(" DE=%u, nRE=%u send 0x%02x... "), de, nre, b); - if (nre) { - SET_nRE; - } else { - CLR_nRE; - } - if (de) { - SET_DE; - } else { - CLR_DE; - } - _delay_us(100); - receivedBytes = 0; - UDR1 = b; - _delay_ms(1); - if (receivedBytes > 0) { - printf_P(PSTR("0x%02x received"), received[0]); - receivedBytes = 0; - } else { - printf_P(PSTR("no byte received")); - } - printf_P(PSTR(" ... press key to proceed")); - while (wait(0xffffffff) == EOF) {} - CLR_DE; - SET_nRE; - - } else if (subtest == 5) { - static uint8_t frame[] = { 0x01, 0x04, 0x00, 0x00, 0x00, 0x02, 0x71, 0xcb }; - printf_P(PSTR("Modbus: lese Spannung von Eastron SDM-230 (Einphasenzähler)")); - SET_DE; - CLR_nRE; - _delay_us(100); - do { - SET_DE; - receivedBytes = 0; - for (uint8_t i = 0; i < sizeof(frame); i++) { - UCSR1A |= (1 << TXC1); - UDR1 = frame[i]; - while ((UCSR1A & (1 < Sending:")); - for (uint8_t i = 0; i < sizeof(frame); i++) { - printf_P(PSTR(" 0x%02x"), frame[i]); - } - int k = wait(100); - - printf_P(PSTR("\n RxD1:")); - if (receivedBytes == 0) { - printf_P(PSTR("?")); - } else { - for (uint8_t i = 0; i < receivedBytes; i++) { - if (i == sizeof(frame)) { - printf_P(PSTR(" ")); - } - printf_P(PSTR(" 0x%02x"), received[i]); - } - } - if (receivedBytes >= 16) { - union { - uint8_t b[4]; - float value; - } f; - f.b[0] = received[14]; - f.b[1] = received[13]; - f.b[2] = received[12]; - f.b[3] = received[11]; - printf_P(PSTR(" -> %4.8fV\n"), (double)f.value); - } - if (k != EOF) { - break; - } - - } while (wait(1000) == EOF); - - } else { - printf_P(PSTR("end")); - return -1; - } - wait(500); - return 0; -} - -void Modbus::handleRxByte (uint8_t b) { - if (receivedBytes < sizeof(received)) { - received[receivedBytes++] = b; - } -} - -#endif \ No newline at end of file diff --git a/software/nano-644/test_2024-07-23/src/units/modbus.hpp b/software/nano-644/test_2024-07-23/src/units/modbus.hpp deleted file mode 100644 index 44b6a9d..0000000 --- a/software/nano-644/test_2024-07-23/src/units/modbus.hpp +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef MODBUS_HPP -#define MODBUS_HPP - -#include -#include "../main.hpp" -#include - -class Modbus : public TestUnit { - public: - uint8_t enabled; - uint8_t receivedBytes; - uint8_t received[16]; - - - public: - Modbus () { enabled = 0; receivedBytes = 0; } - virtual void init (); - virtual void cleanup (); - virtual int8_t run (uint8_t subtest); - virtual PGM_P getName () { return PSTR("Modbus"); } - void handleRxByte (uint8_t); -}; - -#endif \ No newline at end of file diff --git a/software/nano-644/test_2024-07-23/src/units/motor.cpp b/software/nano-644/test_2024-07-23/src/units/motor.cpp deleted file mode 100644 index 4457c1a..0000000 --- a/software/nano-644/test_2024-07-23/src/units/motor.cpp +++ /dev/null @@ -1,207 +0,0 @@ -#include -#include -#include - -#include "motor.hpp" -#include "../main.hpp" - -#if defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__) - - // Nano-644 - // --------------------------------------------------------------- - // PB0 ..... rotation-sensor - // PB2 ..... nFault - // PB3 ..... PWM (OC0A) - // PB4 ..... EN - // PA3 ..... SW3 -> push button for Motor enable control - - #define ADC0K 64 - - void Motor::init () { - ADMUX = (1 << ADLAR) | (1 << REFS0); // ADC0, VREF=AVCC=3.3V - ADCSRA = (1 << ADEN) | 7; // ADC Enable, Prescaler 128 - TCCR0A = (1 << COM0A1) | (1 << WGM01) | (1 << WGM00); // Fast PWM on OC0A - // TCCR0B = (1 << CS02) | ( 1 << CS00); // f = 12 MHz / 1024 = 11,71875 kHz -> fPWM=45Hz - TCCR0B = (1 << CS02); // f = 12 MHz / 256 = 46,875 kHz -> fPWM=183,1Hz - DDRB |= (1 << PB4) | (1 << PB3); // Motor enable - PORTA |= (1 << PORTA3); // push button for Motor enable control - setEnable(); - enabled = 1; - } - - void Motor::cleanup () { - ADMUX = 0; - ADCSRA = 0; - TCCR0A = 0; - TCCR0B = 0; - DDRB &= ~((1 << PB4) | (1 << PB3)); - PORTA &= ~(1 << PORTA3); - enabled = 0; - } - - bool Motor::isSW3Pressed () { - return (PINA & (1 << PC3)) == 0; - } - - void Motor::clearEnable () { - PORTB &= ~(1 << PB4); - } - - void Motor::setEnable () { - PORTB |= (1 << PB4); - } - - bool Motor::isFaultLow () { - return (PINB & (1 << PB2)) == 0; - } - - bool Motor::isSensorHigh () { - return (PINB & (1 << PB0)) != 0; - } -#endif - -#ifdef __AVR_ATmega328P__ - - // Arduino-Nano-5V - // --------------------------------------------------------------- - // PD4 ..... rotation-sensor - // PD7 ..... nFault - // PD6/OC0A ..... PWM - // PB2 ..... EN - // PC3 ..... SW3 -> push button for Motor enable control - - #define ADC0K 91 - - void Motor::init () { - ADMUX = (1 << ADLAR) | (1 << REFS0); // ADC0, VREF=AVCC=5V - ADCSRA = (1 << ADEN) | 7; // ADC Enable, Prescaler 128 - TCCR0A = (1 << COM0A1) | (1 << WGM01) | (1 << WGM00); // Fast PWM on OC0A - // TCCR0B = (1 << CS02) | ( 1 << CS00); // f = 16 MHz / 1024 = 15,625 kHz -> fPWM=61.04Hz - TCCR0B = (1 << CS02); // f = 16 MHz / 256 = 62.5 kHz -> fPWM=244.14Hz - DDRB |= (1 << PB2); - DDRC &= ~(1 << PC3); - DDRD |= (1 << PD6); - DDRD &= ~((1 << PD4) | (1 << PD7)); - PORTC |= ( 1 << PC3); - PORTD |= (1 << PD7) | (1 << PD5); - setEnable(); - enabled = 1; - } - - void Motor::cleanup () { - enabled = 0; - ADMUX = 0; - ADCSRA = 0; - TCCR0A = 0; - TCCR0B = 0; - clearEnable(); - DDRB &= ~((1 << PB2)); - DDRC &= ~(1 << PC3); - DDRD &= ~((1 << PD7) | (1 << PD6) | (1 << PD4)); - PORTC &= ~( 1 << PC3); - PORTD &= ~((1 << PD7) | (1 << PD6)); - } - - bool Motor::isSW3Pressed () { - return (PINC & (1 << PC3)) == 0; - } - - void Motor::clearEnable () { - PORTB &= ~(1 << PB2); - } - - void Motor::setEnable () { - PORTB |= (1 << PB2); - } - - bool Motor::isFaultLow () { - return (PIND & (1 << PD7)) == 0; - } - - bool Motor::isSensorHigh () { - return (PIND & (1 << PD4)) != 0; - } - -#endif - -int8_t Motor::run (uint8_t subtest) { - switch (subtest) { - case 0: { - printf_P(PSTR("\n")); - while (wait(10) == EOF) { - - printf_P(PSTR("\r SW3=%d->"), isSW3Pressed() ? 0 : 1); - if (isSW3Pressed()) { - clearEnable(); - printf_P(PSTR("EN=0")); - } else { - setEnable(); - printf_P(PSTR("EN=1")); - } - - ADCSRA |= (1 << ADSC); // start ADC - while (ADCSRA & (1 << ADSC)) {} // wait for result - printf_P(PSTR("\r => ADC0=%3d"), ADCH); - - ADMUX = (1 << ADLAR) | (1 << REFS1) | (1 << REFS0) | 2; // ADC2, VREF=2.5V - - int16_t x = ((int16_t)(ADCH) - 5) * ADC0K / 64; - if (x < 0) x = 0; else if (x > 255) x = 255; - uint8_t dutyCycle = 0xff - (uint8_t)x; - if (dutyCycle <= 1) { - dutyCycle = 0; - } else if (dutyCycle > 254) { - dutyCycle = 255; - } - OCR0A = dutyCycle; - printf_P(PSTR(" PWM/OC0A=%3d"), dutyCycle); - - ADCSRA |= (1 << ADSC); // start ADC - while (ADCSRA & (1 << ADSC)) {} // wait for result - printf_P(PSTR(" ADC2=%3d"), ADCH); - ADMUX = (1 << ADLAR) | (1 << REFS0); // ADC0, VREF=AVCC=3.3V - - printf_P(PSTR(" nFAULT=%d"), isFaultLow() ? 0 : 1); - printf_P(PSTR(" SENSOR=%d "), isSensorHigh()); - uint16_t timer; - ATOMIC_BLOCK(ATOMIC_FORCEON) { - timer = rpmTimer; - } - float rpm = 60.0 / (float)timer / 0.0001; - if (timer > 0) { - printf_P(PSTR(" n= %4d U/min"), (int)rpm); - } else { - printf_P(PSTR(" no rotation ")); - } - - } - return 0; - } - } - - return -1; -} - -void Motor::tick100us () { - static uint16_t timerH = 0; - static uint16_t timerL = 0; - static bool lastSensorHigh = false; - - bool sensorHigh = isSensorHigh(); - if (!sensorHigh && sensorHigh != lastSensorHigh && timerL > 10) { - rpmTimer = timerL + timerH; - timerL = 0; - timerH = 0; - } - if (sensorHigh) { - timerH = timerH < 0x4000 ? timerH + 1 : 0x4000; - } else { - timerL = timerL < 0x4000 ? timerL + 1 : 0x4000; - } - if (timerH >= 0x4000 || timerL >= 0x4000) { - rpmTimer = 0; // no ratation detected - } - lastSensorHigh = sensorHigh; -} - - diff --git a/software/nano-644/test_2024-07-23/src/units/motor.hpp b/software/nano-644/test_2024-07-23/src/units/motor.hpp deleted file mode 100644 index 6dc68f0..0000000 --- a/software/nano-644/test_2024-07-23/src/units/motor.hpp +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef MOTOR_HPP -#define MOTOR_HPP - -#include -#include "../main.hpp" -#include - -class Motor : public TestUnit { - public: - uint8_t enabled; - uint16_t rpmTimer; - - public: - Motor () { enabled = 0; rpmTimer = 0; }; - virtual void init (); - virtual void cleanup (); - virtual int8_t run (uint8_t subtest); - virtual PGM_P getName () { return PSTR("Motor"); } - void tick100us (); - - private: - bool isSW3Pressed (); - void clearEnable (); - void setEnable (); - bool isFaultLow (); - bool isSensorHigh (); -}; - -#endif \ No newline at end of file diff --git a/software/nano-644/test_2024-07-23/src/units/portexp.cpp b/software/nano-644/test_2024-07-23/src/units/portexp.cpp deleted file mode 100644 index 7eac74d..0000000 --- a/software/nano-644/test_2024-07-23/src/units/portexp.cpp +++ /dev/null @@ -1,169 +0,0 @@ -#include -#include -#include - -#include "portexp.hpp" -#include "../main.hpp" - -// Port-Expander MCP23S17 - -// SN-Print Stecker IO16 -// MCP23S17 | IO16 (MEGA2560) | Ampel-Print | | MCP23S17 | IO16 (MEGA2560) | Ampel-Print | -// ------------------------------------------ -------------------------------------------- -// GPA0 | IO16O7 (PA7) | Taster RU | | GPB0 | IO16U7 (PC7) | Taster LU | -// GPA1 | IO16O6 (PA6) | Taster RO | | GPB1 | IO16U6 (PC6) | Taster LO | -// GPA2 | IO16O5 (PA5) | U-Gruen | | GPB2 | IO16U5 (PC5) | R-Gruen | -// GPA3 | IO16O4 (PA4) | U-Gelb | | GPB3 | IO16U4 (PC4) | R-Gelb | -// GPA4 | IO16O3 (PA3) | U-Rot | | GPB4 | IO16U3 (PC3) | R-Rot | -// GPA5 | IO16O2 (PA2) | L-Gruen | | GPB5 | IO16U2 (PC2) | O-Gruen | -// GPA6 | IO16O1 (PA1) | L-Gelb | | GPB6 | IO16U1 (PC1) | O-Gelb | -// GPA7 | IO16O0 (PA0) | L-Rot | | GPB7 | IO16U0 (PC0) | O-Rot | - -#if defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__) - - // Nano-644 - // -------------------------------------------------------- - // PA7 ... nCS - // PB5 ... MOSI - // PB6 ... MISO - // PB7 ... SCK - - void PortExp::init () { - PRR0 &= (1 << PRSPI); - PORTA |= (1 << PA7); - DDRA |= (1 << PA7); // SPI nCS - // PORTB/DDRB must be configured before SPCR !! - PORTB |= (1 << PB4); // nSS must be HIGH, otherwise SPI master will not become active!! - DDRB |= (1 << PB7) | (1 << PB5) | (1 << PB4); // SPI SCK (=PB7) and SPI MOSI (=PB5) - - // SPCR |= (1 << SPE) | (1 << MSTR) | (1 << SPR1) | (1 << SPR0); // SPI enable , Master, f=12MHz/128=93,75kHz - SPCR = (1 << SPE) | (1 << MSTR); // SPI enable , Master, f=12MHz/4 = 3MHz - } - - void PortExp::cleanup () { - DDRB &= ~(1 << PB6); // // SPI MISO (=PB6) - DDRB &= ~((1 << PB7) | (1 << PB5)); // SPI SCK (=PB7) and SPI MOSI (=PB5) - DDRA &= ~(1 << PA7); - PORTA &= ~(1 << PA7); // SPI nCS - SPCR = 0; - } - - void PortExp::setChipEnable () { - PORTA &= ~(1 << PA7); - } - - void PortExp::clearChipEnable () { - PORTA |= (1 << PA7); - } - - -#endif - -#ifdef __AVR_ATmega328P__ - - // Arduino-Nano-5V - // ------------------------------------ - // PC1 ... nCS (MANUAL (!) connection PA1 - PA7 required) - // PB3 ... MOSI - // PB4 ... MISO - // PB5 ... SCK - - void PortExp::init () { - PRR &= (1 << PRSPI); - PORTC |= (1 << PC1); - DDRC |= (1 << PC1); // SPI nCS - // PORTB/DDRB must be configured before SPCR !! - PORTB |= (1 << PB2); // nSS must be HIGH, otherwise SPI master will not become active!! - DDRB |= (1 << PB5) | (1 << PB3) | (1 << PB2); // SPI SCK (=PB5), SPI MOSI (=PB3), SPI nSS (=PB2) - - // SPCR |= (1 << SPE) | (1 << MSTR) | (1 << SPR1) | (1 << SPR0); // SPI enable , Master, f=16MHz/128=125kHz - SPCR = (1 << SPE) | (1 << MSTR); // SPI enable , Master, f=12MHz/4 = 3MHz - } - - void PortExp::cleanup () { - PORTC &= ~(1 << PC1); - DDRC &= ~(1 << PC1); - PORTB &= ~(1 << PB2); - DDRB &= ~((1 << PB5) | (1 << PB3) | (1 << PB2)); - SPCR = 0; - } - - void PortExp::setChipEnable () { - PORTC &= ~(1 << PC1); - } - - void PortExp::clearChipEnable () { - PORTC |= (1 << PC1); - } - -#endif - - - -int8_t PortExp::writeByte (uint8_t addr, uint8_t b) { - - setChipEnable(); - - SPDR = 0x40; // WRITE BYTE - while ((SPSR & (1 << SPIF)) == 0) {} - if (SPDR != 0) { - printf_P(PSTR("E1")); - clearChipEnable(); - return -1; - } - - SPDR = addr; // register address - while ((SPSR & (1 << SPIF)) == 0) {} - if (SPDR != 0) { - printf_P(PSTR("E2")); - clearChipEnable(); - return -1; - } - - SPDR = b; // value - while ((SPSR & (1 << SPIF)) == 0) {} - if (SPDR != 0) { - printf_P(PSTR("E3")); - clearChipEnable(); - return -1; - } - - clearChipEnable(); - - _delay_us(5); - return 0; -} - -int8_t PortExp::run (uint8_t subtest) { - if (subtest == 0) { - while (wait(500) == EOF) { - printf_P(PSTR("\n => start ...")); - for (uint8_t i = 0; i < 8; i++) { - writeByte(0, ~(1 << i)); // IODIRA (Bank = 0) - // writeByte(0, 0x00); // IODIRA (Bank = 0) - all output - writeByte(0x12, (1 << i)); // GPIOA (Bank = 0) - printf_P(PSTR("\n Bank0 - GPA%d = 1"), i); - wait(200); - writeByte(0x12, 0); // GPIOA (Bank = 0) - printf_P(PSTR("\n Bank0 - GPA%d = 0"), i); - writeByte(0, 0xff); // IODIRA (Bank = 0) - wait(200); - } - for (uint8_t i = 0; i < 8; i++) { - writeByte(1, ~(1 << i)); // IODIRB (Bank = 0) - // writeByte(1, 0x00); // IODIRB (Bank = 0) - all output - writeByte(0x13, (1 << i)); // GPIOB (Bank = 0) - printf_P(PSTR("\n Bank0 - GPB%d = 1"), i); - wait(200); - writeByte(0x13, 0); // GPIOB (Bank = 0) - printf_P(PSTR("\n Bank0 - GPB%d = 0"), i); - writeByte(1, 0xff); // IODIRB (Bank = 0) - wait(200); - } - } - return 0; - } - - return -1; -} - diff --git a/software/nano-644/test_2024-07-23/src/units/portexp.hpp b/software/nano-644/test_2024-07-23/src/units/portexp.hpp deleted file mode 100644 index 2fb665c..0000000 --- a/software/nano-644/test_2024-07-23/src/units/portexp.hpp +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef PORTEXP_HPP -#define PORTEXP_HPP - -#include -#include "../main.hpp" -#include - -class PortExp : public TestUnit { - public: - PortExp () {}; - virtual void init (); - virtual void cleanup (); - virtual int8_t run (uint8_t subtest); - virtual PGM_P getName () { return PSTR("PortExp"); } - - private: - void setChipEnable (); - void clearChipEnable (); - int8_t writeByte (uint8_t addr, uint8_t b); -}; - -#endif \ No newline at end of file diff --git a/software/nano-644/test_2024-07-23/src/units/poti.cpp b/software/nano-644/test_2024-07-23/src/units/poti.cpp deleted file mode 100644 index 94fc5a4..0000000 --- a/software/nano-644/test_2024-07-23/src/units/poti.cpp +++ /dev/null @@ -1,34 +0,0 @@ -#include -#include - -#include "poti.hpp" -#include "../main.hpp" - -void Poti::init () { - ADMUX = (1 << REFS0); // ADC0, VREF=AVCC=3.3V - ADCSRA = (1 << ADEN) | 7; // ADC Enable, Prescaler 128 -} - -void Poti::cleanup () { - ADMUX = 0; - ADCSRA = 0; -} - -int8_t Poti::run (uint8_t subtest) { - switch (subtest) { - case 0: { - printf_P(PSTR("\n")); - while (wait(10) == EOF) { - printf_P(PSTR("\r => Measure ADC0: ")); - ADCSRA |= (1 << ADSC); // start ADC - while (ADCSRA & (1 << ADSC)) {} // wait for result - printf_P(PSTR("%4d (0x%03x)"), ADC, ADC); - } - return 0; - } - } - - return -1; -} - - diff --git a/software/nano-644/test_2024-07-23/src/units/poti.hpp b/software/nano-644/test_2024-07-23/src/units/poti.hpp deleted file mode 100644 index b13dd29..0000000 --- a/software/nano-644/test_2024-07-23/src/units/poti.hpp +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef POTI_HPP -#define POTI_PP - -#include -#include "../main.hpp" -#include - -class Poti : public TestUnit { - public: - Poti () {}; - virtual void init (); - virtual void cleanup (); - virtual int8_t run (uint8_t subtest); - virtual PGM_P getName () { return PSTR("Poti"); } -}; - -#endif \ No newline at end of file diff --git a/software/nano-644/test_2024-07-23/src/units/r2r.cpp b/software/nano-644/test_2024-07-23/src/units/r2r.cpp deleted file mode 100644 index 87fb822..0000000 --- a/software/nano-644/test_2024-07-23/src/units/r2r.cpp +++ /dev/null @@ -1,46 +0,0 @@ -#include -#include - -#include "r2r.hpp" -#include "../main.hpp" - -#if defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__) - // AVCC=3.3, POTI Vmax=3.3V - #define K 1.0 -#endif - -#ifdef __AVR_ATmega328P__ - // AVCC=4.7V, POTI Vmax=3.3V - #define K (1023.0 / 738.0) -#endif - -void R2r::init () { - ADMUX = (1 << REFS0) | 2; // ADC2, VREF=AVCC=3.3V - ADCSRA = (1 << ADEN) | 7; // ADC Enable, Prescaler 128 -} - -void R2r::cleanup () { - ADMUX = 0; - ADCSRA = 0; -} - -int8_t R2r::run (uint8_t subtest) { - switch (subtest) { - case 0: { - printf_P(PSTR("\n")); - while (wait(10) == EOF) { - printf_P(PSTR("\r => Measure ADC2: ")); - ADCSRA |= (1 << ADSC); // start ADC - while (ADCSRA & (1 << ADSC)) {} // wait for result - printf_P(PSTR("%4d (0x%03x)"), ADC, ADC); - uint8_t sw = (uint8_t)( ((float)(ADC) + 32.0) / 64.0 * K ); - printf_P(PSTR(" SW9:6 = %d %d% d %d "), sw >> 3, (sw >> 2) & 0x01, (sw >> 1) & 0x01, sw & 0x01 ); - } - return 0; - } - } - - return -1; -} - - diff --git a/software/nano-644/test_2024-07-23/src/units/r2r.hpp b/software/nano-644/test_2024-07-23/src/units/r2r.hpp deleted file mode 100644 index 84e97e6..0000000 --- a/software/nano-644/test_2024-07-23/src/units/r2r.hpp +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef R2R_HPP -#define R2R_PP - -#include -#include "../main.hpp" -#include - -class R2r : public TestUnit { - public: - R2r () {}; - virtual void init (); - virtual void cleanup (); - virtual int8_t run (uint8_t subtest); - virtual PGM_P getName () { return PSTR("R2R"); } -}; - -#endif \ No newline at end of file diff --git a/software/nano-644/test_2024-07-23/src/units/rgb.cpp b/software/nano-644/test_2024-07-23/src/units/rgb.cpp deleted file mode 100644 index 3f69cbd..0000000 --- a/software/nano-644/test_2024-07-23/src/units/rgb.cpp +++ /dev/null @@ -1,152 +0,0 @@ -#include -#include - -#include "rgb.hpp" -#include "../main.hpp" - -#if defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__) - - // Nano-644 - // --------------------------------------------------------------- - // PB0 ..... Red (inverse logic -> 0 = ON) - // PB1 ..... Green (inverse logic -> 0 = ON) - // PB2 ..... Blue (inverse logic -> 0 = ON) - - void Rgb::init () { - ledOff(RED); - ledOff(GREEN); - ledOff(BLUE); - DDRB |= (1 << PB2) | (1 << PB1) | (1 << PB0); - } - - void Rgb::cleanup () { - ledOff(RED); - ledOff(GREEN); - ledOff(BLUE); - DDRB &= ~((1 << PB2) | (1 << PB1) | (1 << PB0)); - } - - void Rgb::setLed (LED led, bool on) { - if (on) { - switch(led) { - case RED: PORTB &= ~(1 << PB0); break; - case GREEN: PORTB &= ~(1 << PB1); break; - case BLUE: PORTB &= ~(1 << PB2); break; - } - } else { - switch(led) { - case RED: PORTB |= (1 << PB0); break; - case GREEN: PORTB |= (1 << PB1); break; - case BLUE: PORTB |= (1 << PB2); break; - } - } - } - - void Rgb::ledToggle (LED led) { - switch(led) { - case RED: PORTB ^= (1 << PB0); break; - case GREEN: PORTB ^= (1 << PB1); break; - case BLUE: PORTB ^= (1 << PB2); break; - } - } - - -#endif - -#ifdef __AVR_ATmega328P__ - - // Arduino-Nano-5V - // --------------------------------------------------------------- - // PD4 ..... Red (inverse logic -> 0 = ON) - // PB0 ..... Green (inverse logic -> 0 = ON) - // PD7 ..... Blue (inverse logic -> 0 = ON) - - void Rgb::init () { - ledOff(RED); - ledOff(GREEN); - ledOff(BLUE); - DDRB |= (1 << PB0); - DDRD |= (1 << PD7) | (1 << PD4); - } - - void Rgb::cleanup () { - ledOff(RED); - ledOff(GREEN); - ledOff(BLUE); - DDRB &= ~(1 << PB0); - DDRD &= ~((1 << PD7) | (1 << PD4)); - } - - void Rgb::setLed (LED led, bool on) { - if (on) { - switch (led) { - case RED: PORTD &= ~(1 << PD4); break; - case GREEN: PORTB &= ~(1 << PB0); break; - case BLUE: PORTD &= ~(1 << PD7); break; - } - } else { - switch (led) { - case RED: PORTD |= (1 << PD4); break; - case GREEN: PORTB |= (1 << PB0); break; - case BLUE: PORTD |= (1 << PD7); break; - } - } - } - - void Rgb::ledToggle (LED led) { - switch (led) { - case RED: PORTD ^= (1 << PD4); break; - case GREEN: PORTB ^= ~(1 << PB0); break; - case BLUE: PORTD ^= (1 << PD7); break; - } - } - -#endif - -void Rgb::ledOn (LED led) { - setLed(led, true); -} - -void Rgb::ledOff (LED led) { - setLed(led, false); -} - -int8_t Rgb::run (uint8_t subtest) { - switch (subtest) { - case 0: { - ledOn(RED); - printf_P(PSTR("Red")); - wait(3000); - ledOff(RED); - return 0; - } - - case 1: { - ledOn(GREEN); - printf_P(PSTR("Green")); - wait(3000); - ledOff(GREEN); - return 0; - } - - case 2: { - ledOn(BLUE); - printf_P(PSTR("Blue")); - wait(3000); - ledOff(BLUE); - return 0; - } - - case 3: { - ledOn(RED); ledOn(GREEN); ledOn(BLUE); - printf_P(PSTR("All")); - wait(3000); - ledOff(RED); ledOff(GREEN); ledOff(BLUE); - return 0; - } - } - - return -1; -} - - diff --git a/software/nano-644/test_2024-07-23/src/units/rgb.hpp b/software/nano-644/test_2024-07-23/src/units/rgb.hpp deleted file mode 100644 index 12e9da4..0000000 --- a/software/nano-644/test_2024-07-23/src/units/rgb.hpp +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef RGB_HPP -#define RGB_PP - -#include -#include "../main.hpp" -#include - -class Rgb : public TestUnit { - public: - enum LED { RED, GREEN, BLUE }; - - public: - Rgb () {}; - virtual void init (); - virtual void cleanup (); - virtual int8_t run (uint8_t subtest); - virtual PGM_P getName () { return PSTR("Rgb"); } - - void setLed (LED led, bool on); - void ledOn (LED led); - void ledOff (LED led); - void ledToggle (LED led); -}; - -#endif \ No newline at end of file diff --git a/software/nano-644/test_2024-07-23/src/units/rtc8563.cpp b/software/nano-644/test_2024-07-23/src/units/rtc8563.cpp deleted file mode 100644 index 4bd75ca..0000000 --- a/software/nano-644/test_2024-07-23/src/units/rtc8563.cpp +++ /dev/null @@ -1,253 +0,0 @@ -#include -#include -#include -#include -#include - -#include "rtc8563.hpp" -#include "../adafruit/bme280.h" -#include "../main.hpp" - -// RTC BME653EMA on Nano-644 - -const char PSTR_WEEKDAYS[] PROGMEM = "So\0Mo\0Di\0Mi\0Do\0Fr\0Sa\0"; - -// const uint8_t CONFIG[] PROGMEM = { -// /* config -> */ 0x00, 0x00, -// /* enable nINT -> */ 0x01, 0x01, // TIE = 1 -// /* set clock -> */ 0x02, 0x00, 0x00, 0x08, 0x16, 0x02, 0x08, 0x24 -// }; - -void Rtc8563::handleTwiIrq () { - TWCR |= (1 << TWINT); // clear Interrupt Request -} - -#ifdef __AVR_ATmega328P__ -void Rtc8563::init () {} -void Rtc8563::cleanup () {} -int8_t Rtc8563::run (uint8_t subtest) { return -1; } -PGM_P Rtc8563::getName () {} -#endif - -#if defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__) - -void Rtc8563::init () { - PORTC &= ~(1 << PC7); // nInt and nPowerOn (Q7 -> BATTERY) - DDRC |= (1 << PC7); - TWBR = 13; // 100kHz (TWPS1:0 = 00), TWBR = (F_CPU - 16 * 100000) / (2 * 100000 * 4); - TWBR = 28; // 50kHz (TWPS1:0 = 00), TWBR = (F_CPU - 16 * 50000) / (2 * 50000 * 4); - TWBR = 100; // 50kHz (TWPS1:0 = 00), TWBR = (F_CPU - 16 * 50000) / (2 * 50000 * 4); - TWCR = (1 << TWEN); - enabled = true; -} - -void Rtc8563::cleanup () { - enabled = false; - TWCR = (1 << TWEN); - TWBR = 0; - // PORTC &= ~(1 << PC7); - // DDRC &= ~(1 << PC7); -} - -PGM_P Rtc8563::getName () { - return PSTR("RTC-8563"); -} - -uint8_t Rtc8563::bcd2bin (uint8_t value) { - return (value >> 4) * 10 + (value & 0x0f); -} - -int8_t Rtc8563::run (uint8_t subtest) { - int key = EOF; - if (subtest == 0) { - // printf_P(PSTR(" BM280 ... ")); - rtc8563.begin(0x51); - Clock_t clock; - // uint8_t bufferConfig[] = { 0x00, 0x00, 0x01, 0x01 }; - // uint8_t bufferSetClock[] = { 0x02, 0x00, 0x00, 0x08, 0x16, 0x02, 0x08, 0x24 }; - - Rtc8563Reg_t reg; - uint8_t *pReg = (uint8_t *)(void *)® - memset(®, 0, sizeof(reg)); - - printf_P(PSTR("\n => config 8563 ... ")); - reg.reg1.field.tie = 1; - if (!rtc8563.write(pReg, 2)) { - printf_P(PSTR_ERROR); - } else { - printf_P(PSTR_Done); - } - printf_P(PSTR("\n press:")); - printf_P(PSTR("\n t .... timer on/off")); - printf_P(PSTR("\n p .... power on/off (PC7->Q1)")); - printf_P(PSTR("\n c .... init clock")); - printf_P(PSTR("\n w/W .. weekday (+/-)\n")); - printf_P(PSTR("\n y/Y .. year (+/-)")); - printf_P(PSTR("\n m/M .. month (+/-)")); - printf_P(PSTR("\n d/D .. day (+/-)")); - printf_P(PSTR("\n h/H .. hour (+/-)")); - printf_P(PSTR("\n n/N .. minute (+/-)")); - printf_P(PSTR("\n s/S .. second (+/-)\n")); - - do { - uint8_t addr = 0x00; - printf_P(PSTR("\n => read register 0-15 (hex):")); - if (!rtc8563.write_then_read(&addr, 1, pReg, sizeof(reg))) { - printf_P(PSTR_ERROR); - key = waitAndReadKey(1000); - continue; - } - memccpy(&clock, ®.clock, sizeof(clock), sizeof(clock)); - for (uint8_t i = 0; i < 16; i++) { - if (i % 4 == 0) { - printf_P(PSTR(" ")); - } - printf_P(PSTR(" %02X"), pReg[i]); - } - uint16_t year = (clock.month.field.century ? 2100 : 2000) + bcd2bin(clock.year.byte); - int8_t month = bcd2bin(clock.month.byte); - int8_t day = bcd2bin(clock.day.byte); - int8_t hrs = bcd2bin(clock.hour.byte); - int8_t min = bcd2bin(clock.min.byte); - int8_t sec = bcd2bin(clock.sec.byte); - int8_t weekday = clock.weekday.byte; - - PGM_P d = weekday >= 0 && weekday < 7 ? &PSTR_WEEKDAYS[weekday * 3] : PSTR("??"); - printf_P(PSTR(" --> ")); - printf_P(d); - printf_P(PSTR(", %d %04d-%02d-%02d %02d:%02d:%02d"), weekday, year, month, day, hrs, min, sec); - printf_P(PSTR(" - Timer=0x%02x"), reg.timer); - - key = waitAndReadKey(1000); - bool ok = true; - bool change = false; - switch (key) { - case 't': ok &= setTimer(reg.timerControl.field.enable ? 0 : 10, reg); break; - case 'c': ok &= setClock(5, 2024,8,16, 17,12,10 ); break; // ok &= rtc8563.write(bufferSetClock, sizeof(bufferSetClock)); break; - case 'p': powerOnOff(10, reg); break; - case 'y': year++; change = true; break; - case 'Y': year--; change = true; break; - case 'm': month++; change = true; break; - case 'M': month--; change = true; break; - case 'd': day++; change = true; break; - case 'D': day--; change = true; break; - case 'h': hrs++; change = true; break; - case 'H': hrs--; change = true; break; - case 'n': min++; change = true; break; - case 'N': min--; change = true; break; - case 's': sec++; change = true; break; - case 'S': sec--; change = true; break; - case 'w': weekday++; change = true; break; - case 'W': weekday--; change = true; break; - } - if (change) { - printf_P(PSTR("\n set: %04d-%02d-%02d %02d:%02d:%02d"), year, month, day, hrs, min, sec); - setClock(weekday, year, month, day, hrs, min, sec); - } - - } while (key != ESCAPE); - - return 0; - } - - return -1; -} - -bool Rtc8563::setTimer (uint8_t seconds, Rtc8563Reg_t ®) { - - reg.timerControl.field.fd = FDTIMER_1HZ; - reg.timerControl.field.enable = seconds > 0; - reg.timer = seconds; - reg.reg1.field.tie = seconds > 0; - // clear and alarm flag behavior on I2C write different to datasheet - // datasheet: tf cleared to 0, af remains unchanged - // realchip: tf remains 1 and af is set to 1 (no negative result because tie=0 and aie=0) - reg.reg1.field.tf = 0; // clear timer flag - reg.reg1.field.af = 1; // alarm flag remains unchanged - if (seconds > 0) { - printf_P(PSTR("\n Timer set to %ds (1:%02X) ... "), seconds, reg.reg1.byte); - } else { - printf_P(PSTR("\n Timer off ... ")); - } - if (rtc8563.writeByteAndBuffer(0x01, ®.reg1.byte, 1) && rtc8563.writeByteAndBuffer(14, ®.timerControl.byte, 2)) { - printf_P(PSTR("OK")); - return true; - } else { - printf_P(PSTR("fails")); - return false; - } -} - -bool Rtc8563::powerOnOff (uint8_t delayOffSeconds, Rtc8563Reg_t ®) { - int key = EOF; - if (PORTC & (1 << PC7)) { - printf_P(PSTR("\n power on ...")); - DDRC |= ( 1<< PC7); - PORTC &= ~(1 << PC7); - setTimer(0, reg); - } else { - printf_P(PSTR("\n")); - key = EOF; - for (int8_t i = 9; i > 0 && key == EOF; i--) { - printf_P(PSTR("\r press ESC to abort, power off in %ds (press key to skip timer) "), i); - key = waitAndReadKey(1000); - } - if (key == ESCAPE) { - return true; - } - setTimer(10, reg); - reg.reg1.field.af = 1; // alarm flag remains unchanged - reg.reg1.field.tf = 0; // timer flag clear - reg.reg1.field.tie = 1; // enable timer interrupt - rtc8563.writeByteAndBuffer(0x01, ®.reg1.byte, 1); - printf_P(PSTR("\n power off now ...")); - DDRC |= ( 1<< PC7); - PORTC |= (1 << PC7); - _delay_ms(5); - DDRC &= ~( 1<< PC7); - PORTC &= ~(1 << PC7); - waitAndReadKey(5000); - printf_P(PSTR("power off fails, I am still alive :-) ... proceed")); - } - return true; -} - - -bool Rtc8563::setClock (int8_t weekday, uint16_t year, int8_t month, int8_t day, int8_t hour, int8_t min, int8_t sec) { - Clock_t clock; - clock.month.field.century = (year < 2000 || year > 2100) ? 1: 0; - uint8_t y = year % 100; clock.year.field.bcdL = y % 10; clock.year.field.bcdH = y / 10; - - while (weekday < 0) { weekday += 7; } - while (weekday > 6) { weekday -= 7; } - clock.weekday.field.bcdL = weekday; - - while (month < 1) { month += 12; } - while (month > 12) { month -= 12; } - clock.month.field.bcdL = month % 10; clock.month.field.bcdH = month / 10; - - while (day < 1) { day += 31; } - while (day > 31) { day -= 31; } - clock.day.field.bcdL = day % 10; clock.day.field.bcdH = day / 10; - - while (hour < 0) { hour += 24; } - while (hour > 23) { hour -= 24; } - clock.hour.field.bcdL = hour % 10; clock.hour.field.bcdH = hour / 10; - - while (min < 0) { min += 60; } - while (min > 59) { min -= 60; } - clock.min.field.bcdL = min % 10; clock.min.field.bcdH = min / 10; - - while (sec < 0) { sec += 60; } - while (sec > 59) { sec -= 60; } - clock.sec.field.bcdL = sec % 10; clock.sec.field.bcdH = sec / 10; - - printf_P(PSTR("\n %p %p %p %p %p %p %p -> write: "), &clock.sec.byte, &clock.min.byte, &clock.hour.byte, &clock.day.byte, &clock.weekday.byte, &clock.month.byte, &clock.year.byte ); - for (uint8_t i = 0; i < sizeof(clock); i++) { - printf_P(PSTR(" %02x"), ((uint8_t *)(void *)&clock)[i]); - } - return rtc8563.writeByteAndBuffer(0x02, (uint8_t *)(void *)&clock, sizeof(clock)); -} - -#endif - diff --git a/software/nano-644/test_2024-07-23/src/units/rtc8563.hpp b/software/nano-644/test_2024-07-23/src/units/rtc8563.hpp deleted file mode 100644 index ca79713..0000000 --- a/software/nano-644/test_2024-07-23/src/units/rtc8563.hpp +++ /dev/null @@ -1,70 +0,0 @@ -#ifndef RTC8563_HPP -#define RTC8563_HPP - -#include -#include "../main.hpp" -#include "../adafruit/bme280.h" -#include "../adafruit/ens160.h" -#include "../i2cmaster.hpp" -#include "../i2cslave.hpp" - - -class Rtc8563 : public TestUnit { - public: - typedef enum { NORMAL } Rtc8563Mode_t; - - private: - I2cMaster rtc8563; - typedef enum { FDCLOCKOUT_32768HZ = 0, FDCLOCKOUT_1024HZ = 1, FDCLOCKOUT_32HZ = 2, FDCLOCKOUT_1HZ = 3 } FDCLOCKOUT_t; - typedef enum { FDTIMER_4096HZ = 0, FDTIMER_64HZ = 1, FDTIMER_1HZ = 2, FDTIMER_1D60HZ = 3 } FDTIMER_t; - typedef struct { - union { uint8_t byte; struct { uint8_t bcdL:4; uint8_t bcdH:3; uint8_t voltageLow:1; } field; } sec; - union { uint8_t byte; struct { uint8_t bcdL:4; uint8_t bcdH:3; uint8_t notUsed:1; } field; } min; - union { uint8_t byte; struct { uint8_t bcdL:4; uint8_t bcdH:2; uint8_t notUsed:2; } field; } hour; - union { uint8_t byte; struct { uint8_t bcdL:4; uint8_t bcdH:2; uint8_t notUsed:2; } field; } day; - union { uint8_t byte; struct { uint8_t bcdL:3; } field; uint8_t notUsed:5; } weekday; - union { uint8_t byte; struct { uint8_t bcdL:4; uint8_t bcdH:1; uint8_t notUsed:2; uint8_t century:1; } field; } month; - union { uint8_t byte; struct { uint8_t bcdL:4; uint8_t bcdH:4; } field; } year; - } Clock_t; // identical to 8563 register 2..8 - - typedef struct { - union { uint8_t byte; struct { uint8_t bcdL:4; uint8_t bcdH:3; uint8_t enable:1; } field; } min; - union { uint8_t byte; struct { uint8_t bcdL:4; uint8_t bcdH:2; uint8_t notUsed:1; uint8_t enable:1; } field; } hour; - union { uint8_t byte; struct { uint8_t bcdL:4; uint8_t bcdH:2; uint8_t notUsed:1; uint8_t enable:1; } field; } day; - union { uint8_t byte; struct { uint8_t bcdL:3; } field; uint8_t notUsed:4; uint8_t enable_W:1; } weekday; - } Alarm_t; - - typedef struct { - union { uint8_t byte; struct { uint8_t notUsed210:3; uint8_t testC:1; uint8_t notUsed4:1; uint8_t stop:1; uint8_t notUsed6:1; uint8_t test1:1; } field; } reg0; - union { uint8_t byte; struct { uint8_t tie:1; uint8_t aie:1; uint8_t tf:1; uint8_t af:1; uint8_t ti_tp:1; uint8_t notUsed:3; } field; } reg1; - Clock_t clock; - Alarm_t alarm; - union { uint8_t byte; struct { FDCLOCKOUT_t fd:2; uint8_t notUsed65432:5; uint8_t enable:1; } field; } clockoutControl; - union { uint8_t byte; struct { FDTIMER_t fd:2; uint8_t notUsed65432:5; uint8_t enable:1; } field; } timerControl; - uint8_t timer; - } Rtc8563Reg_t; - - - public: - bool enabled; - - public: - Rtc8563 (Rtc8563Mode_t mode) { enabled = false; this->mode = mode; } - void tick1ms () { rtc8563.tick1ms(); } - virtual void init (); - virtual void cleanup (); - virtual int8_t run (uint8_t subtest); - virtual PGM_P getName (); - void handleTwiIrq (); - - private: - Rtc8563Mode_t mode; - uint8_t bcd2bin (uint8_t value); - int8_t runModeNormal (uint8_t subtest); - int8_t runModeBattery (uint8_t subtest); - bool setTimer (uint8_t seconds, Rtc8563Reg_t ®); - bool powerOnOff (uint8_t delayOffSeconds, Rtc8563Reg_t ®); - bool setClock (int8_t weekday, uint16_t year, int8_t month, int8_t day, int8_t hour, int8_t min, int8_t sec); -}; - -#endif \ No newline at end of file diff --git a/software/nano-644/test_2024-07-23/src/units/seg7.cpp b/software/nano-644/test_2024-07-23/src/units/seg7.cpp deleted file mode 100644 index 208107b..0000000 --- a/software/nano-644/test_2024-07-23/src/units/seg7.cpp +++ /dev/null @@ -1,193 +0,0 @@ -#include -#include - -#include "seg7.hpp" -#include "../main.hpp" - -#if defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__) - - // Nano-644 - // --------------------------------------------------------------- - - // PA0 ... Cathode Char 1 - // PA1 ... Cathode Char 2 - // PA2 ... Cathode Char 3 - // PA3 ... Cathode Char 4 - - // PB0 ... Anode Segment A - // PB1 ... Anode Segment B - // PB2 ... Anode Segment C - // PB3 ... Anode Segment D - // PB4 ... Anode Segment E - // PB5 ... Anode Segment F - // PB6 ... Anode Segment G - // PB7 ... Anode DP - - // PD5 ... nOE (Output Enable) for all LEDs - // PD6 ... Anode L1:2 - // PD7 ... Anode L3 - -void Seg7::init () { - setAnodes(0); - setCathodes(0); - DDRA |= (1 << PA3) | (1 << PA2) | (1 << PA1) | (1 << PA0); - DDRB = 0xff; - DDRD |= (1 << PD7) | (1 << PD6) | (1 << PD5); - } - - void Seg7::cleanup () { - setAnodes(0); - setCathodes(0); - DDRA &= ~((1 << PA3) | (1 << PA2) | (1 << PA1) | (1 << PA0)); - DDRB = 0x00; - DDRD &= ~((1 << PD7) | (1 << PD6) | (1 << PD5)); - } - - void Seg7::setAnodes (uint16_t a) { - if (a & 0x0001) PORTB |= (1 << PB0); else PORTB &= ~(1 << PB0); // Anode Char A - if (a & 0x0002) PORTB |= (1 << PB1); else PORTB &= ~(1 << PB1); // Anode Char B - if (a & 0x0004) PORTB |= (1 << PB2); else PORTB &= ~(1 << PB2); // Anode Char C - if (a & 0x0008) PORTB |= (1 << PB3); else PORTB &= ~(1 << PB3); // Anode Char D - if (a & 0x0010) PORTB |= (1 << PB4); else PORTB &= ~(1 << PB4); // Anode Char E - if (a & 0x0020) PORTB |= (1 << PB5); else PORTB &= ~(1 << PB5); // Anode Char F - if (a & 0x0040) PORTB |= (1 << PB6); else PORTB &= ~(1 << PB6); // Anode Char G - if (a & 0x0080) PORTB |= (1 << PB7); else PORTB &= ~(1 << PB7); // Anode Char DP - if (a & 0x0100) PORTD |= (1 << PD6); else PORTD &= ~(1 << PD6); // Anode L1/L2 - if (a & 0x0200) PORTD |= (1 << PD7); else PORTD &= ~(1 << PD7); // Anode L3 - } - - void Seg7::setCathodes (uint8_t c) { - if (c & 0x01) PORTA |= (1 << PA0); else PORTA &= ~(1 << PA0); // Chathode Char 1 (most left) - if (c & 0x02) PORTA |= (1 << PA1); else PORTA &= ~(1 << PA1); // Chathode Char 2 - if (c & 0x04) PORTA |= (1 << PA2); else PORTA &= ~(1 << PA2); // Chathode Char 3 - if (c & 0x08) PORTA |= (1 << PA3); else PORTA &= ~(1 << PA3); // Chathode Char 4 (most right) - } - - void Seg7::setOE (bool enabled) { - if (enabled) { - PORTD &= ~(1 << PD5); - } else { - PORTD |= (1 << PD5); - } - } - -#endif - -#ifdef __AVR_ATmega328P__ - - // Arduino-Nano-5V - // --------------------------------------------------------------- - - // PC0 ... Cathode Char 1 - // PC1 ... Cathode Char 2 - // PC2 ... Cathode Char 3 - // PC3 ... Cathode Char 4 - - // PD4 ... Anode Segment A - // PB0 ... Anode Segment B - // PD7 ... Anode Segment C - // PD6 ... Anode Segment D - // PB2 ... Anode Segment E - // PB3 ... Anode Segment F - // PB4 ... Anode Segment G - // PB5 ... Anode DP - - // PB1 ... nOE (Output Enable) for all LEDs - // PD3 ... Anode L1:2 - // PD2 ,,, Anode L3 - - void Seg7::init () { - enabled = 1; - setAnodes(0); - setCathodes(0); - DDRB |= (1 << PB5) | (1 << PB4) | (1 << PB3) | (1 << PB2) | (1 << PB1) | (1 << PB0) ; - DDRC |= (1 << PC3) | (1 << PC2) | (1 << PC1) | (1 << PC0); - DDRD |= (1 << PD7) | (1 << PD6) | (1 << PD4) | (1 << PD3) | (1 << PD2); - - } - - void Seg7::cleanup () { - enabled = 0; - setAnodes(0); - setCathodes(0); - DDRB &= ~((1 << PB5) | (1 << PB4) | (1 << PB3) | (1 << PB2) | (1 << PB1) | (1 << PB0)); - DDRC &= ~((1 << PC3) | (1 << PC2) | (1 << PC1) | (1 << PC0)); - DDRD &= ~((1 << PD7) | (1 << PD6) | (1 << PD4) | (1 << PD3) | (1 << PD2)); - } - - void Seg7::setAnodes (uint16_t a) { - if (a & 0x0001) PORTD |= (1 << PD4); else PORTD &= ~(1 << PD4); // Anode Char A - if (a & 0x0002) PORTB |= (1 << PB0); else PORTB &= ~(1 << PB0); // Anode Char B - if (a & 0x0004) PORTD |= (1 << PD7); else PORTD &= ~(1 << PD7); // Anode Char C - if (a & 0x0008) PORTD |= (1 << PD6); else PORTD &= ~(1 << PD6); // Anode Char D - if (a & 0x0010) PORTB |= (1 << PB2); else PORTB &= ~(1 << PB2); // Anode Char E - if (a & 0x0020) PORTB |= (1 << PB3); else PORTB &= ~(1 << PB3); // Anode Char F - if (a & 0x0040) PORTB |= (1 << PB4); else PORTB &= ~(1 << PB4); // Anode Char G - if (a & 0x0080) PORTB |= (1 << PB5); else PORTB &= ~(1 << PB5); // Anode Char DP - if (a & 0x0100) PORTD |= (1 << PD3); else PORTD &= ~(1 << PD3); // Anode L1/L2 - if (a & 0x0200) PORTD |= (1 << PD2); else PORTD &= ~(1 << PD2); // Anode L3 - } - - void Seg7::setCathodes (uint8_t c) { - if (c & 0x01) PORTC |= (1 << PC0); else PORTC &= ~(1 << PC0); // Chathode Char 1 (most left) - if (c & 0x02) PORTC |= (1 << PC1); else PORTC &= ~(1 << PC1); // Chathode Char 2 - if (c & 0x04) PORTC |= (1 << PC2); else PORTC &= ~(1 << PC2); // Chathode Char 3 - if (c & 0x08) PORTC |= (1 << PC3); else PORTC &= ~(1 << PC3); // Chathode Char 4 (most right) - } - - void Seg7::setOE (bool enabled) { - if (enabled) { - PORTB &= ~(1 << PB1); - } else { - PORTB |= (1 << PB1); - } - } - -#endif - -const char *segName[] = { "A", "B", "C", "D", "E", "F", "G", "DP" }; - - -int8_t Seg7::run (uint8_t subtest) { - if (subtest == 0) { - setCathodes(0x0f); // all segment cathodes conected to GND - setAnodes(0x3ff); // all segments ON - setOE(true); - printf_P(PSTR("ON")); - wait(2000); - setAnodes(0); - return 0; - - } else if (subtest == 1) { - printf_P(PSTR("OFF")); - wait(1000); - return 0; - - } else if (subtest == 2) { - setAnodes(0x100); // L1/L2 ON - printf_P(PSTR("L1/L2 ON")); - wait(1000); - setAnodes(0); - return 0; - - } else if (subtest == 3) { - setAnodes(0x200); // L3 ON - printf_P(PSTR("L1/L2 ON")); - wait(1000); - setAnodes(0); - return 0; - - } else if (subtest < (4 + 4 * 8)) { - uint8_t chIndex = (subtest - 4) / 8; - uint8_t segIndex = (subtest - 4) % 8; - setCathodes(1 << chIndex); - setAnodes(1 << segIndex); - printf_P(PSTR("Char %d - %s -> %02x"), chIndex, segName[segIndex], (1 << segIndex)); - wait(400); - return 0; - } - - return -1; -} - - diff --git a/software/nano-644/test_2024-07-23/src/units/seg7.hpp b/software/nano-644/test_2024-07-23/src/units/seg7.hpp deleted file mode 100644 index 0e71fde..0000000 --- a/software/nano-644/test_2024-07-23/src/units/seg7.hpp +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef SEG7_HPP -#define SEG7_HPP - -#include -#include "../main.hpp" -#include - -class Seg7 : public TestUnit { - public: - bool enabled; - - public: - Seg7 () { enabled = false; } - virtual void init (); - virtual void cleanup (); - virtual int8_t run (uint8_t subtest); - virtual PGM_P getName () { return PSTR("Seg7"); } - - private: - void setAnodes (uint16_t); - void setCathodes (uint8_t mask); - void setOE (bool enabled); -}; - -#endif \ No newline at end of file diff --git a/software/nano-644/test_2024-07-23/src/units/switch.cpp b/software/nano-644/test_2024-07-23/src/units/switch.cpp deleted file mode 100644 index 4ce9456..0000000 --- a/software/nano-644/test_2024-07-23/src/units/switch.cpp +++ /dev/null @@ -1,100 +0,0 @@ -#include -#include -#include - -#include "switch.hpp" -#include "../main.hpp" - -#if defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__) - - // Nano-644 - // --------------------------------------------------------------- - // PA0 ..... SW1 - // PA1 ..... SW2 - // PA2 ..... SW3 - // PA3 ..... SW4 - - void Switch::init () { - DDRA &= ~((1 << PORTA3) | (1 << PORTA2) | (1 << PORTA1) | (1 << PORTA0)); - PORTA |= (1 << PORTA3) | (1 << PORTA2) | (1 << PORTA1) | (1 << PORTA0); - } - - void Switch::cleanup () { - PORTA &= ~((1 << PORTA3) | (1 << PORTA2) | (1 << PORTA1) | (1 << PORTA0)); - DDRA &= ~((1 << PORTA3) | (1 << PORTA2) | (1 << PORTA1) | (1 << PORTA0)); - } - - bool Switch::isPressed (SWITCH sw) { - switch (sw) { - case SW1: return (PINA & ( 1 << PA0)) == 0; - case SW2: return (PINA & ( 1 << PA1)) == 0; - case SW3: return (PINA & ( 1 << PA2)) == 0; - case SW4: return (PINA & ( 1 << PA3)) == 0; - default: return false; - } - } - -#endif - -#ifdef __AVR_ATmega328P__ - - // Arduino-Nano-5V - // --------------------------------------------------------------- - // PC0 ..... SW1 - // PC1 ..... SW2 - // PC2 ..... SW3 - // PC3 ..... SW4 - - void Switch::init () { - DDRC &= ~((1 << PORTC3) | (1 << PORTC2) | (1 << PORTC1) | (1 << PORTC0)); - PORTC |= (1 << PORTC3) | (1 << PORTC2) | (1 << PORTC1) | (1 << PORTC0); - } - - void Switch::cleanup () { - PORTC &= ~((1 << PORTC3) | (1 << PORTC2) | (1 << PORTC1) | (1 << PORTC0)); - DDRC &= ~((1 << PORTC3) | (1 << PORTC2) | (1 << PORTC1) | (1 << PORTC0)); - } - - bool Switch::isPressed (SWITCH sw) { - switch (sw) { - case SW1: return (PINC & ( 1 << PC0)) == 0; - case SW2: return (PINC & ( 1 << PC1)) == 0; - case SW3: return (PINC & ( 1 << PC2)) == 0; - case SW4: return (PINC & ( 1 << PC3)) == 0; - default: return false; - } - } - -#endif - -int8_t Switch::run (uint8_t subtest) { - if (subtest < 16) { - SWITCH sw = (SWITCH)(subtest / 4); - switch (subtest % 4) { - case 1: { - if (!isPressed(sw)) { - printf_P(PSTR("Press SW%d"), sw + 1); - while (!isPressed(sw) && wait(0) == EOF) {} - wait(10); - } - return 0; - } - - case 0: case 2: { - if (isPressed(sw)) { - printf_P(PSTR("Release SW%d "), sw + 1); - while (isPressed(sw) && wait(0) == EOF) {} - wait(10); - } - return 0; - } - - case 3: { - return 0; - } - } - - } - - return -1; -} diff --git a/software/nano-644/test_2024-07-23/src/units/switch.hpp b/software/nano-644/test_2024-07-23/src/units/switch.hpp deleted file mode 100644 index 03bf0b2..0000000 --- a/software/nano-644/test_2024-07-23/src/units/switch.hpp +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef SWITCH_HPP -#define SWITCH_HPP - -#include -#include "../main.hpp" -#include - -class Switch : public TestUnit { - typedef enum { SW1 = 0, SW2 = 1, SW3 = 2, SW4 = 3 } SWITCH; - - public: - Switch () {}; - virtual void init (); - virtual void cleanup (); - virtual int8_t run (uint8_t subtest); - virtual PGM_P getName () { return PSTR("Switch"); } - bool isPressed (SWITCH sw); -}; - -#endif \ No newline at end of file diff --git a/software/nano-644/test_2024-07-23/src/units/uart1.cpp b/software/nano-644/test_2024-07-23/src/units/uart1.cpp deleted file mode 100644 index 57e0bfb..0000000 --- a/software/nano-644/test_2024-07-23/src/units/uart1.cpp +++ /dev/null @@ -1,65 +0,0 @@ -#include -#include -#include - -#include "uart1.hpp" -#include "../main.hpp" - -#ifdef __AVR_ATmega328P__ - void Uart1::init () {} - void Uart1::cleanup () {} - int8_t Uart1::run (uint8_t subtest) { return -1; } - void Uart1::handleRxByte (uint8_t b) {} -#endif - -#if defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__) - -int uart1_putchar(char c, FILE *stream) { - if (c == '\n') { - uart1_putchar('\r', stream); - } - loop_until_bit_is_set(UCSR1A, UDRE1); - UDR1 = c; - return 0; -} - -static FILE mystderr = { 0, 0, _FDEV_SETUP_WRITE , 0, 0, uart1_putchar, NULL, 0 }; - -void Uart1::init () { - PORTD |= (1 << PD2); // enable RxD1 pullup - UCSR1A = (1 << U2X1); - UCSR1B = (1 << RXCIE1) | (1 << RXEN1) | (1 < send text via UART1 now...")); - fprintf_P(stderr, PSTR("Hello UART1, ECHO-Modus active\n")); - } while (wait(5000) == EOF); - return 0; - } - - return -1; -} - -void Uart1::handleRxByte (uint8_t b) { - uart1_putchar(b, stderr); -} - -#endif \ No newline at end of file diff --git a/software/nano-644/test_2024-07-23/src/units/uart1.hpp b/software/nano-644/test_2024-07-23/src/units/uart1.hpp deleted file mode 100644 index 40437e1..0000000 --- a/software/nano-644/test_2024-07-23/src/units/uart1.hpp +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef UART1_HPP -#define UART1_HPP - -#include -#include "../main.hpp" -#include - -class Uart1 : public TestUnit { - public: - uint8_t enabled; - - public: - Uart1 () { enabled = 0; } - virtual void init (); - virtual void cleanup (); - virtual int8_t run (uint8_t subtest); - virtual PGM_P getName () { return PSTR("Uart1"); } - void handleRxByte (uint8_t); -}; - -#endif \ No newline at end of file diff --git a/software/test-software/.gdb_history b/software/test-software/.gdb_history new file mode 100644 index 0000000..3339046 --- /dev/null +++ b/software/test-software/.gdb_history @@ -0,0 +1,9 @@ +target remote :1234 +layout split +stepi +quit +target remote :1234 +layout split +stepi +b *main+9 +quit diff --git a/software/test-software/.gdbinit b/software/test-software/.gdbinit new file mode 100644 index 0000000..139597f --- /dev/null +++ b/software/test-software/.gdbinit @@ -0,0 +1,2 @@ + + diff --git a/software/test-software/.gitignore b/software/test-software/.gitignore new file mode 100644 index 0000000..a959910 --- /dev/null +++ b/software/test-software/.gitignore @@ -0,0 +1,4 @@ +.depend +**/build +**/dist +**/sim diff --git a/software/test-software/.vscode/c_cpp_properties.json b/software/test-software/.vscode/c_cpp_properties.json new file mode 100644 index 0000000..3a57c79 --- /dev/null +++ b/software/test-software/.vscode/c_cpp_properties.json @@ -0,0 +1,18 @@ +{ + "configurations": [ + { + "name": "Linux AVR", + "includePath": [ + "/usr/lib/avr/include/**", + "/usr/lib/gcc/avr/**" + ], + "defines": [], + "compilerPath": "/usr/bin/avr-gcc", + "compilerArgs": [ "-mmcu=atmega644p", "-DF_CPU=12000000", "-Os" ], + "cStandard": "gnu11", + "cppStandard": "gnu++11", + "intelliSenseMode": "linux-gcc-x64" + } + ], + "version": 4 +} diff --git a/software/test-software/.vscode/launch.json b/software/test-software/.vscode/launch.json new file mode 100644 index 0000000..f29cf2e --- /dev/null +++ b/software/test-software/.vscode/launch.json @@ -0,0 +1,37 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Build", + // "request": "launch", + "type": "node-terminal", + "preLaunchTask": "build" + },{ + "name": "Flash", + // "request": "launch", + "type": "node-terminal", + "preLaunchTask": "flash" + },{ + "name": "Clean", + // "request": "launch", + "type": "node-terminal", + "preLaunchTask": "clean" + },{ + // es muss mit simuc --board arduino dist/programm.elf der Simulator + // gestartet werden. Dessen gdb-stub öffnet auf localhost:1234 einen Port + "name": "Debug (simuc)", + "type": "cppdbg", + "request": "launch", + "program": "${workspaceFolder}/sim/atmega328p.elf", + "cwd": "${workspaceFolder}", + "externalConsole": false, + "MIMode": "gdb", + "miDebuggerPath": "/usr/bin/avr-gdb", + "miDebuggerServerAddress": ":1234", + "preLaunchTask": "build" + } + ] +} diff --git a/software/test-software/.vscode/settings.json b/software/test-software/.vscode/settings.json new file mode 100644 index 0000000..58539af --- /dev/null +++ b/software/test-software/.vscode/settings.json @@ -0,0 +1,29 @@ +{ + "[c]": { + "editor.insertSpaces": true, + "editor.tabSize": 3, + "editor.detectIndentation": false + }, + "[cpp]": { + "editor.insertSpaces": true, + "editor.tabSize": 3, + "editor.detectIndentation": false + }, + "[h]": { + "editor.insertSpaces": true, + "editor.tabSize": 3, + "editor.detectIndentation": false + }, + "[hpp]": { + "editor.insertSpaces": true, + "editor.tabSize": 3, + "editor.detectIndentation": false + }, + "cSpell.words": [], + "cSpell.ignorePaths": [ + "**/*.json", "**/*.c", "**/*.h", "**/*.cpp", "**/*.hpp", "**/Makefile" + ], + "java.project.sourcePaths": [ + "src/units" + ] +} diff --git a/software/test-software/.vscode/tasks.json b/software/test-software/.vscode/tasks.json new file mode 100644 index 0000000..74fb1c7 --- /dev/null +++ b/software/test-software/.vscode/tasks.json @@ -0,0 +1,23 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=733558 + // for the documentation about the tasks.json format + "version": "2.0.0", + "tasks": [{ + "label": "build", + "type": "shell", + "command": "make", + "problemMatcher":[ + "$gcc" + ] + },{ + "label": "clean", + "type": "shell", + "command": "make", + "args": [ "clean" ], + },{ + "label": "flash", + "type": "shell", + "command": "make", + "args": [ "flash" ], + }] +} \ No newline at end of file diff --git a/software/test-software/LICENSE b/software/test-software/LICENSE new file mode 100644 index 0000000..c9565b9 --- /dev/null +++ b/software/test-software/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 Manfred Steiner (Manfred.Steiner@gmx.at) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/software/test-software/Makefile b/software/test-software/Makefile new file mode 100644 index 0000000..9df5e1b --- /dev/null +++ b/software/test-software/Makefile @@ -0,0 +1,27 @@ +.PHONY: all release clean-all clean + +SEP = -------------------------------------------------------- + +all: + @printf "\n\e[1;36m$(SEP)\n Arduino Nano\n$(SEP)\e[m\n" + -@make -C nano-328 + @printf "\n\e[1;36m$(SEP)\nNano-644\n$(SEP)\e[m\n" + -@make -C nano-644 + @printf "\n\e[1;36m$(SEP)\n Nano-1284\n$(SEP)\e[m\n" + -@make -C nano-1284 + +release: + -@make -C nano-328 release + -@make -C nano-644 release + -@make -C nano-1284 release + +clean-all: clean + test -d nano-328/release && rm -r nano-328/release + test -d nano-644/release && rm -r nano-644/release + test -d nano-1284/release && rm -r nano-1284/release + +clean: + @make -C nano-328 clean + @make -C nano-644 clean + @make -C nano-1284 clean + diff --git a/software/test-software/README.md b/software/test-software/README.md new file mode 100644 index 0000000..cfc24f0 --- /dev/null +++ b/software/test-software/README.md @@ -0,0 +1,37 @@ +# Test-Software for Nano-X-Base + +This software supports: +* Arduino Nano (ATmega328P, 16MHz, 5V) +* Nano-644 (ATmega644P, 12MHz, 3.3V) +* Nano-1284 (ATmega1284P, 12MHz, 3.3V) + +For the Nano-X-Base hardware version: +* V1a +* V2a + +## System requirements + +Makefiles and scripts are designed for running in a Linux system. +It is tested on a Debian system. + +## Build + +* To build all files use `make` +* To create release folder use `make release` +* To clean this folder use `make clean` + (release files are not removed) + +## Flashing the target + +Ensure that bootloader is available on target. Then change to the subdirectory of your target and execute `make flash`. + +Bootloader git repository: +[https://git.htl-mechatronik.at/public/?p=bootloader-arduino.git;a=home](https://git.htl-mechatronik.at/public/?p=bootloader-arduino.git;a=home) + +For example: +``` +user@pc:~/nano-x-base/software/test-software$ cd nano-328 +user@pc:~/nano-x-base/software/test-software/nano-328$ make flash +... +user@pc:~/nano-x-base/software/test-software/nano-328$ make picocom +``` diff --git a/software/test-software/create-release b/software/test-software/create-release new file mode 100755 index 0000000..90a8fff --- /dev/null +++ b/software/test-software/create-release @@ -0,0 +1,120 @@ +#!/bin/sh +#set -x + +while [ ! -z "$1" ]; do + DIR="$1" + FILE="$2" + + #echo " creating release folder for file $FILE in directory $DIR ..." + + if [ ! -d "$DIR" ]; then + printf " [1;31mERROR: missing target directory $DIR\e[m\n" + exit 1 + fi + + if [ -z "$FILE" ] || [ ! -f "$FILE" ]; then + printf " [1;31mERROR: missing file $FILE\e[m\n" + exit 2 + fi + + shift + shift + + DATE_OBJDUMP=$(avr-objdump -tT "$FILE" 2>&1 | grep -e _.*DATE) + if [ -z "$DATE_OBJDUMP" ]; then + printf " \e[1;31mERROR ($FILE -> $DIR): symbol DATE not found\e[m\n" + exit 3 + fi + + TIME_OBJDUMP=$(avr-objdump -tT "$FILE" 2>&1 | grep -e _.*TIME) + if [ -z "$DATE_OBJDUMP" ]; then + printf " \e[1;31mERROR ($FILE -> $DIR): symbol TIME not found\e[m\n" + exit 4 + fi + + TEXT_SECT_READELF=$(readelf --syms ${FILE} | grep " .text") + if [ -z "$DATE_OBJDUMP" ]; then + printf " \e[1;31mERROR ($FILE -> $DIR): symbol .text not found\e[m\n" + exit 5 + fi + + avr-objcopy --dump-section .text=/tmp/.dumpsection.bin "$FILE" + SECT_TEXT_OFFSET_HEX="0x$(echo "$TEXT_SECT_READELF" | tr '\t' ' ' | tr -s ' ' | cut -d' ' -f 3)" + SECT_TEXT_OFFSET=$(( $(printf "%d" $SECT_TEXT_OFFSET_HEX) )) + + DATE_OFFSET_HEX="0x$(echo "$DATE_OBJDUMP" | cut -d " " -f 1)" + DATE_LENGTH_HEX="0x$(echo "$DATE_OBJDUMP" | tr '\t' ' ' | tr -s ' ' | cut -d' ' -f 5)" + DATE_OFFSET=$(( $(printf "%d" $DATE_OFFSET_HEX) - $SECT_TEXT_OFFSET )) + DATE_LENGTH=$(( $(printf "%d" $DATE_LENGTH_HEX) - 1)) + + TIME_OFFSET_HEX="0x$(echo "$TIME_OBJDUMP" | cut -d " " -f 1)" + TIME_LENGTH_HEX="0x$(echo "$TIME_OBJDUMP" | tr '\t' ' ' | tr -s ' ' | cut -d' ' -f 5)" + TIME_OFFSET=$(( $(printf "%d" $TIME_OFFSET_HEX) - $SECT_TEXT_OFFSET )) + TIME_LENGTH=$(( $(printf "%d" $TIME_LENGTH_HEX) - 1)) + + DATE_STRING=$(hexdump -s ${DATE_OFFSET} -n ${DATE_LENGTH} -e "${DATE_LENGTH} \"%_p\" \"\\n\"" /tmp/.dumpsection.bin) + TIME_STRING=$(hexdump -s ${TIME_OFFSET} -n ${TIME_LENGTH} -e "${TIME_LENGTH} \"%_p\" \"\\n\"" /tmp/.dumpsection.bin) + + DATE_MONTH_STRING=$(echo $DATE_STRING | cut -d' ' -f1) + case "$DATE_MONTH_STRING" in + Jan) DATE_MONTH="1";; + Feb) DATE_MONTH="2";; + Mar) DATE_MONTH="3";; + Apr) DATE_MONTH="4";; + May) DATE_MONTH="5";; + Jun) DATE_MONTH="6";; + Jul) DATE_MONTH="7";; + Aug) DATE_MONTH="8";; + Sep) DATE_MONTH="9";; + Oct) DATE_MONTH="10";; + Nov) DATE_MONTH="11";; + Dec) DATE_MONTH="12";; + *) printf " \e[1;31mERROR ($FILE -> $DIR): invalidate date ($DATE_STRINGS) in file $FILE\e[m\n"; exit 6;; + esac + + DATE_DAY=$(echo $DATE_STRING | cut -d' ' -f2 | sed 's/^0*//') + DATE_YEAR=$(echo $DATE_STRING | cut -d' ' -f3 | sed 's/^0*//') + TIME_VALUE=$(echo $TIME_STRING | cut -d' ' -f2-) + TIME_HOUR=$(echo $TIME_STRING | cut -d ':' -f1 | sed 's/^0*//') + TIME_MINUTE=$(echo $TIME_STRING | cut -d ':' -f2 | sed 's/^0*//') + TIME_SECOND=$(echo $TIME_STRING | cut -d ':' -f3 | sed 's/^0*//') + + NAME=$(printf "v%4d-%02d-%02d_%02d%02d%02d" $DATE_YEAR $DATE_MONTH $DATE_DAY $TIME_HOUR $TIME_MINUTE $TIME_SECOND | egrep ^v[0-9]{4}-[0-9]{2}-[0-9]{1,2}_[0-9]{2}[0-9]{2}[0-9]{2}$) + if [ -z "$NAME" ]; then + printf " \e[1;31mERROR ($FILE -> $DIR): cannot create release name\e[m\n" + exit 7 + fi + FILENAME=$(echo "$FILE" | rev | cut -d"/" -f1 | rev) + if [ -d "$DIR/$NAME" ] && [ -f "$DIR/$NAME/$FILENAME" ]; then + echo " OK: release already created ($FILE -> $DIR/$NAME)" + else + test -d "$DIR/$NAME" || mkdir "$DIR/$NAME" + cp -a "$FILE" "$DIR/$NAME/" + if [ $? = 0 ]; then + echo " OK ($FILE -> $DIR/$NAME)" + else + printf " \e[1;31mERROR ($FILE -> $DIR)\e[m\n" + exit 8 + fi + fi + for suffix in "hex" "bin"; do + SUFFIXFILE=$(echo $FILE | sed "s/.elf$/.${suffix}/") + SUFFIXFILENAME=$(echo "$SUFFIXFILE" | rev | cut -d"/" -f1 | rev) + if [ -f "$SUFFIXFILE" ]; then + if [ -d "$DIR/$NAME" ] && [ -f "$DIR/$NAME/$SUFFIXFILENAME" ]; then + echo " OK: release ${suffix}-file already created ($FILE -> $DIR/$NAME)" + else + test -d "$DIR/$NAME" || mkdir "$DIR/$NAME" + cp -a "$SUFFIXFILE" "$DIR/$NAME/" + if [ $? = 0 ]; then + echo " OK ($SUFFIXFILE -> $DIR/$NAME)" + else + printf " \e[1;31mERROR ($SUFFIXFILE -> $DIR)\e[m\n" + exit 8 + fi + fi + fi + done + +done + diff --git a/software/test-software/create-release.old b/software/test-software/create-release.old new file mode 100755 index 0000000..225277f --- /dev/null +++ b/software/test-software/create-release.old @@ -0,0 +1,86 @@ +#!/bin/sh +#set -x + +while [ ! -z "$1" ]; do + DIR="$1" + FILE="$2" + + #echo " creating release folder for file $FILE in directory $DIR ..." + + if [ ! -d "$DIR" ]; then + printf " [1;31mERROR: missing target directory $DIR\e[m\n" + exit 1 + fi + + if [ -z "$FILE" ] || [ ! -f "$FILE" ]; then + printf " [1;31mERROR: missing file $FILE\e[m\n" + exit 2 + fi + + shift + shift + + DATE_OBJDUMP=$(avr-objdump -tT "$FILE" 2>&1 | grep MAIN_CPP_DATE) + if [ -z "$DATE_OBJDUMP" ]; then + printf " [1;31mERROR ($FILE -> %DIR): symbol MAIN_CPP_DATE not found\e[m\n" + exit 3 + fi + + TIME_OBJDUMP=$(avr-objdump -tT "$FILE" 2>&1 | grep MAIN_CPP_TIME) + if [ -z "$DATE_OBJDUMP" ]; then + printf " [1;31mERROR ($FILE -> %DIR): symbol MAIN_CPP_TIME not found\e[m\n" + exit 4 + fi + + DATE_OFFSET_HEX="0x$(echo "$DATE_OBJDUMP" | cut -d " " -f 1)" + TIME_OFFSET_HEX="0x$(echo "$TIME_OBJDUMP" | cut -d " " -f 1)" + DATE_OFFSET=$(( $(printf "%d" $DATE_OFFSET_HEX) + 148 )) + TIME_OFFSET=$(( $(printf "%d" $TIME_OFFSET_HEX) + 148 )) + + DATE_STRINGS=$(strings -a -t d "$FILE" | grep "$(printf "%7s" "$DATE_OFFSET")") + TIME_STRINGS=$(strings -a -t d "$FILE" | grep "$(printf "%7s" "$TIME_OFFSET")") + + DATE_MONTH_STRING=$(echo $DATE_STRINGS | cut -d' ' -f2) + case "$DATE_MONTH_STRING" in + Jan) DATE_MONTH="01";; + Feb) DATE_MONTH="02";; + Mar) DATE_MONTH="03";; + Apr) DATE_MONTH="04";; + May) DATE_MONTH="05";; + Jun) DATE_MONTH="06";; + Jul) DATE_MONTH="07";; + Aug) DATE_MONTH="08";; + Sep) DATE_MONTH="09";; + Oct) DATE_MONTH="10";; + Nov) DATE_MONTH="11";; + Dec) DATE_MONTH="12";; + *) printf " [1;31mERROR ($FILE -> %DIR): invalidate date in file $FILE\e[m\n"; exit 5;; + esac + + DATE_DAY=$(echo $DATE_STRINGS | cut -d' ' -f3) + DATE_YEAR=$(echo $DATE_STRINGS | cut -d' ' -f4) + TIME_VALUE=$(echo $TIME_STRINGS | cut -d' ' -f2-) + TIME_HOUR=$(echo $TIME_VALUE | cut -d ':' -f1) + TIME_MINUTE=$(echo $TIME_VALUE | cut -d ':' -f2) + TIME_SECOND=$(echo $TIME_VALUE | cut -d ':' -f3) + + NAME=$(printf "v%4d-%02d-%02d_%02d%02d%02d" $DATE_YEAR $DATE_MONTH $DATE_DAY $TIME_HOUR $TIME_MINUTE $TIME_SECOND | egrep ^v[0-9]{4}-[0-9]{2}-[0-9]{1,2}_[0-9]{2}[0-9]{2}[0-9]{2}$) + if [ -z "$NAME" ]; then + printf " [1;31mERROR ($FILE -> %DIR): cannot create release name\e[m\n" + exit 6 + fi + FILENAME=$(echo "$FILE" | rev | cut -d"/" -f1 | rev) + if [ -d "$DIR/$NAME" ] && [ -f "$DIR/$NAME/$FILENAME" ]; then + echo " OK: release already done ($FILE -> $DIR/$NAME)" + else + test -d "$DIR/$NAME" || mkdir "$DIR/$NAME" + cp -a "$FILE" "$DIR/$NAME/" + if [ $? = 0 ]; then + echo " OK ($FILE -> $DIR/$NAME)" + else + printf " [1;31mERROR ($FILE -> %DIR)\e[m\n" + fi + fi + +done + diff --git a/software/test-software/nano-1284/Makefile b/software/test-software/nano-1284/Makefile new file mode 100644 index 0000000..8485c67 --- /dev/null +++ b/software/test-software/nano-1284/Makefile @@ -0,0 +1,262 @@ +$(shell mkdir -p dist >/dev/null) +$(shell mkdir -p build >/dev/null) +$(shell mkdir -p sim >/dev/null) +$(shell mkdir -p sim/build >/dev/null) +$(shell mkdir -p release/sim >/dev/null) + +# -------------------------------------------------------------------------------- +# Variables configured by engineer + +NAME=nano-x-base_test-software_nano-m1284p_12mhz +DEVICE=atmega1284p +AVRDUDE_DEVICE=m1284p +CPU_FREQUENCY=12000000 +BAUDRATE=115200 +START_ADDRESS=0 + +# -------------------------------------------------------------------------------- +# Automatic created Makefile variables + +SRC= $(wildcard src/*.c src/*.cpp src/*/*.c src/*/*.cpp) +HDR= $(wildcard src/*.h src/*.hpp src/*/*.h src/*/*.hpp) +MAINSRC= $(wildcard src/main.c src/main.cpp) +OBJ_CPP = $(SRC:src/%.cpp=build/%.o) +OBJ = $(OBJ_CPP:src/%.c=build/%.o) +OBJ_SIM_CPP = $(SRC:src/%.cpp=sim/build/%.o) +OBJ_SIM = $(OBJ_SIM_CPP:src/%.c=sim/build/%.o) + +CC= avr-g++ +CFLAGS= -Wall -mmcu=$(DEVICE) -Os -DF_CPU=$(CPU_FREQUENCY) -DBAUD_RATE=$(BAUDRATE) -DDOUBLE_SPEED -DNUM_LED_FLASHES=4 '-DMAX_TIME_COUNT=F_CPU>>4' -c +#LFLAGS= -Wall -mmcu=$(DEVICE) -Os -DF_CPU=$(CPU_FREQUENCY) -Wl,-u,vfprintf -lprintf_flt -lm +LFLAGS= -Wall -mmcu=$(DEVICE) -Os -DF_CPU=$(CPU_FREQUENCY) -Wl,--section-start=.text=$(START_ADDRESS) + +CFLAGS_SIM= -Wall -mmcu=$(DEVICE) -Og -DF_CPU=$(CPU_FREQUENCY) -g -DBAUD_RATE=$(BAUDRATE) -DDOUBLE_SPEED -DNUM_LED_FLASHES=4 '-DMAX_TIME_COUNT=F_CPU>>4' -c +#LFLAGS_SIM= -Wall -mmcu=$(DEVICE) -Og -DF_CPU=$(CPU_FREQUENCY) -g -Wl,-u,vfprintf -lprintf_flt -lm +LFLAGS_SIM= -Wall -mmcu=$(DEVICE) -Og -DF_CPU=$(CPU_FREQUENCY) -g -Wl,--section-start=.text=$(START_ADDRESS) + +# -------------------------------------------------------------------------------- +# make targets + +.PHONY: all +all: dist/$(NAME).elf sim/$(NAME).elf dist/$(NAME).s dist/$(NAME).hex dist/$(NAME).bin sim/$(NAME).s info + +.PHONY: info +info: + @echo + @avr-size --mcu=$(DEVICE) --format=avr dist/$(NAME).elf + +# -------------------------------------------------------------------------------- +# dependency make for hierarchical source file structure + +.depend: $(SRC) $(HDR) + $(CC) -mmcu=$(DEVICE) -MM $(SRC) | sed --regexp-extended 's/^(.*\.o)\: src\/(.*)(\.cpp|\.c) (.*)/build\/\2\.o\: src\/\2\3 \4/g' > .depend + +ifneq (clean,$(filter clean,$(MAKECMDGOALS))) +-include .depend +endif + +# -------------------------------------------------------------------------------- +# elf, hex and assembler file creation + +dist/$(NAME).elf: .depend $(OBJ) + $(CC) $(LFLAGS) -o $@ $(OBJ) + +dist/%.s: dist/%.elf + avr-objdump -d $< > $@ + +dist/%.hex: dist/%.elf + avr-objcopy -O ihex $(HEX_FLASH_FLAGS) $< $@ + +dist/%.bin: dist/%.elf + avr-objcopy -O binary $(HEX_FLASH_FLAGS) $< $@ + +# -------------------------------------------------------------------------------- +# check if the macros __DATE__ or __TIME__ are used in src/main.cpp or src/main.c + +DATE_USED= +ifneq ($(shell cat $(MAINSRC) | grep __DATE__),) + DATE_USED=true +endif +TIME_USED= +ifneq ($(shell cat $(MAINSRC) | grep __TIME__),) + TIME_USED=true +endif + +ifeq (true, $(filter true, $(DATE_USED) $(TIME_USED))) +build/main.o: $(MAIN_SRC) $(SRC) $(HDR) + @mkdir -p $(dir $@) + $(CC) $(CFLAGS) -o $@ $< +endif + +# -------------------------------------------------------------------------------- + +build/%.o: src/%.c + @mkdir -p $(dir $@) + $(CC) $(CFLAGS) -o $@ $< + +build/%.o: src/%.cpp + @mkdir -p $(dir $@) + $(CC) $(CFLAGS) -o $@ $< + +# -------------------------------------------------------------------------------- +# simulation/debugging with gdb or simuc + +sim/$(NAME).elf: .depend $(OBJ_SIM) + $(CC) $(LFLAGS_SIM) -o $@ $(OBJ_SIM) + @ln -sf $(NAME).elf sim/$(DEVICE).elf + +sim/build/%.o: src/%.c + @mkdir -p $(dir $@) + $(CC) $(CFLAGS_SIM) -o $@ $< + +sim/build/%.o: src/%.cpp + @mkdir -p $(dir $@) + $(CC) $(CFLAGS_SIM) -o $@ $< + +sim/%.s: sim/%.elf + avr-objdump -d $< > $@ + +ifeq (m16, $(AVRDUDE_DEVICE)) +simuc: sim/$(NAME).elf + simuc --board sure $< +endif + +ifeq (m328p, $(AVRDUDE_DEVICE)) +simuc: sim/$(NAME).elf + simuc --board arduino $< +endif + +ifeq (m644p, $(AVRDUDE_DEVICE)) +simuc: sim/$(NAME).elf + simuc --board nano-644 $< +endif + +ifeq (m1284p, $(AVRDUDE_DEVICE)) +simuc: sim/$(NAME).elf + simuc --board nano-1284 $< +endif + +gdb: sim/$(NAME).elf + avr-gdb $< + +# ------------------------------------------------------------- +# flash to target with arduino bootloader in bootloader-section + +.PHONY: flash +flash: dist/$(NAME).elf all + avrdude -c arduino -P /dev/ttyUSB0 -b $(BAUDRATE) -p $(AVRDUDE_DEVICE) -e -U flash:w:$< + +.PHONY: flash0 +flash0: dist/$(NAME).elf all + avrdude -c arduino -P /dev/ttyUSB0 -b $(BAUDRATE) -p $(AVRDUDE_DEVICE) -e -U flash:w:$< + +.PHONY: flash1 +flash1: dist/$(NAME).elf all + avrdude -c arduino -P /dev/ttyUSB1 -b $(BAUDRATE) -p $(AVRDUDE_DEVICE) -e -U flash:w:$< + +.PHONY: flash2 +flash2: dist/$(NAME).elf all + avrdude -c arduino -P /dev/ttyUSB2 -b $(BAUDRATE) -p $(AVRDUDE_DEVICE) -e -U flash:w:$< + +.PHONY: flash-read +flash-read: + avrdude -c arduino -P /dev/ttyUSB0 -b $(BAUDRATE) -p $(AVRDUDE_DEVICE) -U flash:r:/tmp/flash.bin + +.PHONY: flash-disassemble +flash-disassemble: flash-read + avr-objdump -b binary -D -m avr5 /tmp/flash.bin > /tmp/flash.s + less /tmp/flash.s + +.PHONY: flash-hexdump +flash-hexdump: flash-read + hexdump -C /tmp/flash.bin | less + +# ---------------------------------------------- +# flash to target with fischl programming device + +.PHONY: isp-flash-$(AVRDUDE_DEVICE) +isp-$(AVRDUDE_DEVICE): + avrdude -c usbasp -p $(AVRDUDE_DEVICE) -U lock:r:-:h + avrdude -c usbasp -p $(AVRDUDE_DEVICE) + +.PHONY: isp-flash +isp-flash: dist/$(NAME).elf all + avrdude -c usbasp -p $(AVRDUDE_DEVICE) -e -U flash:w:$< + +.PHONY: isp-flash-$(AVRDUDE_DEVICE) +isp-flash-$(AVRDUDE_DEVICE): dist/$(NAME).elf all + avrdude -c usbasp -p $(AVRDUDE_DEVICE) -e -U flash:w:$< + +.PHONY: isp-read-flash-$(AVRDUDE_DEVICE) +isp-read-flash-$(AVRDUDE_DEVICE): + avrdude -c usbasp -p m32$(AVRDUDE_DEVICE)8p -U flash:r:/tmp/flash-arduino-atmega328p__$(shell date +"%Y-%m-%d_%H%M%S") + +.PHONY: isp-fuse +isp-fuse: isp-fuse-$(AVRDUDE_DEVICE) + +.PHONY: isp-fuse-$(AVRDUDE_DEVICE) +ifeq (m16, $(AVRDUDE_DEVICE)) +isp-fuse-$(AVRDUDE_DEVICE): + avrdude -c usbasp -p $(AVRDUDE_DEVICE) -U lfuse:w:0x18:m -U hfuse:w:0xD8:m -U lock:w:0xEF:m +endif +ifeq (m328p, $(AVRDUDE_DEVICE)) +isp-fuse-$(AVRDUDE_DEVICE): + avrdude -c usbasp -p $(AVRDUDE_DEVICE) -U lfuse:w:0xEF:m -U hfuse:w:0xD8:m -U efuse:w:0xFD:m -U lock:w:0xEF:m +endif +ifeq (m644p, $(AVRDUDE_DEVICE)) +isp-fuse-$(AVRDUDE_DEVICE): + avrdude -c usbasp -p $(AVRDUDE_DEVICE) -U lfuse:w:0xEF:m -U hfuse:w:0xD8:m -U efuse:w:0xFD:m -U lock:w:0xEF:m +endif +ifeq (m1284p, $(AVRDUDE_DEVICE)) +isp-fuse-$(AVRDUDE_DEVICE): + avrdude -c usbasp -p $(AVRDUDE_DEVICE) -U lfuse:w:0xEF:m -U hfuse:w:0xD8:m -U efuse:w:0xFD:m -U lock:w:0xEF:m +endif + +# -------------------------------------------------------- +# picocom sends CR for ENTER -> convert cr (\r) to lf (\n) + +.PHONY: picocom +picocom: + picocom -b $(BAUDRATE) --omap crlf --raise-dtr /dev/ttyUSB0 + +.PHONY: picocom0 +picocom0: + picocom -b $(BAUDRATE) --omap crlf --raise-dtr /dev/ttyUSB0 + +.PHONY: picocom1 +picocom1: + picocom -b $(BAUDRATE) --omap crlf --raise-dtr /dev/ttyUSB1 + +.PHONY: picocom2 +picocom2: + picocom -b $(BAUDRATE) --omap crlf --raise-dtr /dev/ttyUSB2 + +# -------------------------------------------------------- + +.PHONY: help +help: + @echo + @echo "Possible targets are:" + @echo " clean" + @echo " all help info" + @echo " flash flash0 flash1 flash2 flash-read flash-disassemble flash-hexdump" + @echo " isp-$(AVRDUDE_DEVICE) isp-flash-$(AVRDUDE_DEVICE) isp-fuse-$(AVRDUDE_DEVICE)" + @echo " picocom picocom0 picocom1 picocom2" + @echo " gdb simuc" + @echo + +# -------------------------------------------------------- + +.PHONY: release +release: dist/$(NAME).elf sim/$(NAME).elf dist/$(NAME).hex dist/$(NAME).bin + ../create-release release $(word 1, $^) release/sim $(word 2, $^) + +# -------------------------------------------------------- + +.PHONY: clean +clean: + @rm -r dist + @rm -r build + @rm -r sim + @find . -type f -name ".depend" -exec rm {} \; + @echo "clean done" diff --git a/software/test-software/nano-1284/release/v2024-10-31_172633/nano-x-base_test-software_nano-m1284p_12mhz.bin b/software/test-software/nano-1284/release/v2024-10-31_172633/nano-x-base_test-software_nano-m1284p_12mhz.bin new file mode 100755 index 0000000..c677dd5 Binary files /dev/null and b/software/test-software/nano-1284/release/v2024-10-31_172633/nano-x-base_test-software_nano-m1284p_12mhz.bin differ diff --git a/software/test-software/nano-1284/release/v2024-10-31_172633/nano-x-base_test-software_nano-m1284p_12mhz.elf b/software/test-software/nano-1284/release/v2024-10-31_172633/nano-x-base_test-software_nano-m1284p_12mhz.elf new file mode 100755 index 0000000..a51e773 Binary files /dev/null and b/software/test-software/nano-1284/release/v2024-10-31_172633/nano-x-base_test-software_nano-m1284p_12mhz.elf differ diff --git a/software/test-software/nano-1284/release/v2024-10-31_172633/nano-x-base_test-software_nano-m1284p_12mhz.hex b/software/test-software/nano-1284/release/v2024-10-31_172633/nano-x-base_test-software_nano-m1284p_12mhz.hex new file mode 100644 index 0000000..eeb6af2 --- /dev/null +++ b/software/test-software/nano-1284/release/v2024-10-31_172633/nano-x-base_test-software_nano-m1284p_12mhz.hex @@ -0,0 +1,2313 @@ +:100000000C9434070C945E070C945E070C945E0706 +:100010000C945E070C945E070C945E070C945E07CC +:100020000C945E070C94580B0C945E070C945E07BE +:100030000C945E070C945E070C945E070C945E07AC +:100040000C945E070C945E070C945E070C945E079C +:100050000C949C0A0C945E070C945E070C945E074B +:100060000C945E070C945E070C94180B0C945E07BE +:100070000C94D30A0C945E070C945E070C945E07F4 +:100080000C945E070C945E070C945E07076342367F +:10009000B79BD8A71A39685618AEBAAB558C1D3C19 +:1000A000B7CC5763BD6DEDFD753EF6177231BF00DD +:1000B0000000803F08000000BE922449123EABAA17 +:1000C000AA2ABECDCCCC4C3E00000080BEABAAAA72 +:1000D000AA3E00000000BF000000803F00000000BA +:1000E00000084178D3BB4387D1133D190E3CC3BDF3 +:1000F0004282AD2B3E68EC8276BED98FE1A93E4CA0 +:1001000080EFFFBE01C4FF7F3F000000000063647A +:10011000696E6F70737578585B000A2534643A20F5 +:10012000005D3A20000A0A5B000A53656C6563743F +:1001300020756E69743A2000253378202E2E2E20EB +:10014000004552524F523A20496E76616C696420E4 +:1001500048617264776172652028256429004176C0 +:1001600061696C61626C6520756E6974733A0A0A24 +:100170000048617264776172653A20255300202F30 +:100180002000202F20000A0A48617264776172659E +:100190002025532064657465637465642028414498 +:1001A0004337483D30782530325829000A496E7669 +:1001B000616C69642048617264776172652D56656F +:1001C0007273696F6E3A204144433748203D2025C1 +:1001D00064202841546D65676131323834502C20D9 +:1001E000332E3356290A00563F3F005632610056DF +:1001F000316100446F6E65004552524F52000A0053 +:100200000A3D3D3D3D3D3D3D3D3D3D3D3D3D3D3D51 +:100210003D3D3D3D3D3D3D3D3D3D3D3D3D3D3D3D0E +:100220003D3D3D3D3D3D0A200041546D65676131D6 +:10023000323834500031373A32363A3333004F6374 +:10024000742033312032303234000A505441424C51 +:10025000452025643A203078253032780020213D31 +:1002600020307825303278000A00205B5741524E0A +:100270003A2062756666657220746F20736D616CDA +:100280006C5D2000204F4B5B72656365697665206D +:1002900025642062797465735D2000204552524FB9 +:1002A000525B7265636569766520256420627974A6 +:1002B00065732C20657870656374202564206279ED +:1002C0007465735D20005D20002030782530325841 +:1002D00000205374617465735B004552525D005D8C +:1002E0000020307825303278000A205B7265616426 +:1002F0005265676973746572732830782530327877 +:100300002C202E2E2E2C202564295D202D3E200011 +:100310004552525D003078253032782C7374617408 +:1003200075733D3078253032785D000A205B726548 +:10033000616452656769737465722830782530325C +:100340007829202D3E20004552525D00737461745F +:1003500075733D3078253032785D00202D3E2000C9 +:1003600020307825303278000A205B777269746516 +:1003700052656769737465727328307825303278F6 +:10038000293A20004552525D007374617475733DC3 +:100390003078253032785D000A205B7772697465A9 +:1003A0005265676973746572283078253032782C0D +:1003B0002030782530327829202D3E20004F4B0008 +:1003C0006661696C73004F4B2C20696E6974205014 +:1003D000415441424C45202E2E2E20006661696C0E +:1003E00073004F4B2C20696E6974207265676973C6 +:1003F000746572202E2E2E20006661696C730020B9 +:10040000726573657420434331313031202E2E2EB6 +:10041000200043432D313130312D3F0043432D31F6 +:100420003130312D546573740043432D31313031F7 +:100430002D526563656976650043432D3131303156 +:100440002D53656E6400646F6E652028737461744B +:10045000653D3078253032782900202E2E2E200060 +:10046000202530325800256420646174612062794F +:100470007465732028484558293A20004552524F48 +:10048000522C20004F4B2C200020525353493D2525 +:10049000642C204C51493D25642C204352432000BC +:1004A000202D3E200045320063616E63656C6C65F3 +:1004B00064004532004F4B2C207265636569766598 +:1004C000202E2E2E20003F202849444C4529006331 +:1004D000616E63656C6C6564004531000A205B25C4 +:1004E0003034785D203D3E207374617274202E2E6E +:1004F0002E20004F4B004531005D202D3E20002076 +:100500002530325800202D2D3E2073656E64202545 +:100510006420627974657320284845583A20253054 +:10052000325800307825303278004531000A205B9F +:10053000253034785D3A2073746174653D006661DE +:10054000696C73002850415441424C45203D203095 +:100550007825303258290064426D20000A207377D4 +:100560006974636820706F77657220746F20002053 +:10057000757365202B20616E64202D20666F7220BC +:10058000706F776572206368616E676520286F748D +:10059000686572206B6579202D3E206261636B2057 +:1005A000746F2064656661756C742900292E064796 +:1005B0007A0E14040400000600216276CAF816229E +:1005C000F840073018166C434991876BFB5610E9C9 +:1005D0002A001F4100597F3F813509C6392E360058 +:1005E000C031310000C531300000CD370000008639 +:1005F000350000005030000000372D360000262D59 +:100600003130001D2D313500172D323000032D33D0 +:1006100030002535642028307825303278292000B4 +:100620000D20203D3E20456E636F6465722028706A +:1006300075736820746F20636C656172293A2000BD +:10064000456E636F64657200656E64000A2049320E +:100650004320534C4156453A2066726F6D206D61C0 +:10066000737465723A20307825303278202D3E2020 +:10067000746F206D61737465723A20307825303262 +:100680007800453100202D3E204552524F52003017 +:100690007825303278002C202066726F6D20736CC4 +:1006A0006176653A2000202D3E204552524F52007F +:1006B0000A204932432D4D41535445523A20746F1C +:1006C00020736C6176653A203078253032780045A9 +:1006D0003100453300290062616400706F6F720061 +:1006E0006661697200676F6F6400657863656C6C42 +:1006F000656E74003F002C2065636F323D256428D1 +:1007000000292C2074766F633D2564707062003F71 +:1007100000756E6865616C74687900706F6F720047 +:100720006D6F64657261746500676F6F64006578F2 +:1007300063656C6C656E7400206171693D25642889 +:1007400000453200252E3166C2B0432F252E31667A +:100750002525293A20004531290020207C20454EBE +:10076000533136302028002C20483D20252E32667B +:100770002525002C20543D20252E3266C2B0430092 +:100780000A203D3E20424D3238303A20503D20254F +:100790002E3366626172004F4B00453400453300D2 +:1007A0004532004F4B2C20454E53313630202E2EF3 +:1007B0002E200045310020424D323830202E2E2E82 +:1007C00020004932432D536C617665004932432D38 +:1007D0004D6173746572004932432D537061726BC1 +:1007E00066756E20456E762D436F6D626F00656E87 +:1007F00064000A20203D3E207265636569766520AD +:10080000427974653A20307825303278000A202009 +:100810003D3E2073656E64204279746520307825F2 +:10082000303278004945454534383500656E6400FE +:100830004552524F5228256429004F4B004C4344E7 +:1008400020004552524F5220256429004F4B290069 +:10085000696E6974204C43442028004C6364005442 +:10086000657374204C454420442564004C65640045 +:10087000656E6400202D3E2025342E3866560A0011 +:1008800020307825303278002020003F000A2020D8 +:100890002020202020527844313A00203078253022 +:1008A0003278000A203D3E2053656E64696E673AD7 +:1008B000004D6F646275733A206C657365205370E8 +:1008C000616E6E756E6720766F6E2045617374720F +:1008D0006F6E2053444D2D323330202845696E70A1 +:1008E000686173656E7AC3A4686C65722900202EF6 +:1008F0002E2E207072657373206B657920746F20C3 +:1009000070726F63656564006E6F20627974652034 +:1009100072656365697665640030782530327820C9 +:100920007265636569766564002044453D25752CD4 +:10093000206E52453D25752073656E642030782504 +:100940003032782E2E2E2000696E6974004D6F644F +:100950006275730020206E6F20726F746174696F0E +:100960006E2028543D253034782920200020206E28 +:100970003D2025356420552F6D696E2028543D2576 +:1009800030347829002053454E534F523D25642082 +:1009900000206E4641554C543D256400204144439F +:1009A000323D25336400202050574D2F4F433041B6 +:1009B0003D253364000D20203D3E20414443303D21 +:1009C00025336400454E3D3100454E3D30000D203D +:1009D0005357333D25642D3E000A004D6F746F72EE +:1009E000000A202042616E6B30202D2047504225A6 +:1009F00064203D2030000A202042616E6B30202DA3 +:100A0000204750422564203D2031000A20204261C9 +:100A10006E6B30202D204750412564203D20300052 +:100A20000A202042616E6B30202D20475041256402 +:100A3000203D2031000A203D3E20737461727420F5 +:100A40002E2E2E002900204F4B00204A5033392EE5 +:100A5000322F33206A756D706572656420286C656D +:100A60006674293F00204552524F5200202872657B +:100A7000616420307825303278202D3E2030782572 +:100A800030327800506F72744578700025346420DD +:100A90002830782530337829000D20203D3E204D28 +:100AA00065617375726520414443303A20000A0045 +:100AB000506F7469002025332E3166203D3E20534F +:100AC00057393A36203D20256420256425206420AE +:100AD00025642020002534642028307825303378A0 +:100AE00029000D20203D3E204D6561737572652003 +:100AF000414443323A20000A0052325200416C6CA9 +:100B000000426C756500477265656E005265640051 +:100B1000526762002025303278000A202570202597 +:100B200070202570202570202570202570202570CC +:100B3000202D3E2077726974653A2000706F7765CA +:100B400072206F6666206661696C732C2049206193 +:100B50006D207374696C6C20616C697665203A2D28 +:100B600029202E2E2E2070726F63656564000A2086 +:100B7000706F776572206F6666206E6F77202E2EFD +:100B80002E000D2070726573732045534320746FDF +:100B90002061626F72742C20706F776572206F66AF +:100BA0006620696E20256473202870726573732037 +:100BB0006B657920746F20736B69702074696D6543 +:100BC000722920000A000A20706F776572206F6E0C +:100BD000202E2E2E006661696C73004F4B000A2098 +:100BE00054696D6572206F6666202E2E2E20000AD5 +:100BF0002054696D65722073657420746F202564BC +:100C0000732028313A2530325829202E2E2E2000EC +:100C10000A207365743A20253034642D25303264FF +:100C20002D2530326420253032643A253032643A42 +:100C30002530326400202D2054696D65723D307876 +:100C400025303278002C20256420253034642D2571 +:100C50003032642D2530326420253032643A25301C +:100C600032643A253032640020202D2D3E20003F92 +:100C70003F0020253032580020000A203D3E2072DF +:100C800065616420726567697374657220302D3107 +:100C9000352028686578293A000A202020732F53D0 +:100CA000202E2E207365636F6E6420282B2F2D2934 +:100CB0000A000A2020206E2F4E202E2E206D696EF5 +:100CC00075746520282B2F2D29000A202020682FDD +:100CD00048202E2E20686F757220282B2F2D29007A +:100CE0000A202020642F44202E2E206461792028A1 +:100CF0002B2F2D29000A2020206D2F4D202E2E2055 +:100D00006D6F6E746820282B2F2D29000A2020205B +:100D1000792F59202E2E207965617220282B2F2DB6 +:100D200029000A202020772F57202E2E2077656556 +:100D30006B64617920282B2F2D290A000A2020209E +:100D400063202E2E2E2E20696E697420636C6F63D3 +:100D50006B000A20202070202E2E2E2E20706F7700 +:100D60006572206F6E2F6F666620285043372D3EC8 +:100D7000513129000A20202074202E2E2E2E20747E +:100D8000696D6572206F6E2F6F6666000A20707243 +:100D90006573733A000A203D3E20636F6E66696793 +:100DA0002038353633202E2E2E20005254432D3835 +:100DB00035363300536F004D6F004469004D6900B4 +:100DC000446F004672005361000043686172202541 +:100DD00064202D202573202D3E2025303278004CB4 +:100DE000312F4C32204F4E004C312F4C32204F4E81 +:100DF000004F4646004F4E00536567370052656C02 +:100E000065617365205357256420005072657373C4 +:100E10002053572564005377697463680048656CF4 +:100E20006C6F2055415254312C204543484F2D4D75 +:100E30006F647573206163746976650A000A203DEA +:100E40003E2073656E642074657874207669612035 +:100E50005541525431206E6F772E2E2E00556172FF +:100E6000743100007639353A11241FBECFEFD0E43B +:100E7000DEBFCDBF12E0A0E0B1E0E2E1FFE800E0BC +:100E80000BBF02C007900D92A635B107D9F724E039 +:100E9000A6E5B2E001C01D92A63EB207E1F717E059 +:100EA000C4E3D7E004C02197FE010E94923CC23304 +:100EB000D107C9F70E94F1370C9487470C940000C2 +:100EC000FC01108211820895FC019181992311F097 +:100ED000915091830895FC01608384E68093B8006B +:100EE00084E08093BC0081E0089584E08093BC009E +:100EF0001092B80008954150FB0194E824EC4F3F54 +:100F0000D1F0442319F02093BC0002C09093BC00A0 +:100F10008091BC0087FFFCCF8091B900887F44237B +:100F200019F0803519F009C0883539F48091BB007B +:100F300081934150E4CF81E0089580E00895DC0181 +:100F4000FB0184E835E0442389F0222311F09491D9 +:100F500001C090819093BB008093BC0011963C939C +:100F600011979091BC0097FFFCCF02C081E00895DB +:100F70009091B90041503196987F983221F380E0EA +:100F80000895FC0184EA8093BC0085E08183809110 +:100F9000BC0087FFFCCF9091B900987F983011F08A +:100FA0009031B1F49081990F962B9093BB0084E817 +:100FB0008093BC0085E081838091BC0087FFFCCFDB +:100FC0009091B900987F611105C081E0983129F0B6 +:100FD00080E0089581E09034D9F708950F931F932E +:100FE000CF93DF93D62F8A01C22F60E00E94C10702 +:100FF000811102C080E016C0F80124E8D093BB0044 +:101000002093BC009091BC0097FFFCCF9091B90059 +:10101000987F983279F7D1919FEF9C0FCC2311F0F4 +:10102000C92FECCFDF91CF911F910F91089584E9E3 +:101030008093BC008091BC0084FDFCCF81E00895CA +:10104000FF920F931F93CF93DF93EC018B01F42E4C +:1010500061E00E94C107882379F04F2DB801CE01CD +:101060000E947B07882341F0CE01DF91CF911F9131 +:101070000F91FF900C94170880E0DF91CF911F91A2 +:101080000F91FF900895FF920F931F93CF93DF93DB +:10109000EC018B01F42E60E00E94C107882381F0EF +:1010A00020E04F2DB801CE010E949F07882341F018 +:1010B000CE01DF91CF911F910F91FF900C941708F3 +:1010C00080E0DF91CF911F910F91FF900895FF92E3 +:1010D0000F931F93CF93DF93EC018B01F42E60E00D +:1010E0000E94C107882381F021E04F2DB801CE0175 +:1010F0000E949F07882341F0CE01DF91CF911F917D +:101100000F91FF900C94170880E0DF91CF911F9111 +:101110000F91FF900895CF92DF92EF92FF920F937D +:101120001F93CF93DF93EC016B01142F790160E0E3 +:101130000E94C107882301F120E0412FB601CE01B2 +:101140000E949F078823C1F061E0CE010E94C10781 +:10115000882391F0402FB701CE010E947B0788239E +:1011600059F0CE01DF91CF911F910F91FF90EF9039 +:10117000DF90CF900C94170880E0DF91CF911F9102 +:101180000F91FF90EF90DF90CF900895FC011082B7 +:1011900011821282138614860895FC01908199238E +:1011A00011F091509083089567FD0CC0660F642B79 +:1011B0006093BA0084E68093B80085E48093BC0015 +:1011C00081E0089580E0089584E08093BC0010924F +:1011D000B8000895FB012FB7F894918181E0890F41 +:1011E0008183DB01A90FB11D12964C93883008F062 +:1011F000118281819081891305C08F5F808388303F +:1012000008F010822FBF0895462FBC01655F7F4F05 +:101210000C94EA08FB019FB7F89480812181821326 +:1012200004C09FBF8FEF9FEF089521E0280F208318 +:10123000DB01A80FB11D12968C91283018F49FBFC6 +:1012400090E008951082FBCFBC016F5F7F4F0C943C +:101250000A092091B900287F203819F0283A49F06E +:1012600013C04091BB00BC016F5F7F4F0E94EA0832 +:1012700009C0BC01655F7F4F0E940A0997FD80E0AD +:101280008093BB0085E801C085EC8093BC00089585 +:10129000CF93DF9390915D0480915C049817D1F314 +:1012A000E0915D0481E08E0F80935D04F0E0E25AEE +:1012B000FB4FC081CD3009F4CAE0D0E06091E20478 +:1012C0007091E304CE010E943141CE01DF91CF91B4 +:1012D00008950F931F93CF93C82F8B018A3019F471 +:1012E0008DE00E9469098091E2049091E30408175F +:1012F000190731F48091C00085FFFCCFC093C60070 +:1013000080E090E0CF911F910F910895089580E0C3 +:1013100090E0089508950895089508950895089512 +:101320002FB7F89440918E0450918F04452B59F4B7 +:10133000429A80383FEF930710F480589F4F909364 +:101340008F0480938E042FBF08952FB7F894409197 +:10135000900450919104452B59F4449A80383FEF02 +:10136000930710F480589F4F9093910480939004BA +:101370002FBF0895813041F0823019F48BEE91E057 +:10138000089587EE91E008958FEE91E00895CF9350 +:1013900087E680937C0087E880937A0080917A00CA +:1013A000806480937A0080917A0086FDFCCF109251 +:1013B000860480917900843F10F081E005C080911F +:1013C0007900803E18F082E0809386048091860444 +:1013D0009FEF980F923078F0809179001F928F9351 +:1013E0008CEA91E09F938F930E946D410F900F9034 +:1013F0000F900F9014C0C09179000E94BA091F92FB +:10140000CF939F938F9386E891E09F938F930E9451 +:101410006D410F900F900F900F900F900F901092C2 +:101420007C0010927A0080918604CF910895F89400 +:1014300060938A0470938B0480938C0490938D0442 +:10144000789408950E94170AF89480918A049091E4 +:101450008B04A0918C04B0918D047894892B8A2BF5 +:101460008B2B31F08091000190910101019661F385 +:1014700080910001909101010895CF93DF93CFEF08 +:10148000DFEFD0930101C09300010E94220AD093A4 +:101490000101C0930001DF91CF910895CF93DF93B5 +:1014A000CDB7DEB728970FB6F894DEBF0FBECDBF1D +:1014B00070917E0460917F0450918004409181047A +:1014C000309182042091830490918404809185045A +:1014D00079836A835B834C833D832E839F838887D4 +:1014E0008FB7F894E0917E0470917F04609180043E +:1014F00050918104409182043091830420918404AE +:1015000090918504E9837A836B835C834D833E836A +:101510002F8398878FBF29813A814B815C816D81B0 +:101520007E818F81988528960FB6F894DEBF0FBE16 +:10153000CDBFDF91CF9108951F920F920FB60F92FA +:1015400011240BB60F922F933F938F939F93EF939A +:10155000FF938091C600282F30E030930101209343 +:101560000001E0915C0491E09E0F90935C04F0E038 +:10157000E25AFB4F808390915C0480915D04981344 +:1015800005C080915D048F5F80935D04FF91EF91B2 +:101590009F918F913F912F910F900BBE0F900FBE97 +:1015A0000F901F9018951F920F920FB60F92112453 +:1015B0000BB60F922F933F934F935F936F937F934D +:1015C0008F939F93AF93BF93CF93EF93FF93C0916C +:1015D000CE0080912B04882329F06C2F89E294E0BF +:1015E0000E94902B80913F04882329F06C2F8DE37B +:1015F00094E00E94C33780912604882329F06C2F41 +:1016000084E294E00E94B826FF91EF91CF91BF91C0 +:10161000AF919F918F917F916F915F914F913F918A +:101620002F910F900BBE0F900FBE0F901F9018952B +:101630001F920F920FB60F9211240BB60F922F9399 +:101640003F934F935F936F937F938F939F93AF934A +:10165000BF93EF93FF9380919203882319F082E068 +:1016600093E00DC080910103882319F081E792E097 +:1016700006C080912304882329F083E993E00E9427 +:10168000012603C080E88093BC00FF91EF91BF91D9 +:10169000AF919F918F917F916F915F914F913F910A +:1016A0002F910F900BBE0F900FBE0F901F901895AB +:1016B0001F920F920FB60F9211240BB60F922F9319 +:1016C0003F934F935F936F937F938F939F93AF93CA +:1016D000BF93EF93FF9380914F04882321F08DE413 +:1016E00094E00E94792280914804882321F086E4C6 +:1016F00094E00E94E72C809189048F5F8A3018F46F +:101700008093890490C01092890480918A049091FA +:101710008B04A0918C04B0918D04892B8A2B8B2B88 +:1017200099F080918A0490918B04A0918C04B091DF +:101730008D040197A109B10980938A0490938B04C9 +:10174000A0938C04B0938D0420917E0430917F048B +:1017500040918004509181046091820470918304CF +:101760008091840490918504A1E00E944F3C2093D5 +:101770007E0430937F0440938004509381046093EF +:1017800082047093830480938404909385048BE790 +:1017900093E00E9464078DE793E00E94CD088AEEF3 +:1017A00092E00E9464078CEE92E00E94CD088CE0EB +:1017B00094E00E9464078EE094E00E94CD0880913E +:1017C0006802882319F081508093680280915E023C +:1017D000882319F0815080935E0280918E0490914D +:1017E0008F04892B69F080918E0490918F0401976A +:1017F00090938F0480938E048038910508F442986A +:101800008091900490919104892B69F080919004CB +:101810009091910401979093910480939004803863 +:10182000910508F44498809187049091880401966A +:1018300090938804809387048838934140F098B14E +:1018400088E0892788B91092880410928704FF9154 +:10185000EF91BF91AF919F918F917F916F915F9128 +:101860004F913F912F910F900BBE0F900FBE0F9095 +:101870001F901895CF93DF93EC0119821882809105 +:10188000D30481110EC083ED94E00E948709892B57 +:1018900041F081ED94E00E94600783ED94E00E94A6 +:1018A0008A09198A1A8A1B8A1C8A86E994E09B8312 +:1018B0008A8384E994E09D838C8382E994E09F830A +:1018C0008E8381ED94E099838883DF91CF91089591 +:1018D000CF93DF9300D0CDB7DEB74A83FC01808180 +:1018E0009181009739F0698342E0BE016F5F7F4FBD +:1018F0000E9443080F900F90DF91CF910895CF92EF +:10190000EF920F93CF93DF93EC016295660F660F12 +:10191000607C47702770822F880F880F880F262FD2 +:10192000242B282B2FAB0295000F007E88AD8F71E2 +:10193000082B08AF8E2D8770880F880F880F9EA9FF +:10194000292F207C9C2D9770E22EE82AE92AE89422 +:10195000E7F8EEAA40E064EFCE010E94680C48ADC3 +:1019600042954695477062EFCE010E94680C9EA991 +:10197000492F477060E2469F90011124892F869578 +:1019800086958695877064E0869FA0011124422B7E +:10199000532B97FB992790F9492B65EFCE010E94B5 +:1019A000680C9FA9492F477080E2489F900111243D +:1019B000892F869586958695877064E0869FA0011D +:1019C0001124422B532B9295969596959370492B03 +:1019D00064EFCE01DF91CF910F91EF90CF900C94F7 +:1019E000680C0F93CF93DF931F92CDB7DEB7FC0146 +:1019F00080819181009749F0698301E09E012F5F0A +:101A00003F4F41E0B9010E948B0889810F90DF911F +:101A1000CF910F9108950F93CF93DF9300D0CDB75F +:101A2000DEB7FC0180819181009749F0698302E073 +:101A30009E012F5F3F4F41E0B9010E948B088981D1 +:101A40009A819827892798270F900F90DF91CF913F +:101A50000F9108950E940B0D9827892798270895C4 +:101A60000C940B0D0C942A0D0F93CF93DF9300D0A1 +:101A70001F92CDB7DEB7FC0180819181009749F0BC +:101A8000698303E09E012F5F3F4F41E0B9010E944F +:101A90008B0829816A81862F90E0A0E0B0E0BA2F00 +:101AA000A92F982F8827A22B2B81BC01CD01622B57 +:101AB0000F900F900F90DF91CF910F9108956F923B +:101AC0007F928F929F92AF92BF92CF92DF92EF92CE +:101AD000FF920F931F93CF93DF93EC019FA9892F60 +:101AE000807C803409F043C0492F477060E2469FF4 +:101AF00090011124892F8695869586958770E4E05C +:101B00008E9FA0011124422B532B9295969596956A +:101B10009370492B64EFCE010E94680C0E944E0A1C +:101B2000922E832E742E652E63EFCE010E94F10C4F +:101B300083FF1FC00E944E0AA92CB82CC72CD62C9C +:101B4000E12CF12C00E010E00E945B3C203D37408E +:101B500041055105610571058105910509F038F4CC +:101B600087EB9BE00197F1F700C00000DDCF80E03C +:101B700001C081E0DF91CF911F910F91FF90EF9015 +:101B8000DF90CF90BF90AF909F908F907F906F909D +:101B900008951F93CF93DF93EC0168E80E942A0D0C +:101BA0009E8B8D8B6AE8CE010E942A0D988F8F8BB9 +:101BB0006CE8CE010E942A0D9A8F898F6EE8CE01C3 +:101BC0000E942A0D9C8F8B8F60E9CE010E942A0D06 +:101BD0009E8F8D8F62E9CE010E942A0D98A38F8F70 +:101BE00064E9CE010E942A0D9AA389A366E9CE0179 +:101BF0000E942A0D9CA38BA368E9CE010E942A0DA6 +:101C00009EA38DA36AE9CE010E942A0D98A78FA3F7 +:101C10006CE9CE010E942A0D9AA789A76EE9CE0130 +:101C20000E942A0D9CA78BA761EACE010E94F10CAD +:101C30008DA761EECE010E942A0D9FA78EA763EEAD +:101C4000CE010E94F10C88AB64EECE010E94F10C33 +:101C5000182F65EECE010E94F10C90E1190290015F +:101C600011248F70282B3AAB29AB66EECE010E946F +:101C7000F10C182F65EECE010E94F10C90E11902D3 +:101C80009001112490E044E0959587954A95E1F7FD +:101C9000822B932B9CAB8BAB67EECE010E94F10C99 +:101CA0008DABDF91CF911F91089563EF0E94F10CEE +:101CB00081700895CF92DF92EF92FF920F931F935E +:101CC000CF93DF93EC0160ED0E94F10C90E0A0E077 +:101CD000B0E089879A87AB87BC8780369105A105DC +:101CE000B10569F546EB60EECE010E94680C8FE20B +:101CF00095E70197F1F700C00000CE010E94550E54 +:101D00008111F5CFCE010E94C90DC12CD12CE12C3F +:101D1000F12C05E010E025E030E045E050E063E024 +:101D200070E0CE010E947F0C9FE729EA83E091508A +:101D300020408040E1F700C0000081E001C080E069 +:101D4000DF91CF911F910F91FF90EF90DF90CF9097 +:101D50000895CF93DF93EC01888199810E946B07EE +:101D6000882329F0CE01DF91CF910C945A0E80E0A8 +:101D7000DF91CF9108954F925F926F927F928F92F1 +:101D80009F92AF92BF92CF92DF92EF92FF92CF934A +:101D9000DF93EC016AEF0E94340D6115710520E8B4 +:101DA0008207910509F485C06B017C0184E0F594FC +:101DB000E794D794C7948A95D1F74D885E88C70178 +:101DC000B60128E030E040E050E00E94AD3A612CDE +:101DD000712CD301C201880F991FAA1FBB1F281B9A +:101DE000390B4A0B5B0BAF89B88D0E94D73A4B0178 +:101DF0005C01C701B60120E130E040E050E00E9404 +:101E0000AD3ACA01B90164197509860997099B01A0 +:101E1000AC010E946F3A9B01AC017CE0559547955F +:101E2000379527957A95D1F7A98DBA8D0E94D73A23 +:101E30002B013C01C501B40120E038E040E050E056 +:101E40000E94AD3A69017A01C301B20120E030E499 +:101E500040E050E00E94AD3ABA01A9014C0D5D1D71 +:101E60006E1D7F1D89899A89AB89BC899A01AB0156 +:101E7000280F391F4A1F5B1F2D873E874F87588BBE +:101E8000A5E0B0E00E94CC3A60587F4F8F4F9F4F43 +:101E900020E031E040E050E00E94AD3ACA01B901D3 +:101EA0000E94C73D20E030E048EC52E40E94173D1C +:101EB00004C060E070E080EC9FE7DF91CF91FF907D +:101EC000EF90DF90CF90BF90AF909F908F907F90DA +:101ED0006F905F904F9008952F923F924F925F9234 +:101EE0006F927F928F929F92AF92BF92CF92DF922A +:101EF000EF92FF920F931F93CF93DF93CDB7DEB78F +:101F00006D970FB6F894DEBF0FBECDBF1C010E94C7 +:101F1000BB0E67EFC1010E94340D6F87788B898BF0 +:101F20009A8B611571058048910509F49AC2F101F7 +:101F300085859685A785B0896C017D01FF0CCC084D +:101F4000DC2C76019C01AD016C2D7C2D8C2D9C2D03 +:101F5000345F41405109610971098109910929875B +:101F60003A874B875C873B014C0159016A017B0131 +:101F70008C010E94DF3A422E3D874E875B8B6C8B33 +:101F80007D8B8E8B9B8FD1015E963C915E975D968B +:101F90002C91932F990F990B492F592F692F792F36 +:101FA000892F0E94DF3A0CE00E940F3C2C8F3D8F5E +:101FB00049835F8B688F798F582E9A8FF10130A1FA +:101FC000278D932F990F990BA42CBD84CE84DB8889 +:101FD000EC88FD880E891B8D492F592F692F792F89 +:101FE000892F0E94DF3AF22E032F142FB52FF62FE0 +:101FF000E72FD82EE92EA0E00E94643C84F4215003 +:102000003F4F4F4F5F4F6F4F7F4F8F4F9F4FF22E7E +:10201000032F142FB52FF62FE72FD82EE92E2F2DB3 +:10202000302F412F5B2F6F2F7E2F8D2D9E2D08E09F +:102030000E94283CAC8CBD8CC980DF88E88CF98C70 +:10204000052D1A8D0E94463C70588F4F9F4FD1012D +:102050005B96ED91FC915C975F01C12CD12CE12C3A +:10206000F12C8701E983BA82CB82DC82ED82FE8289 +:102070000F831887C12CD12CE12CF12C00E010E04B +:102080000E94DF3A122F3F8B4983B52FF62FE72F9F +:10209000F82E092FA0E00E94643C84F421503109FD +:1020A000410951096E4F7F4F8F4F9F4F122F3F8B2A +:1020B0004983B52FF62FE72FF82E092F212F3F89BF +:1020C00049815B2F6F2F7E2F8F2D902F01E20E9471 +:1020D000283C2D8F532E49835F8B688F798F8A8F91 +:1020E0009C8FA0E00E94643C09F4C0C1D101969687 +:1020F0003C91969795962C91932F990F990BA42C20 +:10210000BD84CE84DB88EC88FD880E891B8D492F29 +:10211000592F692F792F892F0E94DF3A2D873E870B +:10212000442E5B8B6C8B7D8B8E8B9B8FF10134A14E +:1021300023A1932F990F990BA984BA84CB84DC84B3 +:1021400073018401492F592F692F792F892F0E94FC +:10215000DF3A01E10E940F3CAD84BE84C42CDB88D1 +:10216000EC88FD880E891B8D0E94463C59016A014E +:102170007B01482E192F4F85588969897A8934E067 +:1021800075956795579547953A95D1F780E090E01A +:10219000A0E1B0E0841B950BA60BB70B3C014D01F1 +:1021A000990C6608762C43019C01AD01662D762DB5 +:1021B000862D962D0FE10E940F3C722E832E942EB9 +:1021C000652EB62FA72F8A879B87F10132A121A107 +:1021D000932F990F990B492F592F692F792F892FF9 +:1021E00003E20E940F3C042D0E94463C59016A0103 +:1021F0007B018C01272D382D492D562D6B2F7A2FE1 +:102200008A859B850E945B3CE5E3AE2EFCE0BF2EF9 +:10221000C12CD12CE12CF12C00E010E00E94DF3A1F +:10222000AD8CB52CC980DF88E88CF98C0A8D1C8DAB +:102230000E943A3B2C8B3B8B2A013B014C01F22E36 +:10224000032F142FB52DF62FE72DD82EE92CA0E063 +:102250000E94643C84F42150304E4F4F5F4F6F4FCB +:102260007F4F8F4F9F4FF22E032F142FB52FF62F36 +:10227000E72FD82EE92E2F2D302F412F5B2F6F2FD8 +:102280007E2F8D2D9E2D0DE00E94283C29873A87B8 +:102290004B875C876F8779838D879E87D1019C965A +:1022A0003C919C979B962C91932F990F990BA98405 +:1022B000BA846A017B01082F1E85492F592F692F87 +:1022C000792F892F0E94DF3A0E94DF3AF22E032FE6 +:1022D000142FB52FF62FE72FD82EE92EA0E00E945D +:1022E000643C84F42150310941095E4F6F4F7F4FA8 +:1022F0008F4F9F4FF22E032F142FB52FF62FE72F5E +:10230000D82EE92E2F2D302F412F5B2F6F2F7E2FB0 +:102310008D2D9E2D09E10E94283CAC88BB8862016E +:10232000730184010E94463C29873A874B875C876A +:102330006F8779838D879E87F10132A521A5932F21 +:10234000990F990B492F592F692F792F892F0E94A7 +:10235000DF3A122F3C8B4B8BB52FF62FE72FF82E41 +:10236000092FA0E00E94643C84F421503109484FB9 +:102370005F4F6F4F7F4F8F4F9F4F122F3C8B4B8B79 +:10238000B52FF62FE72FF82E092F212F3C894B89E7 +:102390005B2F6F2F7E2F8F2D902F03E10E94283C03 +:1023A00059016A017B018C0129853A854B855C8541 +:1023B0006F8579818D859E850E94463C122F3987D5 +:1023C0004983B52FF62FE72FF82E092FA0E00E94A2 +:1023D000643C84F421503F4F4F4F5F4F6F4F7F4F0E +:1023E0008F4F9F4F122F39874983B52FF62FE72F35 +:1023F000F82E092F212F398549815B2F6F2F7E2FD2 +:102400008F2D902F08E00E94283C2983F32F6A012A +:102410007B01E82F192FD10197968D919C91989768 +:10242000092E000CAA0BBB0B4C015D01BB0C8808EC +:10243000982C54019C01AD01682D782D882D982D84 +:1024400004E00E940F3CA980BF2E0E2F0E94463C44 +:102450000E94BF3D20E030E040E85BE30E94A13EE7 +:1024600008C060E070E080EC9FE703C060E070E0CF +:10247000CB016D960FB6F894DEBF0FBECDBFDF91D6 +:10248000CF911F910F91FF90EF90DF90CF90BF9071 +:10249000AF909F908F907F906F905F904F903F9004 +:1024A0002F9008954F925F926F927F928F929F929A +:1024B000AF92BF92CF92DF92EF92FF92CF93DF93D2 +:1024C00000D000D000D0CDB7DEB79E838D830E94B0 +:1024D000BB0E6DEF8D819E810E940B0DA0E0B0E0E0 +:1024E000811520E89207A105B10509F4D3C0ED815B +:1024F000FE8185849684A784B088FCE29F1AF1E06F +:10250000AF0AB1083EE0880F991FAA1FBB1F3A957A +:10251000D1F7ED81FE8141A952A9052E000C660B71 +:10252000770B24E1440F551F661F771F2A95D1F7BB +:102530006C017D01C41AD50AE60AF70AA3A9B4A959 +:10254000A50194010E94D73AA7019601261B370BDB +:10255000480B590BCA01B901705C8F4F9F4F412C3A +:1025600030E8532E612C712CA30192010E94AD3AE8 +:1025700029833A834B835C83ED81FE81A0A9B0E07F +:10258000A50194010E94CC3A20E038E040E050E000 +:102590000E94AD3A69017A01F0E8DF0EE11CF11CFE +:1025A000ED81FE81A5A90A2E000CBB0BA5019401AB +:1025B0000E94D73A812C44E0942EA12CB12CA50185 +:1025C00094010E94AD3ACA01B901A70196010E9487 +:1025D0006F3AA50194010E94AD3A405E5F4FED81D4 +:1025E000FE81A6A5B7A50E94D73A705E8F4F9F4F78 +:1025F00020E030E440E050E00E94AD3A69817A8109 +:102600008B819C810E946F3A6B017C01A301920136 +:102610000E94AD3ACA01B9010E946F3A9B01AC0118 +:1026200067E055954795379527956A95D1F7ED81E0 +:10263000FE81A5A5B0E00E94CC3A20E130E040E068 +:1026400050E00E94AD3AD701C601821B930BA40B48 +:10265000B50BB7FF03C080E090E0DC01813091054D +:10266000A105F9E1BF0724F080E090E0A0E0B9E126 +:10267000BC01CD012CE095958795779567952A95B6 +:10268000D1F70E94C53D20E030E040E85AE30E94C7 +:10269000A13E04C060E070E080EC9FE726960FB694 +:1026A000F894DEBF0FBECDBFDF91CF91FF90EF90CA +:1026B000DF90CF90BF90AF909F908F907F906F9062 +:1026C0005F904F900895CF92DF92EF92FF926A0150 +:1026D0007B010E946C0F20E030E048EC52E40E9445 +:1026E000173DA70196010E94173D21E03EED42E40F +:1026F0005EE30E940E3F9B01AC0160E070E080E869 +:102700009FE30E94AA3C20E03AE24DE257E40E9497 +:10271000A13EFF90EF90DF90CF900895CF92DF928F +:10272000EF92FF920F931F93CB01BA0168017901D9 +:1027300020E03AE24DE257E40E94173D9B01AC01D4 +:1027400060E070E080E89FE30E94AA3C26EF38E258 +:1027500048EA50E40E940E3F9B01AC01C701B6015C +:102760000E94173D1F910F91FF90EF90DF90CF9047 +:102770000895FC0161857285838594850895FC0127 +:102780002189328943895489A5E0B0E00E94CC3A7E +:10279000672F782F892F992787FD9A950E94C73D2B +:1027A00020E030E048EC52E40E94173D0895CF93BA +:1027B000DF93EC01CB01BA0120E030E048EC52E4B9 +:1027C0000E94A13E0E94893D982F872F762F662771 +:1027D00025E030E040E050E00E94AD3A298B3A8B92 +:1027E0004B8B5C8BDF91CF9108950F931F93CF9309 +:1027F000DF938C01EB0188E2FB0111928A95E9F7E6 +:102800004BE050E06BE771E0CE010E94D3401B86A5 +:1028100081E090E0A0E0B0E08C879D87AE87BF8725 +:10282000F80180819181092E000CAA0BBB0B888BCB +:10283000998BAA8BBB8B8DE090E0A0E0B0E08C8BF5 +:102840009D8BAE8BBF8B1CA21DA21EA21FA280E07F +:1028500090E0A0E2B2EC8C8F9D8FAE8FBF8F80E0B6 +:1028600090E0AAEAB2E4888F998FAA8FBB8F8AE0A2 +:1028700097EDA3E2BCE388A399A3AAA3BBA3DF912E +:10288000CF911F910F910895CF93DF93EB0124E235 +:10289000FB0111922A95E9F744E250E060E070E014 +:1028A000488359836A837B83FC0180819181092E4F +:1028B000000CAA0BBB0B8C839D83AE83BF838DE082 +:1028C00090E0A0E0B0E088879987AA87BB870E9444 +:1028D0004E0A288B398B4A8B5B8B88E994E00E94E7 +:1028E000BB0E6C8B7D8B8E8B9F8B81E0DF91CF91AC +:1028F00008950F931F93CF93DF938C01EB0188E230 +:10290000FB0111928A95E9F74BE050E06BE771E02B +:10291000CE010E94D3401B8681E090E0A0E0B0E0B1 +:102920008C879D87AE87BF87F80180819181092EB2 +:10293000000CAA0BBB0B888B998BAA8BBB8B86E0F8 +:1029400090E0A0E0B0E08C8B9D8BAE8BBF8B1CA287 +:102950001DA21EA21FA280E090E0A6E9B3E48C8F26 +:102960009D8FAE8FBF8F80E090E8A9E8B4E4888F98 +:10297000998FAA8FBB8F86EA9BE9A4E4BCE388A366 +:1029800099A3AAA3BBA3DF91CF911F910F910895A3 +:10299000CF93DF93EB0124E2FB0111922A95E9F733 +:1029A00044E250E060E070E0488359836A837B83AF +:1029B000FC0180819181092E000CAA0BBB0B8C833A +:1029C0009D83AE83BF8386E090E0A0E0B0E088877F +:1029D0009987AA87BB870E944E0A288B398B4A8B1E +:1029E0005B8B88E994E00E946C0F20E030E048ECBB +:1029F00052E40E94173D6C8B7D8B8E8B9F8B81E008 +:102A0000DF91CF9108950F931F93CF93DF938C01A4 +:102A1000EB0188E2FB0111928A95E9F74BE050E067 +:102A20006BE771E0CE010E94D3401B8681E090E00D +:102A3000A0E0B0E08C879D87AE87BF87F8018081DA +:102A40009181092E000CAA0BBB0B888B998BAA8B4A +:102A5000BB8B8CE090E0A0E0B0E08C8B9D8BAE8BCC +:102A6000BF8B1CA21DA21EA21FA21C8E1D8E1E8E1D +:102A70001F8E80E090E0A8ECB2E4888F998FAA8F37 +:102A8000BB8F80E090E0A0E4B0E488A399A3AAA360 +:102A9000BBA3DF91CF911F910F910895CF93DF9347 +:102AA000EB0124E2FB0111922A95E9F744E250E0A0 +:102AB00060E070E0488359836A837B83FC018081F6 +:102AC0009181092E000CAA0BBB0B8C839D83AE83D6 +:102AD000BF838CE090E0A0E0B0E088879987AA8768 +:102AE000BB870E944E0A288B398B4A8B5B8B88E907 +:102AF00094E00E9452126C8B7D8B8E8B9F8B81E0B9 +:102B0000DF91CF910895CF93DF93EC010E9460078E +:102B10001A828CE78CAB8AE08DAB8EE78EAB8FEAA6 +:102B20008FAB88AF82EA89AF1AAE80E88BAFDF91B6 +:102B3000CF910895CF93DF9300D0CDB7DEB74A830E +:102B4000698342E0BE016F5F7F4F0E9443080F9090 +:102B50000F90DF91CF9108950F93CF93DF931F9242 +:102B6000CDB7DEB79A01698301E041E0BE016F5F36 +:102B70007F4F0E948B080F90DF91CF910F910895A6 +:102B80000F93CF93DF931F92CDB7DEB79A0169837E +:102B900002E041E0BE016F5F7F4F0E948B080F9003 +:102BA000DF91CF910F9108950F931F93CF93DF93F0 +:102BB00000D0CDB7DEB78A01AE014F5F5F4F0E94F4 +:102BC000C015882341F029813A81322723273227F3 +:102BD000F801318320830F900F90DF91CF911F91E7 +:102BE0000F9108950F93CF93DF931F92CDB7DEB768 +:102BF0006983022F9E012F5F3F4F41E0B9010E9480 +:102C00008B080F90DF91CF910F91089540EF60E115 +:102C10000E949A15EFE2F5E73197F1F700C0000046 +:102C200008950F931F93CF93DF9300D0CDB7DEB7F6 +:102C30008C01AE014F5F5F4F60E00E94C0158FE2D4 +:102C400095E70197F1F700C0000089819A818036ED +:102C5000E1E09E0721F4F801128281E008C081368C +:102C6000914021F481E0F801828301C080E00F905F +:102C70000F90DF91CF911F910F9108950F931F93A4 +:102C8000CF93DF931F92CDB7DEB78C0140E062E1B6 +:102C90000E949A15811108C08FE295E70197F1F71C +:102CA00000C0000080E016C04CEC62E1C8010E9448 +:102CB0009A15882389F38FE295E70197F1F700C011 +:102CC0000000AE014F5F5F4F60E2C8010E94AC158B +:102CD000882311F30F90DF91CF911F910F910895E9 +:102CE0000F931F93CF93DF9300D01F92CDB7DEB722 +:102CF0008C010E943E16882359F18FE295E70197D7 +:102D0000F1F700C000004EE062E1C8010E949A1590 +:102D10008823F1F023E0AE014F5F5F4F6CE4C80100 +:102D20000E94F2158823A1F02981F80123839A815A +:102D300094839B81958391E0273008F490E0F8011B +:102D40009283EFE2F5E73197F1F700C0000007C08A +:102D50008FE295E70197F1F700C0000080E00F9047 +:102D60000F900F90DF91CF911F910F9108956330D5 +:102D700021F4FC012281222359F0462F60E10E94B8 +:102D80009A15EFE2F5E73197F1F700C000000895DA +:102D900080E00895CF93DF93EC0163E50E946B0719 +:102DA0008FE295E70197F1F700C00000CE010E9485 +:102DB00006168823A9F0CE010E941116882381F0FF +:102DC00061E0CE010E94B716882351F0CE010E9427 +:102DD0003E16882329F0CE01DF91CF910C94701616 +:102DE00080E0DF91CF910895CF93DF936115710556 +:102DF000D9F0EC017F836E8361E00E94B7168823CF +:102E000099F0CE010E943E16882371F042EC62E1F7 +:102E1000CE010E949A15882339F0EFE2F5E7319749 +:102E2000F1F700C0000007C08FE295E70197F1F7C6 +:102E300000C0000080E0DF91CF9108956F927F92F3 +:102E40008F929F92AF92BF92CF92DF92EF920F93A9 +:102E50001F93CF93DF931F92CDB7DEB73C01CB0119 +:102E6000342FE02FAFE2B5E71197F1F700C0000073 +:102E700068E170E00E94993A8B014FEF460F42954E +:102E8000440F440F407C3111406221114061E11137 +:102E90004860E110446060E4C3010E949A158823F1 +:102EA00009F471C0A80141505109569547955695AE +:102EB000479561E4C3010E949A15882309F463C011 +:102EC000A6015695479562E4C3010E949A1588238E +:102ED00009F459C0A5015695479563E4C3010E94C2 +:102EE0009A15882309F44FC0A4015695479564E4C8 +:102EF000C3010E949A15811146C049895A89569585 +:102F0000479565E4C3010E949A1581113CC0F30105 +:102F10004681415066E4C3010E949A15811133C075 +:102F2000D30116968D919C911797019711F440E863 +:102F300001C040E067E4C3010E949A15882319F19B +:102F4000EFE2F5E73197F1F700C00000AE014F5F07 +:102F50005F4F6FE4C3010E94AC158823A1F0AFE27C +:102F6000B5E71197F1F700C00000F3012681378122 +:102F7000B901606C498150E06417750729F02F5F33 +:102F80003F4F3783268380E00F90DF91CF911F91D1 +:102F90000F91EF90DF90CF90BF90AF909F908F9068 +:102FA0007F906F900895AB0160E20C94AC150F9385 +:102FB000CF93DF931F92CDB7DEB79B0141E24983E8 +:102FC00005E041E0BE016F5F7F4F0E948B080F90CC +:102FD000DF91CF910F9108950F931F93CF93DF93BC +:102FE000CDB7DEB729970FB6F894DEBF0FBECDBFC1 +:102FF0008C016623F1F0AE01475F5F4F60E2C801CC +:103000000E94AC158823E9F087EB9BE00197F1F76C +:1030100000C00000898581FFEECF898581FF11C046 +:1030200027E0AE014F5F5F4F61E2C8010E94F215D9 +:1030300008C0AE01475F5F4F60E20E94AC1581118E +:10304000ECCF80E029960FB6F894DEBF0FBECDBF5F +:10305000DF91CF911F910F9108950F931F93CF93FD +:10306000DF93CDB7DEB729970FB6F894DEBF0FBE5A +:10307000CDBF8C016623C1F087EB9BE00197F1F790 +:1030800000C00000AE01475F5F4F60E2C8010E94D0 +:10309000AC15811102C080E00AC1898580FFECCFA8 +:1030A000898580FFF8CF09C0AE01475F5F4F60E2BE +:1030B0000E94AC158111F4CFEECF28E0AE014F5F36 +:1030C0005F4F68E4C8010E94F215882321F36981EB +:1030D0007A8180E090E00E94C53D20E030E040E051 +:1030E0005AE30E94A13E9B01AC0160E070E080E0E9 +:1030F00090E40E940E3F0E94903DF8016787708B1C +:10310000818B928B6B817C8180E090E00E94C53D39 +:1031100020E030E040E05AE30E94A13E9B01AC0178 +:1031200060E070E080E090E40E940E3F0E94903DDD +:10313000F801678B708F818F928F6D817E8180E027 +:1031400090E00E94C53D20E030E040E05AE30E945C +:10315000A13E9B01AC0160E070E080E090E40E9441 +:103160000E3F0E94903DF801678F70A381A392A348 +:103170006F81788580E090E00E94C53D20E030E0DE +:1031800040E05AE30E94A13E9B01AC0160E070E088 +:1031900080E090E40E940E3F0E94903DF80167A3FA +:1031A00070A781A792A728E0AE014F5F5F4F68E24A +:1031B000C8010E94F215882309F46DCF69817A81D4 +:1031C00080E090E00E94C53D20E030E040E05AE31E +:1031D0000E94A13E9B01AC0160E070E080E090E4C1 +:1031E0000E940E3F0E94903DF801638B748B858B8B +:1031F000968B6B817C8180E090E00E94C53D20E051 +:1032000030E040E05AE30E94A13E9B01AC0160E047 +:1032100070E080E090E40E940E3F0E94903DF80133 +:10322000638F748F858F968F6D817E8180E090E0B3 +:103230000E94C53D20E030E040E05AE30E94A13EFC +:103240009B01AC0160E070E080E090E40E940E3FE2 +:103250000E94903DF80163A374A385A396A36F8198 +:10326000788580E090E00E94C53D20E030E040E0BD +:103270005AE30E94A13E9B01AC0160E070E080E057 +:1032800090E40E940E3F0E94903DF80163A774A74E +:1032900085A796A7AE014F5F5F4F68E3C8010E9404 +:1032A000AC15882309F4F7CE9981F80193AB2996E0 +:1032B0000FB6F894DEBF0FBECDBFDF91CF911F9147 +:1032C0000F910895CF93DF9300D000D0CDB7DEB734 +:1032D00069837A834B835C8324E0AE014F5F5F4F49 +:1032E00063E10E94EE070F900F900F900F90DF9117 +:1032F000CF9108958F929F92AF92BF92CF92DF921B +:10330000EF92FF920F931F93CF93DF93EC014A014B +:103310005B01C901B80120E030E040E054E40E94C4 +:10332000A13E0E94903D6B017C0123E333E948E814 +:1033300053E4C501B4010E94AB3C20E030E040E81A +:1033400052E40E94A13E0E94903DA601CE01DF9171 +:10335000CF911F910F91FF90EF90DF90CF90BF9092 +:10336000AF909F908F900C946219FC018681978199 +:103370008330910540F4880F991FFC01EC59FE4FF2 +:1033800080819181089582E194E0089528982098A1 +:103390001CBC2C9884B18F7084B981B18F7C81B9A9 +:1033A00082B18F7C82B93E984698089560E070E0C3 +:1033B000CB010E94220A0196C9F30895611102C04F +:1033C0000E94D6198FEF08956EBD0DB407FEFDCF94 +:1033D0008EB50895289A08952898089595B181E0AA +:1033E000892785B9089514980895149A089583B18A +:1033F00086FB882780F9089580B185FB882780F9AE +:1034000008952AE0FC0120871E99FECF81E00895EF +:1034100024E6FC012087059BFECF81E0089524E689 +:10342000FC0120870599FECF81E008950F931F933B +:10343000CF93DF93EC01162F0E94F319CE010E9467 +:10344000011A082F612F6F73CE010E94E419CE017B +:103450000E94F519802FDF91CF911F910F91089550 +:10346000FF920F931F93CF93DF93EC01062FF42E5F +:103470000E94F319CE010E94011A182F602FCE016D +:103480000E94E4196F2DCE010E94E4198A838D8178 +:1034900081608D83CE010E94F519898580FF2BC044 +:1034A0001F92FF921F920F9388E993E09F938F934F +:1034B0000E946D410F900F900F900F900F900F9002 +:1034C000112389F08D8182FF0EC08A811F928F9314 +:1034D00089E893E09F938F930E946D410F900F9026 +:1034E0000F900F9008C084E893E09F938F930E9401 +:1034F0006D410F900F90812FDF91CF911F910F9110 +:10350000FF900895AF92BF92CF92DF92EF92FF9219 +:103510000F931F93CF93DF93EC01B42ED52E022F80 +:103520006F73162F10640E94F319CE010E94011AC6 +:10353000C82E612FCE010E94E419EB2CFD2C5701FF +:10354000D02EDD2041F0F50161915F01CE010E9496 +:10355000E419DA94F6CFCE010E94F519898581FF2E +:1035600046C01F731F921F9388E693E09F938F932B +:103570000E946D410F900F900F900F90102F80E6DA +:10358000A82E83E0B82E112379F0F70181917F01F5 +:103590001F928F93BF92AF920E946D4111500F9076 +:1035A0000F900F900F90EFCF8BE593E09F938F9349 +:1035B0000E946D410F900F90CC2089F08D8182FF89 +:1035C0000EC08A811F928F938CE493E09F938F9318 +:1035D0000E946D410F900F900F900F9008C087E4EC +:1035E00093E09F938F930E946D410F900F908C2DCD +:1035F000DF91CF911F910F91FF90EF90DF90CF90CF +:10360000BF90AF900895EF92FF920F931F93CF93C7 +:10361000DF93EC017A016F73162F10680E94F31983 +:10362000CE010E94011A082F612FCE010E94E419D9 +:103630008A838D8181608D8360E0CE010E94E419D0 +:10364000F7018083CE010E94F519898582FF2EC083 +:103650001F731F921F938BE293E09F938F930E949F +:103660006D410F900F900F900F900023B9F08D8156 +:1036700080FF14C08A811F928F93F70180811F926F +:103680008F9385E193E09F938F930E946D410F90FC +:103690000F900F900F900F900F9008C080E193E073 +:1036A0009F938F930E946D410F900F90802FDF9119 +:1036B000CF911F910F91FF90EF900895AF92BF921D +:1036C000CF92DF92EF92FF920F931F93CF93DF93EE +:1036D0008C01D62FB42ED52EC22F0E94F319C8010B +:1036E0000E94011AC82E6D2F606CC8010E94E41957 +:1036F000EB2CFD2C5701DC2EDD2049F060E0C801E9 +:103700000E94E419F50181935F01DA94F5CFC801B5 +:103710000E94F519F801818583FF31C01F92CF9374 +:10372000DF731F92DF9389EE92E09F938F930E9445 +:103730006D410F900F900F900F900F900F90CC2035 +:10374000B1F001EE12E0CC2379F0F70181917F0115 +:103750001F928F931F930F930E946D41C1500F9042 +:103760000F900F900F90EFCF8FED92E002C08AED97 +:1037700092E09F938F930E946D410F900F908C2D3C +:10378000DF91CF911F910F91FF90EF90DF90CF903D +:10379000BF90AF90089521E00C945E1B9B012053D5 +:1037A00031092E30310510F40C94CB1B80E00895C4 +:1037B000AF92BF92CF92DF92EF92FF920F931F933F +:1037C000CF93DF93CDB7DEB762970FB6F894DEBF25 +:1037D0000FBECDBF8C01242F8AE0F8018087AB019A +:1037E0006FE3C8010E94821AF82EAE014E5E5F4F51 +:1037F0006AE370E0C8010E94CB1B9A899431A1F55D +:103800008F2191F165E370E0C8010E94161AF82E2D +:10381000882351F1D12CE12CAE014F5E5F4F65E35F +:1038200070E0C8010E94CB1BF8228989D81659F094 +:10383000FFE0FE1540F0E1E0F0E0EC0FFD1FEE0DC3 +:10384000F11D8083E394FF2049F0833129F0D82EC5 +:10385000F80190859111E0CFFF24F39491E083313A +:1038600009F090E0F92261F46BE370E0C8010E9476 +:10387000161A60C0222389F0F8018085882369F038 +:10388000AE014E5E5F4F6AE370E0C8010E94CB1B41 +:103890002A898111EFCF80E001C081E091E0211100 +:1038A00090E0892309F3AE014F5E5F4F65E370E05E +:1038B000C8010E94CB1B2989882339F0213039F0B7 +:1038C000F80180858111EFCF02C080E001C081E066 +:1038D00091E0213009F090E0892361F181ED92E0DF +:1038E0009F938F930E946D41CE0101965C010F90D2 +:1038F0000F908C0189ECC82E82E0D82E802F8A1977 +:103900008E1570F4F80181918F011F928F93DF92D1 +:10391000CF920E946D410F900F900F900F90EECFBD +:1039200086EC92E09F938F930E946D410F900F90D1 +:1039300081E001C080E062960FB6F894DEBF0FBE52 +:10394000CDBFDF91CF911F910F91FF90EF90DF904E +:10395000CF90BF90AF9008953F924F925F926F9239 +:103960007F928F929F92AF92BF92CF92DF92EF920F +:10397000FF920F931F93CF93DF93CDB7DEB7679777 +:103980000FB6F894DEBF0FBECDBF6C01611105C04C +:1039900046E062E00E94301A14C1623008F010C1A3 +:1039A0008FE695E09F938F930E946D410F900F904B +:1039B00080E090E0EE24EA94FE2C512C34E1432E7A +:1039C0004FEF642E44E0742E59EF852E54E0952E6F +:1039D0002FEF30E03E8B2D8B5C013FEFA31AB30A33 +:1039E0009F938F938DE295E09F938F930E946D41FB +:1039F000AE014B5E5F4F65E370E0C6010E94CB1BDA +:103A00000F900F900F900F90811109C02AE235E0BE +:103A10003F932F930E946D410F900F900EC08E899F +:103A20008F938D898F93E3E2F5E0FF93EF930E94EC +:103A30006D410F900F900F900F908F8989831F9287 +:103A40005F921F924F9285E095E09F938F930E9423 +:103A50006D418E010E5F1F4F0F900F900F900F90D2 +:103A60000F900F90312C832D8A0DF80181938F01D7 +:103A70001F928F937F926F920E946D4133940F90AB +:103A80000F900F900F90F3E13F12EDCF9F928F9226 +:103A90000E946D4144E1BE016F5F7F4FC6010E94ED +:103AA000D81B0F900F90811171C084E690E00E94A6 +:103AB000900986EF94E09F938F930E946D410F9041 +:103AC0000F902FEFE216F20609F45EC03BE2E31618 +:103AD000F10429F08DE2E816F10431F00CC091E018 +:103AE000951558F45A940EC0552051F0E9E0E515AB +:103AF00048F0539407C0512C05C05524539402C07C +:103B00008AE0582EF5E05F9E8001112405521A4F7D +:103B100041E050E0B801CE0147960E94BC408CE5E0 +:103B200095E09F938F930E946D410F5F1F4F1F93EE +:103B30000F930E946D4187E595E09F938F930E94BC +:103B40006D414F896EE3C6010E94301A0F900F90AD +:103B50000F900F900F900F90882371F08F891F9214 +:103B60008F9384E495E09F938F930E946D410F9013 +:103B70000F900F900F9008C08EE395E09F938F9366 +:103B80000E946D410F900F90C50122CF84E690E016 +:103B90000E94A50960ED77E080E090E00E943D0A78 +:103BA0007C0123EF34E03F932F930E946D410F90EF +:103BB0000F909BE1E916F10409F083CF80E001C08A +:103BC0008FEF67960FB6F894DEBF0FBECDBFDF91C3 +:103BD000CF911F910F91FF90EF90DF90CF90BF900A +:103BE000AF909F908F907F906F905F904F903F909D +:103BF00008958F929F92AF92BF92CF92DF92EF92F1 +:103C0000FF920F931F93CF93DF9300D0CDB7DEB712 +:103C10008C014B015A01C22EFA01108282E3F80195 +:103C2000808785818B7F8583AE014E5F5F4F6BE31D +:103C300070E0C8010E94CB1BF82E882309F446C00F +:103C40008A818F7709F446C0D82E8FEA94E00197D5 +:103C5000F1F700C00000AE014E5F5F4F6BE370E014 +:103C6000C8010E94CB1B882321F09A819F77E92EFF +:103C700001C0ED2C91E0F8012085211101C090E0F8 +:103C8000F92EF82219F1DE1411F0DE2CDECFF80146 +:103C900085818270D82E90E044962E2D30E08217D8 +:103CA000930769F19F938F93F50180811F928F9302 +:103CB0008BE992E09F938F930E946D41F5011082F2 +:103CC0000F900F900F900F900F900F90F12C02C05B +:103CD000E11056C06AE370E0C8010E94161A8F21F5 +:103CE0000F900F90DF91CF911F910F91FF90EF9068 +:103CF000DF90CF90BF90AF909F908F9008959F934B +:103D00008F9384E892E09F938F930E946D410F9070 +:103D10000F900F900F90F4E1FC1518F42E2D2D1933 +:103D200001C02C2DF5012083A4016FEFC8010E9472 +:103D30005E1BF501811102C01082C8CF8081E81A94 +:103D4000DE1430F68AE692E09F938F930E946D41D5 +:103D50000F900F90AE014F5F5F4F6FEFC8010E9451 +:103D6000031BEA94DE14B0F3DD2009F4AFCF22E0A8 +:103D7000A8014D5F5F4F6FEFC8010E945E1BA6CF89 +:103D800022E0A8014D5F5F4F6FEFC8010E945E1BEC +:103D9000F82E882309F49ACFF80185818460858301 +:103DA00099CF3F924F925F926F927F928F929F92A4 +:103DB000AF92BF92CF92DF92EF92FF920F931F9339 +:103DC000CF93DF93CDB7DEB767970FB6F894DEBF1A +:103DD0000FBECDBF8C01611105C046E062E00E94BC +:103DE000301A61C1623008F05DC180E090E07C0172 +:103DF0002FEFE21AF20A9F938F938CED94E09F933A +:103E00008F930E946D4164E370E0C8010E94161A0E +:103E10000F900F900F900F908FEF90E09E8B8D8BF7 +:103E2000AE014B5E5F4F65E370E0C8010E94CB1BA3 +:103E300081110EC089ED94E09F938F930E946D4194 +:103E40009FE7EFE4F2E19150E040F040E1F714C069 +:103E500060E070E0CB010E94220A019691F08FECA5 +:103E600094E09F938F930E946D418FE79FE4E2E17E +:103E700081509040E040E1F700C000000F900F90AB +:103E800019C08D899E898130910571F486EC94E08A +:103E90009F938F930E946D41FFE72FE482E1F150E1 +:103EA00020408040E1F7E8CF8D30910519F041972F +:103EB00009F0B2CF8D899E898D30910521F041970F +:103EC00011F0C70194CF85EB94E09F938F930E94EC +:103ED0006D410F900F9086E6482E84E0582E9AE5AB +:103EE000692E94E0792E2CE7C22E24E0D22E34E8FD +:103EF000A32E34E0B32E45EA842E44E0942EAE0186 +:103F00004B5E5F4F65E370E0C8010E94CB1B8111DF +:103F10000EC0E2EBF4E0FF93EF930E946D418FE758 +:103F20009FE4E2E181509040E040E1F72EC060E084 +:103F300070E0CB010E94220A019691F088EA94E099 +:103F40009F938F930E946D412FE78FE492E1215060 +:103F500080409040E1F700C000000F900F90A2C099 +:103F6000AE01495E5F4F6BE370E0C8010E94CB1B5E +:103F700081110EC09F928F920E946D41EFE7FFE486 +:103F800022E1E150F0402040E1F700C0000071C0A4 +:103F90008F89843108F46FC024E1AE01495E5F4F20 +:103FA000BE016F5F7F4FC8010E94F91D882309F48D +:103FB00062C08F89882309F45EC084E690E00E9485 +:103FC000A50980EA94E09F938F930E946D41F801C8 +:103FD00085810F900F9082FF24C084818F771F927C +:103FE0008F938381282F082E000C330B3F938F93E0 +:103FF00089E894E09F938F930E946D41F80184813A +:104000000F900F900F900F900F900F9087FF03C0AD +:10401000BF92AF9202C0DF92CF920E946D410F908B +:104020000F908F891F928F935F924F920E946D41E4 +:104030000F900F900F900F90312C8F893816A8F4A5 +:10404000E1E0F0E0EC0FFD1FE30DF11D80811F9218 +:104050008F9380E694E09F938F930E946D413394F9 +:104060000F900F900F900F90E8CF7F926F920E9469 +:104070006D410F900F908D899E898D30910509F4C7 +:104080003ECF8131910509F43ACF9F938F9386E417 +:1040900094E09F938F930E946D410F900F900F902B +:1040A0000F900FCF8FEF67960FB6F894DEBF0FBE5D +:1040B000CDBFDF91CF911F910F91FF90EF90DF90D7 +:1040C000CF90BF90AF909F908F907F906F905F90B8 +:1040D0004F903F900895FC012681378121303105B2 +:1040E00031F038F02230310541F40C94D11E0C949B +:1040F000AC1C611102C00E94D6198FEF0895AF92D7 +:10410000BF92CF92DF92EF92FF920F931F93CF93C4 +:10411000DF93CDB7DEB729970FB6F894DEBF0FBE99 +:10412000CDBF7C0188E692E09F938F930E946D4102 +:104130008CEAC82E85E0D82E0F900F9010E09DE5F8 +:10414000A92E92E0B92E41E050E0B601CE010996C9 +:104150000E94BC40AE014F5F5F4F612FC7010E94BC +:10416000031B89859981981751F01F928F93BF92F5 +:10417000AF920E946D410F900F900F900F901F5FB4 +:104180008FEFC81AD80A1F32F1F600E310E0AE0133 +:104190004F5F5F4FB801C7010E94CE1B0F5F1F4FDB +:1041A0000E331105A1F728E0AE014F5F5F4F6EE3BC +:1041B000C7010E945E1B29960FB6F894DEBF0FBEA2 +:1041C000CDBFDF91CF911F910F91FF90EF90DF90C6 +:1041D000CF90BF90AF9008951F93CF93DF93EC01E2 +:1041E0000E94F31988E28A95F1F7CE010E94F51931 +:1041F00088EC8A95F1F7CE010E94F319CE010E9456 +:10420000011A182F60E370E0CE010E94161A1823DD +:10421000CE010E94011A8123DF91CF911F91089551 +:10422000CF92DF92EF92FF921F93CF93DF931F9273 +:10423000CDB7DEB76C018CEAE82E85E0F82E10E0F1 +:1042400041E050E0B701CE0101960E94BC40498197 +:10425000612FC6010E94301A173039F4998192FFFC +:1042600004C0F6019581926095831F5F882331F029 +:104270008FEFE81AF80A1F3219F781E00F90DF91EB +:10428000CF911F91FF90EF90DF90CF9008955F92B4 +:104290006F927F928F929F92AF92BF92CF92DF9256 +:1042A000EF92FF920F931F93CF93DF93CDB7DEB7BB +:1042B00028970FB6F894DEBF0FBECDBF4C018E011C +:1042C0000F5F1F4FE12CF12C60E0702EC12E8AE4AD +:1042D000A82E82E0B82EDD24D394D60E6E2C5F2C4F +:1042E00085E0689FB001112465527A4F41E050E0AB +:1042F000C8010E94BC40EAE0ED1508F4D12CF4019D +:10430000818584FF10C0F80180811F928F935F9296 +:104310006F92BF92AF920E946D410F900F900F90DD +:104320000F900F900F90FFEFEF1AFF0A0F5F1F4FD4 +:1043300088E0E816F10411F06D2DCDCF28E0472D6F +:104340005C2D6EE3C4010E94821A28960FB6F89481 +:10435000DEBF0FBECDBFDF91CF911F910F91FF90B8 +:10436000EF90DF90CF90BF90AF909F908F907F9015 +:104370006F905F900895CF93DF93EC013E9A469A39 +:104380002898209A80916400847080936400149A25 +:104390000C9A2C9A269884B1806B84B980E58CBDE8 +:1043A000159A0D988FEF93E09F938F930E946D4124 +:1043B000CE010E94EC200F900F90811103C089EF75 +:1043C00093E01FC082EE93E09F938F930E946D4114 +:1043D000CE010E9410210F900F90811103C08CED2F +:1043E00093E00FC086EC93E09F938F930E946D4102 +:1043F000CE010E9447210F900F90811107C080ECE1 +:1044000093E09F938F930E946D410CC08DEB93E0DE +:104410009F938F930E946D418FEF8987CE010E94F9 +:104420007F2019860F900F90DF91CF91089524B1CE +:10443000287F24B925B1276025B921E0FC0122831A +:104440000895FC01128284B1887F84B985B1887F88 +:1044500085B90895EF92FF920F931F93CF93DF9347 +:1044600061112CC0EC0100E216E082E1E82E86E04A +:10447000F82E6AE070E080E090E00E94220A019647 +:10448000F9F41F930F930E946D418B811F928F93BC +:10449000282F082E000C330B3F938F93FF92EF923F +:1044A0000E946D418DB79EB708960FB6F8949EBFD7 +:1044B0000FBE8DBF1A99DDCF1B82DBCF8FEF01C0FE +:1044C00080E0DF91CF911F910F91FF90EF900895C1 +:1044D00083B182FB882780F991E08927089583B111 +:1044E00080958170089583B18695817091E08927C8 +:1044F0000895FC018281811102C01382089533B1B5 +:1045000091E03927379533273795330F330B23B194 +:10451000269521702927279522272795220F220BE0 +:1045200080E030FB80F920FB81F990911F019827F2 +:104530009370D1F490911E0190FD0EC0982791FFC9 +:104540000BC0938181FD04C09F3729F09F5F03C09A +:10455000903809F09150938380911E0130FB80F9CF +:1045600020FB81F980931E0180911F0130FB80F9AF +:1045700020FB81F980931F010895FC0182819381C2 +:104580008330910540F4880F991FFC01E659FE4FD6 +:104590008081918108958AE991E00895E8EBF0E047 +:1045A0002DE020832CE1208324E6208324E0209347 +:1045B000BC0020E620937C0027E820937A008057F7 +:1045C0009F4F21E0FC012083089580579F4FFC01FD +:1045D000108284E08093BC001092B80010927C009E +:1045E00010927A0008952F923F924F925F926F92AD +:1045F0007F928F929F92AF92BF92CF92DF92EF9273 +:10460000FF920F931F93CF93DF93CDB7DEB76197E0 +:104610000FB6F894DEBF0FBECDBF8C016111A5C2ED +:10462000FC0182819381009709F0E8C186EB97E055 +:104630009F938F930E946D4198012C5F3F4F3D8760 +:104640002C8767E7C9010E94A90E0F900F90811176 +:1046500003C083EB97E08BC283EA97E09F938F932D +:104660000E946D4158013DE3A30EB11CC5010E949B +:10467000CA160F900F90811103C080EA97E077C2AD +:1046800062E0C5010E94B716811103C08DE997E071 +:104690006EC200E010E022E832E440E050E068EC56 +:1046A00071E4C5010E947A19811103C08AE997E07B +:1046B0005EC287E997E09F938F930E946D410F90B0 +:1046C0000F908FEF8F83412C512C32014E865F86E5 +:1046D000688A798A8C859D850E946C0F20E030E580 +:1046E00043EC57E40E94173D9F938F937F936F9302 +:1046F000E0E8F7E0FF93EF930E946D418C859D8584 +:104700000E94BB0E68877987382E292E9F938F933E +:1047100039853F9388858F93E3E7F7E0FF93EF9325 +:104720000E946D418C859D850E9452124B018A87A3 +:104730009B879F938F939F926F9387E697E09F93BA +:104740008F930E946D410FB6F894DEBF0FBECDBFB0 +:104750003F813F3F09F19A858B85282D392D492FBF +:10476000582FFC01682D792D8F2F9E2F0E945E3FC0 +:10477000811112C078856985C101272F362F492FF5 +:10478000582FDB01F1016B2F7A2F8F2F9E2F0E9464 +:104790005E3F882309F4FBC165E0C62ED12CE12CD5 +:1047A000F12C05E010E025E030E045E050E063E06A +:1047B00070E08C859D850E947F0C8F81803208F48B +:1047C00013C1EAE5F7E0FF93EF930E946D410F906C +:1047D0000F903F8113162CF5632F330F770B880B47 +:1047E000990B0E94C73D6B017C019B01AC01C30189 +:1047F000B2010E94173D4B018A879B87A701960152 +:104800006E857F85888999890E94173D6887798799 +:10481000382E292E412C512C32014E865F86688A13 +:10482000798A9A858B85082D192D292F382FF8859F +:10483000E985C1014F2F5E2F692F722DC5010E949E +:104840007A19811105C086E597E09F938F93C7C0C1 +:104850008B858F939A859F939F928F922F923F92F1 +:10486000E985EF93F885FF9324E437E03F932F9396 +:104870000E946D4162E0C5010E94B7160FB6F89420 +:10488000DEBF0FBECDBF811103C081E497E093C0AE +:1048900014E687EC9FEA0197F1F700C00000BE0123 +:1048A0006A5F7F4FC5010E94D317882309F48AC02D +:1048B0008E8181FF87C0BE016F5F7F4FC5010E945F +:1048C000D717882309F481C089811F928F93E8E369 +:1048D000F7E0FF93EF930E946D410F900F900F90C0 +:1048E0000F908981833091F038F4813061F082300B +:1048F00099F489E297E012C0843059F0853061F470 +:1049000081E197E00BC08EE297E008C080E297E07B +:1049100005C08BE197E002C08FE097E09F938F93F3 +:104920000E946D410F900F908B818F938A818F939E +:1049300081E097E09F938F930E946D418D818F93CB +:104940008C818F9326EF36E03F932F930E946D4129 +:104950008C819D810FB6F894DEBF0FBECDBF80392C +:10496000F1E09F0718F484EF96E01DC0883522E03F +:10497000920718F48AEE96E016C0803233E093076F +:1049800018F485EE96E00FC0883EE3E09E0718F429 +:1049900080EE96E008C08C3D954018F48BED96E0D3 +:1049A00002C087ED96E09F938F930E946D410F9018 +:1049B0000F9085ED96E09F938F930E946D410F902D +:1049C0000F9003C0115009F064CF61E0C5010E944F +:1049D000B716811108C022ED36E03F932F930E9455 +:1049E0006D410F900F901F8268EE73E080E090E0C1 +:1049F0000E94220A019609F46DCEC1C08130910552 +:104A000009F071C007581F4F61E0C8010E946B0791 +:104A1000811103C08FEC96E0AAC090EB692E96E05E +:104A2000792E26EAE22E26E0F22E36E9C32E36E073 +:104A3000D32E45E8A42E46E0B42E5FE8852E56E03E +:104A4000952E80917A00806480937A0080917A001C +:104A500086FDFCCF8091790089831F928F937F928E +:104A60006F920E946D4141E0BE016F5F7F4FC801B0 +:104A70000E9443080F900F900F900F90811106C075 +:104A8000FF92EF920E946D410F900F90DF92CF92B4 +:104A90000E946D4141E0BE016F5F7F4FC8010E94DF +:104AA00020080F900F90882361F089811F928F93C7 +:104AB0009F928F920E946D410F900F900F900F90D8 +:104AC00006C0BF92AF920E946D410F900F9068EEAA +:104AD00073E080E090E00E94220A019609F4B1CFD1 +:104AE0000E9475074CC0029709F03FC005581F4F40 +:104AF00040E061E0C8010E94D408811103C082E84F +:104B000096E035C08CE4C82E86E0D82EC8010E94FD +:104B100024097C010196F1F080917A0080648093F1 +:104B20007A0080917A0086FDFCCF60917900C801FF +:104B30000E940409809179001F928F93FF92EF9257 +:104B4000DF92CF920E946D410F900F900F900F90C7 +:104B50000F900F9060E070E0CB010E94220A019656 +:104B6000A9F2C8010E94E4080AC088E496E09F9375 +:104B70008F930E946D410F900F908FEF29C064EFCB +:104B800071E080E090E00E94220A80E021C07885F8 +:104B90006985C101272F362F492F582F6E857F85B4 +:104BA000888999890E94AB3C6E877F87888B998B17 +:104BB0009A858B85282D392D492F582FC301B20195 +:104BC0000E94AB3C2B013C018F818F5F8F83E4CD32 +:104BD00061960FB6F894DEBF0FBECDBFDF91CF91C7 +:104BE0001F910F91FF90EF90DF90CF90BF90AF900B +:104BF0009F908F907F906F905F904F903F902F90FD +:104C00000895FC01228133812230310541F4579A05 +:104C10005F9A85589F4F0E9429095F980895809157 +:104C2000BC0080688093BC00089520E620937C003F +:104C300027E820937A00289A299824B1236024B980 +:104C40005A9A22E02093C80028E92093C90026E060 +:104C50002093CA001092CD002BE92093CC0021E0D4 +:104C6000FC0122830895FC01128210927C001092B4 +:104C70007A001092C8001092C9001092CA001092D7 +:104C8000CD001092CC005A9884B18C7F84B985B144 +:104C90008C7F85B90895CF92DF92EF92FF920F93A8 +:104CA0001F93CF93DF938C0161114EC028982998F0 +:104CB0008DE0E82E88E0F82ECC24CA94DC2CC2EFDC +:104CC000D7E064EF71E080E090E00E94220A019654 +:104CD00009F044C080917A00806480937A008091CA +:104CE0007A0086FDFCCF8091C80080648093C80064 +:104CF000289A299A809179008093CE008091C800EB +:104D000086FFFCCF29982898809179001F928F9375 +:104D1000FF92EF920E946D41F894F8018381948193 +:104D2000D482C38278940F900F900F900F9097FDCC +:104D3000C8CF9F938F93DF93CF930E946D410F90C5 +:104D40000F900F900F90BDCF8EEE97E09F938F93B3 +:104D50000E946D410F900F908FEF01C080E0DF91B6 +:104D6000CF911F910F91FF90EF90DF90CF9008951A +:104D700070E0FC017483638308955F9A08955F98DF +:104D800008955E9A08955E980895139A0895139869 +:104D900008958FEF84B9089580918604813019F4C5 +:104DA0008FEF84B9089514B80895809186048130F6 +:104DB00041F487EB9BE00197F1F700C0000080E031 +:104DC000089583B1089565B90895109A08951098CB +:104DD00008951F93CF93DF93EC01162F0E94C726EF +:104DE0008FEF84B98A81882389F0812F807F85B9EC +:104DF000CE010E94C5268CE38A95F1F7CE010E9470 +:104E0000C72684E08A95F1F71295107F15B9CE0177 +:104E10000E94C5268CE38A95F1F7CE010E94C72631 +:104E200084E08A95F1F7DF91CF911F9108951F9348 +:104E3000CF93DF93EC01162F0E94C326CE010E9470 +:104E4000BF26612FCE01DF91CF911F910C94E926EF +:104E5000EF92FF920F931F93CF93DF93EC017B01AF +:104E60008B8187FD59C080918604813041F487EBA6 +:104E70009BE00197F1F700C0000081E04EC0CE0139 +:104E80000E94CC268FEF85B9CE010E94C126CE01AB +:104E90000E94BF2694E09A95F1F7CE010E94C526A4 +:104EA0008CE38A95F1F7CE010E94D526082FCE011A +:104EB0000E94C72694E09A95F1F7CE010E94C5267C +:104EC0008CE38A95F1F7CE010E94D52682958F70EA +:104ED000007F182F102BCE010E94C72694E09A95D0 +:104EE000F1F7CE010E94C326912F90788BE0E8164F +:104EF000F10430F08BE0E81AF10811F09111C4CF01 +:104F00008B81813021F4992311F08BEF8B8315B8BD +:104F10008FEF84B981E0911180E0DF91CF911F91F3 +:104F20000F91FF90EF900895CF93DF93EC0162E330 +:104F300070E00E942827811102C08AEF8B83DF91E5 +:104F4000CF9108951F93CF93DF93EC01162F0E940A +:104F50009427612F6068CE010E941727CE01DF9150 +:104F6000CF911F910C9494271F93CF93DF93EC0163 +:104F700015B88FEF84B98FE79BEB0197F1F700C06D +:104F800000001B8210E08A81882311F068E201C0D2 +:104F900068E0CE010E941727111105C087E99AE346 +:104FA0000197F1F704C08BE291E00197F1F700C09F +:104FB00000001F5F143039F76CE0CE010E94172704 +:104FC00062E370E0CE010E942827811102C08FEFBA +:104FD0001BC06CE0CE010E94172762E370E0CE0197 +:104FE0000E942827811102C08DEF0EC061E0CE0122 +:104FF0000E94172760EB74E0CE010E9428278111E0 +:1050000002C08CEF01C081E08B83DF91CF911F91B3 +:105010000895CF93DF93EC0181B1896081B98FEF5F +:1050200084B98AB1806C8AB9CE010E94B42780E528 +:1050300098E09F938F930E946D418B810F900F900A +:10504000813049F48CE498E09F938F930E946D41E6 +:105050000F900F9010C0282F082E000C330B3F9399 +:105060008F9382E498E09F938F930E946D410F90FD +:105070000F900F900F90CE01DF91CF910C94E52609 +:10508000CF93DF93FC012381213061F4EC010E9476 +:1050900094276CE0CE010E941727CE01DF91CF91BB +:1050A0000C949427DF91CF910895CF93DF93FC0167 +:1050B0002381213061F4EC010E94942768E0CE0145 +:1050C0000E941727CE01DF91CF910C949427DF9196 +:1050D000CF910895CF93DF93FC012381213061F4B8 +:1050E000EC010E94942761E0CE010E941727CE01B7 +:1050F000DF91CF910C949427DF91CF9108950E9476 +:105100006A2882B1867F82B981B1867F81B915B85C +:1051100014B88BB18F738BB98AB18F738AB9089524 +:10512000CF93DF93EC018B818130B9F44431A8F443 +:10513000613039F048F0623031F0633071F44C5A2C +:1051400003C0405C01C04C5E642FCE010E94A227C8 +:10515000CE01DF91CF910C949427DF91CF910895E8 +:105160001F93CF93DF93FC0123812130A1F4162FED +:10517000EC010E94C326CE010E94BD26612FCE0104 +:105180000E94E926CE010E94BF26CE01DF91CF9179 +:105190001F910C949427DF91CF911F910895FF9256 +:1051A0000F931F93CF93DF938C0161114FC0C0E029 +:1051B00084E1F82ED0E2DC0F8C2F6F2D0E947F3A15 +:1051C000911105C040E0682FC8010E9490286D2F02 +:1051D000C8010E94B028C8010E949427CF5FC03543 +:1051E00049F78DE398E09F938F930E946D41F801FA +:1051F00083810F900F90813049F48AE398E09F9368 +:105200008F930E946D410F900F9010C0282F082E91 +:10521000000C330B3F938F9380E398E09F938F9321 +:105220000E946D410F900F900F900F9061E070E021 +:1052300080E090E00E94220A0196C1F364EF71E0E1 +:1052400080E090E00E94220A80E009C08CE298E0B1 +:105250009F938F930E946D410F900F908FEFDF917E +:10526000CF911F910F91FF9008950F931F93CF93AC +:10527000DF93EC018B01F80161918F01662339F016 +:105280008B81813021F4CE010E94B028F4CFDF91D0 +:10529000CF911F910F9108958BB18F708BB98AB107 +:1052A000806F8AB908958AB18F708AB98BB18F7077 +:1052B0008BB908958130910549F030F08230910525 +:1052C00039F0039739F008955C9A08955D9A08952E +:1052D0005E9A08955F9A0895CB0141110C945A2962 +:1052E0006130710551F038F06230710541F0633082 +:1052F000710539F008955C9808955D9808955E9859 +:1053000008955F9808956130710559F038F0623062 +:10531000710551F06330710559F008959BB180E13A +:1053200005C09BB180E202C09BB180E4892702C026 +:105330008BB180588BB90895CB010C945A2940E069 +:105340000C946C29CF936031E8F5C62FC370C2303E +:1053500091F0C330B9F0C13039F063E070E00E94E1 +:105360009F2980E090E014C060E070E00E949F29D7 +:1053700081E090E00DC061E070E00E949F2982E032 +:1053800090E006C062E070E00E949F2983E090E018 +:105390000E945A296C2F70E06F5F7F4F7F936F934D +:1053A0008FE598E09F938F930E946D4164EF71E0C9 +:1053B00080E090E00E94220A0F900F900F900F90D3 +:1053C00080E001C08FEFCF9108950895FC01128213 +:1053D0001092C8001092C9001092CA001092CD001D +:1053E0001092CC005A9884B18C7F84B985B18C7F9F +:1053F00085B908952F923F924F925F926F927F925C +:105400008F929F92AF92BF92CF92DF92EF92FF92D4 +:105410000F931F93CF93DF9300D000D0CDB7DEB7AB +:105420009C838B83611121C0289A299884B1836061 +:1054300084B95A9A82E08093C80088E98093C900B1 +:1054400086E08093CA001092CD008BE98093CC0057 +:1054500081E0EB81FC81828388E499E09F938F93C4 +:105460000E946D410F900F903DC18FEF860F8430E9 +:1054700008F06EC0633039F0643041F0623051F4AE +:105480001EE801E009C015E500E002C01AEA01E0EB +:10549000F12C04C011E000E0FF24F3941F921F934D +:1054A0001F92FF921F920F9389E299E09F938F932F +:1054B0000E946D410FB6F894DEBF0FBECDBFFF2036 +:1054C00011F0289A01C02898002311F0299A01C0F0 +:1054D0002998EBE2F1E03197F1F700C00000EB8191 +:1054E000FC8113821093CE0087EB9BE00197F1F7CC +:1054F00000C000008381882389F084811F928F93EC +:1055000089E199E09F938F930E946D41EB81FC812B +:1055100013820F900F900F900F9008C088E099E0D1 +:105520009F938F930E946D410F900F908EEE98E0A5 +:105530009F938F930E946D410F900F906FEF7FEFBD +:10554000CB010E94220A0196C9F32998289ACAC061 +:10555000653009F0BDC081EB98E09F938F930E9466 +:105560006D41299A28988BE291E00197F1F700C0EC +:1055700000000F900F9083EA282E88E0382E9BE9D8 +:10558000492E98E0592E2DE8622E28E0722E3BE835 +:10559000832E38E0932E48E8E42E48E0F42E50E8BD +:1055A000C52E58E0D52E64E7A62E68E0B62E299ABF +:1055B000EB81FC81138200E711E0F8018091C800C3 +:1055C00080648093C80081918093CE008091C80050 +:1055D00085FFFCCF21E0E837F20781F78091C80012 +:1055E00086FFFCCF29983F922F920E946D410F9029 +:1055F0000F90F80181918F011F928F935F924F92CC +:105600000E946D410F900F900F900F90F1E00837BE +:105610001F0779F764E670E080E090E00E94220ABC +:105620009A8389837F926F920E946D410F900F90B1 +:10563000EB81FC818381882311F010E01FC09F92D1 +:105640008F920E946D410F900F901DC0183031F461 +:10565000FF92EF920E946D410F900F90EB81FC81C1 +:10566000E10FF11D84811F928F93DF92CF920E94F0 +:105670006D411F5F0F900F900F900F90EB81FC8199 +:105680008381181718F3EB81FC818381803190F0BE +:1056900082899189208937853F932F939F938F9398 +:1056A000BF92AF920E946D410F900F900F900F909C +:1056B0000F900F9089819A810196A1F468EE73E0B2 +:1056C00080E090E00E94220A019609F470CF0AC09F +:1056D00080E798E09F938F930E946D410F900F9009 +:1056E0008FEF07C064EF71E080E090E00E94220A33 +:1056F00080E00F900F900F900F90DF91CF911F914E +:105700000F91FF90EF90DF90CF90BF90AF909F9060 +:105710008F907F906F905F904F903F902F90089563 +:10572000FC012381203130F431E0320F3383E20F6A +:10573000F11D64830895579810927C0010927A00AE +:1057400014BC15BC24B1277E24B91398FC01128225 +:10575000089580B183FB882780F991E08927089517 +:105760002C9808952C9A0895CF93DF93EC01579AC3 +:1057700080E680937C0087E880937A0083E884BD8C +:1057800084E085BD84B1886184B9139ACE010E94FA +:10579000B22B81E08A83DF91CF9108952F923F92BF +:1057A0004F925F926F927F928F929F92AF92BF9231 +:1057B000CF92DF92EF92FF920F931F93CF93DF93DD +:1057C0006111E1C0EC0189ED99E09F938F930E94F4 +:1057D0006D410F900F9089EC482E89E0582E95EB83 +:1057E000692E99E0792E06EA19E02CE9E22E29E0EB +:1057F000F22E31E9C32E39E0D32E45E8A42E49E03C +:10580000B42E54E5252E59E0352E6DE6862E69E03E +:10581000962E6AE070E080E090E00E94220A0196F5 +:1058200009F0B3C080B183FB882780F91F928F9362 +:105830008EEC99E09F938F930E946D410F900F9093 +:105840000F900F90CE01039905C00E94B02B5F927C +:105850004F9206C00E94B22B84EC99E09F938F93E5 +:105860000E946D410F900F9080917A008064809328 +:105870007A0080917A0086FDFCCF809179001F929A +:105880008F937F926F920E946D4182EE80937C0095 +:105890008091790090E005970F900F900F900F90F6 +:1058A00097FF02C080E090E0809587BD1F928F93A4 +:1058B0001F930F930E946D4180917A0080648093C2 +:1058C0007A000F900F900F900F9080917A0086FDD4 +:1058D000FCCF809179001F928F93FF92EF920E94EC +:1058E0006D4190E690937C0083B182FB882780F91C +:1058F0001F928F93DF92CF920E946D4183B181708E +:105900001F928F93BF92AF920E946D41F8946B816A +:105910007C8178948DB79EB70C960FB6F8949EBF95 +:105920000FBE8DBF6115710519F17F936F9380E0F4 +:1059300090E00E94C53D9B01AC0160E070E080E713 +:1059400092E40E94173D27E137EB41ED58E30E94B6 +:10595000173D0E94893D7F936F939F928F920E9483 +:105960006D410F900F900F900F900F900F9051CFAF +:105970001F921F923F922F920E946D410F900F90A5 +:105980000F900F9046CF8FEF01C080E0DF91CF9155 +:105990001F910F91FF90EF90DF90CF90BF90AF904D +:1059A0009F908F907F906F905F904F903F902F903F +:1059B000089583B182FB882780F991E089270895B3 +:1059C00083B1817008958BB180588BB908951F936E +:1059D000CF93DF93EC0123B18091DB049091DC0441 +:1059E000122F117020FD1BC02091DF04222309F12A +:1059F0002091DD043091DE0423303105D0F0820F98 +:105A0000931F9C838B831092DE041092DD0410920E +:105A1000DC041092DB04CE010E94E32C0AC0811545 +:105A200020E4920748F501969093DC048093DB0410 +:105A30000DC08091DD049091DE04811520E4920771 +:105A4000F0F401969093DE048093DD048091DB04F2 +:105A50009091DC048115904438F48091DD0490919C +:105A6000DE048115904410F01C821B821093DF0429 +:105A7000DF91CF911F91089580E090E4D5CF80E031 +:105A800090E4E0CFE4E6F0E0808184708083179AB0 +:105A90000F9A2C9A84B1806B84B926988CB5836553 +:105AA0008CBD0895269884B18F7584B90F98179886 +:105AB0001CBC089517980895179A08950F931F9383 +:105AC000CF93DF93EC01062F142F0E945A2D80E410 +:105AD0008EBD0DB407FEFDCF0EBD0DB407FEFDCF8C +:105AE0001EBD0DB407FEFDCFCE010E945C2D84E1EA +:105AF0008A95F1F780E0DF91CF911F910F91089582 +:105B00001F93CF93DF93EC01162F0E945A2D81E44F +:105B10008EBD0DB407FEFDCF1EBD0DB407FEFDCF3B +:105B20001EBC0DB407FEFDCFCE010E945C2D8EB5CC +:105B3000DF91CF911F910895CF93DF93C42FD22F80 +:105B40001F924F931F926F938CE69AE09F938F93CF +:105B50000E946D410F900F900F900F900F900F903B +:105B6000CD1769F085E69AE09F938F930E946D416F +:105B70000F900F90CF3F59F48AE49AE002C086E478 +:105B80009AE09F938F930E946D410F900F9084E451 +:105B90009AE09F938F930E946D410F900F90DF9139 +:105BA000CF9108952F923F924F925F926F927F9282 +:105BB0008F929F92AF92BF92CF92DF92EF92FF921D +:105BC0000F931F93CF93DF936111D8C0EC0185E34E +:105BD000282E8AE0382ECC24C394D12C20E2422EE9 +:105BE0002AE0522E3BE0632E3AE0732E46EFA42EBD +:105BF00049E0B42E51EE852E59E0952E64EF71E008 +:105C000080E090E00E94220A019609F0B9C03F921C +:105C10002F920E946D410F900F90E12CF12C860184 +:105C20000E2C01C0000F0A94EAF7402F409560E067 +:105C3000CE010E945E2D402F62E1CE010E945E2DBA +:105C4000FF92EF925F924F920E946D4162E1CE010E +:105C50000E94802D202F482F62E1CE010E949C2DB2 +:105C600068EC70E080E090E00E94220A40E062E18F +:105C7000CE010E945E2DFF92EF927F926F920E9462 +:105C80006D4162E1CE010E94802D20E0482F62E14B +:105C9000CE010E949C2D4FEF60E0CE010E945E2D50 +:105CA00068EC70E080E090E00E94220A8FEFE81A32 +:105CB000F80A8DB79EB708960FB6F8949EBF0FBE30 +:105CC0008DBF98E0E916F10409F0A9CF00E010E0DB +:105CD0007601002E01C0EE0C0A94EAF74E2D409595 +:105CE00061E0CE010E945E2D4E2D63E1CE010E9447 +:105CF0005E2D1F930F93BF92AF920E946D4163E19F +:105D0000CE010E94802D2E2D482F63E1CE010E94EE +:105D10009C2D68EC70E080E090E00E94220A40E058 +:105D200063E1CE010E945E2D1F930F939F928F928D +:105D30000E946D4163E1CE010E94802D20E0482F3A +:105D400063E1CE010E949C2D4FEF61E0CE010E94E5 +:105D50005E2D68EC70E080E090E00E94220A0F5F08 +:105D60001F4F8DB79EB708960FB6F8949EBF0FBE13 +:105D70008DBF0830110509F0ABCF40CF8FEF01C0C8 +:105D800080E0DF91CF911F910F91FF90EF90DF9016 +:105D9000CF90BF90AF909F908F907F906F905F90CB +:105DA0004F903F902F90089580E480937C0087E887 +:105DB00080937A00089510927C0010927A000895E2 +:105DC0000F931F93CF93DF9361113AC08EEA9AE04D +:105DD0009F938F930E946D410F900F9009E91AE0F5 +:105DE000CCE8DAE06AE070E080E090E00E94220A0D +:105DF000019641F51F930F930E946D4180917A00A7 +:105E0000806480937A000F900F9080917A0086FDD5 +:105E1000FCCF2091780030917900809178009091AA +:105E200079003F932F939F938F93DF93CF930E949B +:105E30006D410F900F900F900F900F900F90D2CF59 +:105E40008FEF01C080E0DF91CF911F910F910895F6 +:105E500082E480937C0087E880937A000895109212 +:105E60007C0010927A000895AF92BF92CF92DF9299 +:105E7000EF92FF920F931F93CF93DF9361117FC037 +:105E800087EF9AE09F938F930E946D410F900F9040 +:105E900032EEE32E3AE0F32E05ED1AE0C5EBDAE040 +:105EA0006AE070E080E090E00E94220A019609F02A +:105EB00068C0FF92EF920E946D4180917A008064E9 +:105EC00080937A000F900F9080917A0086FDFCCF2E +:105ED000209178003091790080917800909179003C +:105EE0003F932F939F938F931F930F930E946D4126 +:105EF000609178007091790080E090E00E94C53D4B +:105F00002AE939E941E852E40E94173D2DEC3CECC6 +:105F10004CE05FE30E94AB3CD62EC72EB82EA92ED4 +:105F2000A6019501652F742F832F922F0E94903D1B +:105F3000862F90E061701F926F9381FB222720F9DA +:105F40001F922F9382FB222720F91F922F9323E089 +:105F5000959587952A95E1F79F938F93AF92BF927E +:105F6000CF92DF92DF93CF930E946D418DB79EB7A2 +:105F700044960FB6F8949EBF0FBE8DBF91CF8FEFA2 +:105F800001C080E0DF91CF911F910F91FF90EF90C2 +:105F9000DF90CF90BF90AF900895442371F06130AF +:105FA000710539F020F06230710529F008952898C4 +:105FB0000895299808952A9808956130710539F057 +:105FC00020F06230710529F00895289A0895299AE1 +:105FD00008952A9A08956130710541F020F06230E9 +:105FE000710539F0089595B181E005C095B182E061 +:105FF00002C095B184E0892785B9089541E00C94E9 +:10600000CD2F40E00C94CD2FCF93DF93EC0160E0D7 +:1060100070E00E94013061E070E0CE010E9401302A +:1060200062E070E0CE010E94013084B1876084B9E3 +:10603000DF91CF910895CF93DF93EC0160E070E0A2 +:106040000E94013061E070E0CE010E94013062E008 +:1060500070E0CE010E94013084B1887F84B9DF9165 +:10606000CF910895CF93DF93EC01613009F43FC0E5 +:1060700058F1623009F44EC0633009F064C060E04A +:1060800070E00E94FE2F61E070E0CE010E94FE2FC2 +:1060900062E070E0CE010E94FE2F8DEF9AE09F93A8 +:1060A0008F930E946D4168EB7BE080E090E00E945E +:1060B000220A60E070E0CE010E94013061E070E0F1 +:1060C000CE010E94013036C060E070E00E94FE2FD9 +:1060D0008CE09BE09F938F930E946D4168EB7BE087 +:1060E00080E090E00E94220A60E070E025C061E05C +:1060F00070E00E94FE2F86E09BE09F938F930E94AA +:106100006D4168EB7BE080E090E00E94220A61E054 +:1061100070E012C062E070E00E94FE2F81E09BE020 +:106120009F938F930E946D4168EB7BE080E090E04D +:106130000E94220A62E070E0CE010E9401300F90BE +:106140000F9080E001C08FEFDF91CF9108954798C5 +:106150003F9AE8EBF0E02DE020832CE1208324E659 +:10616000208324E02093BC0021E0FC0124830895D7 +:10617000FC01148284E08093BC001092B800089562 +:106180008BEA9DE00895ECEBF0E0808180688083ED +:106190000895862F8695869586958E71982F990FEE +:1061A000990F890F6F70860F08950F931F93CF93E8 +:1061B000DF938C01EA019E859C7F92609E8781E03F +:1061C000611101C080E09E8580FB97F99E876F87F3 +:1061D000998180FB90F99B7F98609983662389F071 +:1061E0001F929F931F926F938FEE9BE09F938F93CD +:1061F0000E946D410F900F900F900F900F900F9095 +:1062000008C08EED9BE09F938F930E946D410F908D +:106210000F900E5F1F4F21E0AE014F5F5F4F61E0B7 +:10622000C8010E94EE078823A1F0AE01425F5F4FD4 +:1062300022E06EE0C8010E94EE07C82F882349F0D3 +:106240008BED9BE09F938F930E946D410F900F9079 +:1062500009C085ED9BE09F938F930E946D410F9045 +:106260000F90C0E08C2FDF91CF911F910F91089577 +:10627000CF92DF92EF92FF920F931F93CF93DF9312 +:106280007C01EA01479B10C086EC9BE09F938F93B3 +:106290000E946D413F9A4798AE0160E0C7010E949D +:1062A000D5300F900F905CC084EC9BE09F938F9350 +:1062B0000E946D410F900F9009E010E082E8C82E17 +:1062C0008BE0D82E1F930F93DF92CF920E946D41E7 +:1062D00068EE73E080E090E00E943D0A0F900F901E +:1062E0000F900F900130110531F0015011098F3FCF +:1062F0002FEF920739F34B9799F1AE016AE0C7018E +:106300000E94D530898188608B7F81608983AE014E +:106310004F5F5F4F21E061E0C70102960E94EE07E8 +:106320008EE69BE09F938F930E946D413F9A479A20 +:1063300087E99AE30197F1F700C000003F9847987A +:1063400068E873E180E090E00E943D0A8CE39BE006 +:106350009F938F930E946D410F900F900F900F901D +:1063600081E0DF91CF911F910F91FF90EF90DF902F +:10637000CF9008958F929F92AF92BF92CF92DF926B +:10638000EF92FF920F931F93CF93DF93CDB7DEB7BA +:1063900027970FB6F894DEBF0FBECDBF4C01362F46 +:1063A000CA011E2DFC2DEA2DBA01605D774051E037 +:1063B0006536710508F450E04E8150FB47F94E8375 +:1063C00064E670E00E94993A6AE00E947F3A829502 +:1063D000807F982B9F8337FF02C0395FFCCF373017 +:1063E00014F03750FCCF37708D81887F382B3D8378 +:1063F000121614F0245FFCCF2D3014F02C50FCCF7B +:10640000822F6AE00E948B3A9F702E81207F922B10 +:1064100080FB94F99E83101614F0015EFCCF0032CD +:1064200014F00F51FCCF802F6AE00E948B3A9F70CE +:106430003C81307C8370282F2295207F832F892BED +:10644000822B8C8317FF02C0185EFCCF183114F02A +:106450001851FCCF812F6AE00E948B3A9F703B81DC +:10646000307C8370282F2295207F832F892B822BCD +:106470008B83F7FF02C0F45CFCCFFC3314F0FC53B9 +:10648000FCCF8F2F6AE00E948B3A9F703A81307860 +:106490008770282F2295207F832F892B822B8A8338 +:1064A000E7FF02C0E45CFCCFEC3314F0EC53FCCF0C +:1064B0008E2F6AE00E948B3A9F7039813078877006 +:1064C000282F2295207F832F892B822B8983CE0131 +:1064D00007969F938F9301979F938F9301979F9315 +:1064E0008F9301979F938F9301979F938F9301971A +:1064F0009F938F938E010F5F1F4F1F930F938AE11E +:106500009BE09F938F930E946D4178015E0188E02C +:10651000A80EB11C0FB6F894DEBF0FBECDBF84E14C +:10652000C82E8BE0D82EF70181917F011F928F93A7 +:10653000DF92CF920E946D410F900F900F900F90BD +:10654000AE14BF0481F727E0A80162E0C4010296FF +:106550000E94EE0727960FB6F894DEBF0FBECDBFA0 +:10656000DF91CF911F910F91FF90EF90DF90CF902F +:10657000BF90AF909F908F9008952F923F924F922F +:106580005F926F927F928F929F92AF92BF92CF92C3 +:10659000DF92EF92FF920F931F93CF93DF93CDB7CC +:1065A000DEB76E970FB6F894DEBF0FBECDBF611198 +:1065B00066C22C019C012E5F3F4F3D8F2C8F61E501 +:1065C000C9010E946B07CE0101969A8F898F80E1E5 +:1065D000E98DFA8D11928A95E9F785E99DE09F93FF +:1065E0008F930E946D418A8181608A8342E0BE015F +:1065F0006F5F7F4F8C8D9D8D0E9443080F900F9091 +:10660000811103C088EF91E002C083EF91E09F9376 +:106610008F930E946D410F900F908CE89DE09F93A7 +:106620008F930E946D4184E79DE09F938F930E941A +:106630006D4182E59DE09F938F930E946D418CE3B5 +:106640009DE09F938F930E946D4182E29DE09F9316 +:106650008F930E946D418CE09DE09F938F930E94E9 +:106660006D4185EF9CE09F938F930E946D4180EE7A +:106670009CE09F938F930E946D418AEC9CE09F93D6 +:106680008F930E946D4182EB9CE09F938F930E94B9 +:106690006D4189E99CE09F938F930E946D410FB6F5 +:1066A000F894DEBF0FBECDBF188E8AE79CE09F93A3 +:1066B0008F930E946D4100E19E012F5F3F4F41E0AB +:1066C000BE01685E7F4F8C8D9D8D0E948B080F9060 +:1066D0000F90811110C088EF91E09F938F930E94DB +:1066E0006D4168EE73E080E090E00E943D0A4C014D +:1066F0000F900F90BDC127E030E047E050E0BE01B1 +:106700006D5F7F4FCE0141960E94C5409E012F5F75 +:106710003F4F790110E0812F837041F488E79CE0BE +:106720009F938F930E946D410F900F90F70181917D +:106730007F011F928F9322E73CE03F932F930E94AB +:106740006D411F5F0F900F900F900F90103119F750 +:106750008E8987FD03C040ED57E002C044E358E056 +:106760008F89982F9695969596959E71292F220F31 +:10677000220F920F8F70890F1A01280E311C8E89FB +:10678000982F9695969596959E71792E770C770C05 +:10679000790E8F70780E672C8C89982F9695969528 +:1067A00096959E71B92EBB0CBB0CB90E8F70B80EAE +:1067B000BB8E8B89982F9695969596959E71D92E1E +:1067C000DD0CDD0CD90E8F70D80EED2C8A89982F38 +:1067D0009695969596959E71F92EFF0CFF0CF90EE5 +:1067E0008F70F80ECF2C8989182F1695169516954F +:1067F0001E71912F990F990F190F8F70180FA12EDD +:106800000D890E8F073048F4E3E00E02C001112419 +:106810009C012C54324F490104C03FE6832E3CE0DA +:10682000932E88E69CE09F938F930E946D419F92E8 +:106830008F920E946D41812F012E000C990B9F9326 +:106840001F938F2D0F2C000C990B9F93FF928D2D72 +:106850000D2C000C990B9F93DF928B2D0B2C000CB1 +:10686000990B9F93BF92872D072C000C990B9F9338 +:106870007F923F922F92802F002E000C990B9F93B6 +:106880000F9325E43CE03F932F930E946D4188894C +:106890001F928F93E5E3FCE0FF93EF930E946D411D +:1068A00068EE73E080E090E00E943D0A4C010FB674 +:1068B000F894DEBF0FBECDBF94E68916910409F4AB +:1068C00090C0F4F5FEE48F16910409F494C08CF4A2 +:1068D00038E48316910409F487C08DE48816910486 +:1068E00009F47BC094E48916910409F0C1C0BA94FC +:1068F00079C0E7E58E16910409F485C044F423E5D8 +:106900008216910409F0B4C0AA24AA9478C039E58B +:106910008316910409F45AC083E68816910409F09D +:10692000A7C08AE0A82E9CE0C92E21E1E22E00E15A +:1069300028E048EE57E065E0C2010E94BA3198C0F5 +:1069400090E789169104D1F194F4FDE68F16910435 +:1069500009F440C02EE68216910409F449C038E6D5 +:106960008316910409F084C0EE24E3943FC084E7C9 +:1069700088169104B1F044F4E3E78E16910409F00F +:1069800077C0AA24A3943BC0F7E78F169104C9F1FE +:1069900029E78216910409F06BC03FEF231A330AEE +:1069A00034C08F8587FD02C06AE001C060E0AE019F +:1069B0004F5F5F4FC2010E94D5305AC0AE014F5F9A +:1069C0005F4F6AE0C2010E94383152C081E0281A4C +:1069D00031081BC06624639402C066246A94670C65 +:1069E00014C0B394BB8E11C0EE24EA94ED0C0DC01C +:1069F000CC24C39402C0CC24CA94CF0C06C0A10EF0 +:106A000004C00F5F01C001500E8F8A2D0A2C000CAC +:106A1000990B9F93AF928C2D0C2C000C990B9F938C +:106A2000CF928E2D0E2C000C990B9F93EF92EB8D35 +:106A30008E2F0E2E000C990B9F93EF93862D062C14 +:106A4000000C990B9F936F923F922F9220E13CE0B4 +:106A50003F932F930E946D410B8D262DA1016E8DCA +:106A6000C2010E94BA310FB6F894DEBF0FBECDBF8F +:106A70009BE18916910409F017CE80E001C08FEFE9 +:106A80006E960FB6F894DEBF0FBECDBFDF91CF91EB +:106A90001F910F91FF90EF90DF90CF90BF90AF903C +:106AA0009F908F907F906F905F904F903F902F902E +:106AB000089560FF02C0289A01C0289861FF02C0B3 +:106AC000299A01C0299862FF02C02A9A01C02A9817 +:106AD00063FF02C02B9A01C02B9864FF02C02C9A5E +:106AE00001C02C9865FF02C02D9A01C02D9866FF49 +:106AF00002C02E9A01C02E9867FF02C02F9A01C0D3 +:106B00002F9880918604813019F0823061F00895C9 +:106B100070FF02C05E9A01C05E9871FF02C05F9A6A +:106B200008955F98089570FF02C0129A01C01298EC +:106B300071FF02C0139A08951398089580918604F6 +:106B4000813019F08230B1F0089560FF02C0109AD0 +:106B500001C0109861FF02C0119A01C0119862FF34 +:106B600002C0129A01C0129863FF02C0139A0895DE +:106B70001398089560FF02C05C9A01C05C9861FFA1 +:106B800002C05D9A01C05D9862FF02C05E9A01C0BA +:106B90005E9863FF02C05F9A08955F980895CF934F +:106BA000DF93EC0160E070E00E94593560E0CE01B7 +:106BB0000E949E358FEF84B980918604813041F028 +:106BC000823061F481B18E6081B98AB1806F05C075 +:106BD00081B18F6081B98AB1806E8AB9DF91CF911E +:106BE0000895CF93DF93EC0160E070E00E94593587 +:106BF00060E0CE010E949E3514B8809186048130F9 +:106C000041F0823061F481B1817F81B98AB18F70A6 +:106C100005C081B1807F81B98AB18F718AB9DF9156 +:106C2000CF91089580918604813019F0823039F037 +:106C30000895662311F05D9808955D9A089566237E +:106C400011F011980895119A0895CF92DF92EF9262 +:106C5000FF920F931F93CF93DF937C01611117C0B5 +:106C60006FE00E949E356FEF73E0C7010E945935B7 +:106C700061E0C7010E94123685EF9DE09F938F93DC +:106C80000E946D4160ED77E080E090E028C06130C7 +:106C900069F481EF9DE09F938F930E946D4168EEB0 +:106CA00073E080E090E00E94220A20C0623039F454 +:106CB00060E071E00E94593588EE9DE008C06330C5 +:106CC000C1F460E072E00E9459358FED9DE09F9322 +:106CD0008F930E946D4168EE73E080E090E00E9427 +:106CE000220A60E070E0C7010E9459350F900F90B2 +:106CF00044C0643208F043C0C62FD0E024978E0110 +:106D000083E0159507958A95E1F7C770DD27CC24B8 +:106D1000C394D12CB601002E01C0660F0A94EAF785 +:106D2000C7010E949E350C2E02C0CC0CDD1C0A94BB +:106D3000E2F7B601C7010E945935DF92CF92CC0F1E +:106D4000DD1FC05EDE4F89818F9388818F931F93F3 +:106D50000F938AEC9DE09F938F930E946D4160E9B1 +:106D600071E080E090E00E94220A8DB79EB70896FD +:106D70000FB6F8949EBF0FBE8DBF80E001C08FEFAD +:106D8000DF91CF911F910F91FF90EF90DF90CF9007 +:106D9000089581B1807F81B982B18F6082B90895F1 +:106DA00082B1807F82B981B1807F81B908956130DD +:106DB000710581F058F06230710581F06330710522 +:106DC000A1F480B183FB882780F90CC080B1809545 +:106DD0008170089580B18695817004C080B182FB76 +:106DE000882780F991E08927089580E008950F931E +:106DF0001F93CF93DF93603108F04EC08C01C62FF4 +:106E0000C695C695D0E06370613021F0633009F417 +:106E10004BC021C0BE010E94D736811145C0CE01B2 +:106E200001969F938F938BE09EE09F938F930E9498 +:106E30006D410F900F900F900F90BE01C8010E94FE +:106E4000D73681112BC060E070E0CB010E94220A8E +:106E5000019621F5F2CFBE010E94D736882321F199 +:106E6000CE0101969F938F938DEF9DE09F938F931B +:106E70000E946D410F900F900F900F90BE01C801BE +:106E80000E94D736882351F060E070E0CB010E9469 +:106E9000220A019619F4F2CF8FEF07C06AE070E082 +:106EA00080E090E00E94220A80E0DF91CF911F9164 +:106EB0000F910895CF93C82F8A3019F48DE00E9466 +:106EC0005A378091C80085FFFCCFC093CE0080E088 +:106ED00090E0CF9108955A9A22E02093C80028E9C3 +:106EE0002093C90026E02093CA001092CD002CE028 +:106EF0002093CC0020E331E03093E5042093E404B8 +:106F000021E0FC0122830895FC0112821092C80046 +:106F10001092C9001092CA001092CD001092CC00BD +:106F20001092E5041092E40408950F931F93CF93F9 +:106F3000DF93611122C00DE31EE0CDE1DEE01F937F +:106F40000F930E946D41DF93CF938091E5048F935F +:106F50008091E4048F930E94144168E873E180E01B +:106F600090E00E94220A0F900F900F900F900F90C8 +:106F70000F90019621F380E001C08FEFDF91CF9158 +:106F80001F910F910895862F6091E4047091E5049C +:106F90000C945A370F931F93CF93DF93EC018B011F +:106FA00080EA91E099838883CE0104960E943A0C8E +:106FB000CE01CD960E948315CE0187589F4F0E9427 +:106FC0006007CE0185589F4F0E94C608FE01E0571A +:106FD000FF4F10821B830A83DF91CF911F910F9186 +:106FE0000895CF93DF93CDB7DEB7AC970FB6F89483 +:106FF000DEBF0FBECDBF87B18C6987B988B18376FC +:1070000088B93D98459A82E08093C00098E99093B2 +:10701000C10096E09093C2001092C5009CE090934E +:10702000C4008093B0008093B10096E99093B300C0 +:107030008093700080E191E09093E3048093E204F8 +:1070400082E091E09093E1048093E004789486E2FA +:10705000EEE3F1E0DE01119601900D928A95E1F7E1 +:107060000E94C7090EEF11E0F0E0EF2EF2E0FF2ED4 +:107070006E0127E2C20ED11C1E013BE2230E311C21 +:107080006EE7462E61E0562E75E3672E72E0772E8E +:10709000E1E7AE2EE1E0BE2E1F930F930E946D41FB +:1070A000FF92EF920E946D4189E292E09F938F934D +:1070B0000E946D4122E831E03F932F930E946D4181 +:1070C000AEE3B2E0BF93AF930E946D415F924F92E7 +:1070D0000E946D417F926F920E946D41FF92EF92EC +:1070E0000E946D41809186049FEF980F0FB6F8942F +:1070F000DEBF0FBECDBF9230C8F40E94BA099F9385 +:107100008F93BF92AF920E946D41FF92EF920E94C7 +:107110006D411F930F930E946D418EE591E09F9307 +:107120008F930E946D411CA61BA60DC01F928F93CA +:1071300081E491E09F938F930E946D410F900F9097 +:107140000F900F90FFCF0FB6F894DEBF0FBECDBFEC +:107150008BA59CA58331910548F5FC01EE0FFF1F1F +:10716000A1E0B0E0AC0FBD1FEA0FFB1F8080918053 +:107170009F938F9328E331E03F932F930E946D41BB +:10718000D401ED91FC910680F781E02DC4010995B1 +:107190009F938F930E946D411F930F930E946D41A7 +:1071A0008BA59CA501969CA78BA7CDCF89E291E0EA +:1071B0009F938F930E946D4110925D0410925C0426 +:1071C0004091E0045091E10464E070E0C6010E9447 +:1071D000E2403F922F9288E791E09F938F93DF9256 +:1071E000CF920E9495410FB6F894DEBF0FBECDBF7F +:1071F000019709F051CF8BA59CA58331910508F02B +:107200004BCF880F991FE1E0F0E0EC0FFD1FE80F76 +:10721000F91FA080B18085E291E09F938F930E9437 +:107220006D41D501ED91FC910680F781E02DC501FE +:1072300009959F938F930E946D4181E291E09F9306 +:107240008F930E946D418FEF9FEF90930101809388 +:107250000001D501ED91FC910280F381E02DC50183 +:1072600009950F900F900F900F900F900F90812C19 +:10727000912C3AE1632E31E0732E44244A94542C2D +:107280009F928F927F926F920E946D41D501ED91F6 +:10729000FC910190F081E02D682DC50109950F90BA +:1072A0000F900F900F9087FD18C080910001909172 +:1072B00001014B9739F48FEF9FEF90930101809379 +:1072C00000010BC05092010140920001BFEF8B1AE8 +:1072D0009B0A2FEF8216910499F6D501ED91FC914E +:1072E0000480F581E02DC5010995CACE84EC91E0BA +:1072F00090935B0480935A0481E492E09093590444 +:10730000809358048CE092E0909357048093560445 +:1073100084E292E0909354048093530410925504B5 +:1073200084EF91E0909352048093510482E991E0BC +:1073300090934E0480934D041092500410924F0489 +:1073400080E092E090934C0480934B048CED91E0AC +:1073500090934704809346041092480410924A0484 +:107360001092490488EE91E0909345048093440480 +:1073700088EB91E0909341048093400481E09091E8 +:107380008604913009F480E0809342041092430413 +:107390008DE492E090933E0480933D0410923F046C +:1073A00080ED91E090932A048093290410922B049D +:1073B00010922C048CEA91E090932504809324048D +:1073C000109226048FEF9FEF909328048093270458 +:1073D00060E070E083E993E00E94CA3761E070E00A +:1073E00082E093E00E94CA3762E070E081E792E0B9 +:1073F0000E94CA3788E192E090936B0280936A0200 +:107400008CE692E00E94600710926E021092700269 +:1074100010926F0286E891E090936102809360027F +:107420001092680221E030E03093670220936602F8 +:10743000109262021092630210926402109265022E +:10744000909357028093560210925E0282E090E081 +:1074500090935D0280935C02109258021092590240 +:1074600010925A0210925B02089588E994E00E94FB +:107470003A0C88E191E0909397048093960490935E +:1074800095048093940490939304809392040895B8 +:1074900080E496E0089584E298E008958BE598E012 +:1074A00008958CE698E008958DE499E008958BEDB9 +:1074B00099E0089584E89AE0089580EB9AE00895B1 +:1074C00089EF9AE0089580E19BE0089588EF9DE0C0 +:1074D000089586E19EE008958DE59EE00895DB0124 +:1074E0008F939F930E94CC3ABF91AF91A29F800D42 +:1074F000911DA39F900DB29F900D11240895991B8B +:1075000079E004C0991F961708F0961B881F7A959A +:10751000C9F78095089587FB082E062687FD81957B +:1075200067FD61950E947F3A0EF4919507FC819565 +:107530000895AA1BBB1B51E107C0AA1FBB1FA617BA +:10754000B70710F0A61BB70B881F991F5A95A9F70C +:1075500080959095BC01CD010895052E97FB1EF4F2 +:1075600000940E94C43A57FD07D00E94703C07FC6B +:1075700003D04EF40C94C43A509540953095219523 +:107580003F4F4F4F5F4F089590958095709561954F +:107590007F4F8F4F9F4F08950E949B3CA59F900D5A +:1075A000B49F900DA49F800D911D11240895B7FFE5 +:1075B0000C94CC3A0E94CC3A821B930B0895DF9333 +:1075C000CF931F930F939A9DF02D219FF00D8B9DCC +:1075D000F00D8A9DE02DF10D039FF00D029FE00D4F +:1075E000F11D4E9DE00DF11D5E9DF00D4F9DF00DC6 +:1075F0007F936F93BF92AF925F934F93D5010E9499 +:107600009B3C8B01AC01D7010E949B3CEB01E80F36 +:10761000F91FD6010E942F3B2F913F91D6010E9466 +:107620009B3CC60FD71FE81FF91FAF91BF910E9467 +:107630002F3B2F913F910E949B3CC60FD71FE81F05 +:10764000F91FD6010E949B3CE60FF71F9801BE016F +:10765000CF0111240F911F91CF91DF9108950E94C6 +:107660009B3C460F571FC81FD91F08F43196089539 +:10767000689401C0E894F92FF12B12F00C946C3B44 +:10768000A0E0B0E0E6E4FBE30C94DE3B092E0594B9 +:1076900022F40E94C83B112392F4F0E80F26FFEF7A +:1076A000E094F09400951095B094C094D094A19477 +:1076B000BF0ACF0ADF0AEF0AFF0A0F0B1F0B0E9457 +:1076C000773B07FC0E94C83BCDB7DEB7ECE00C94DB +:1076D000FA3B689401C0E8948F929F92CF93DF9316 +:1076E0000E94773BDF91CF919F908F9008958824DF +:1076F0009924F401E401B0E49F93AA279A158B041E +:107700009C04ED05FE05CF05D007A10798F4AD2F29 +:10771000DC2FCF2FFE2FE92D982C892E982F872F25 +:10772000762F652F542F432F322F2227B85031F751 +:10773000BF9127C01B2EBF91BB27220F331F441FB1 +:10774000551F661F771F881F991F881C991CEE1FE5 +:10775000FF1FCC1FDD1FAA1FBB1F8A149B04EC0553 +:10776000FD05CE05DF05A007B10748F08A189B0884 +:10777000EC09FD09CE09DF09A00BB10B21601A94B9 +:10778000E1F62EF49401AF01BE01CD01000C089585 +:107790006095709580959095309540955095219580 +:1077A0003F4F4F4F5F4F6F4F7F4F8F4F9F4F08950A +:1077B0002F923F924F925F926F927F928F929F9201 +:1077C000AF92BF92CF92DF92EF92FF920F931F93EF +:1077D000CF93DF93CDB7DEB7CA1BDB0B0FB6F894A0 +:1077E000DEBF0FBECDBF09942A88398848885F84E0 +:1077F0006E847D848C849B84AA84B984C884DF8051 +:10780000EE80FD800C811B81AA81B981CE0FD11D34 +:107810000FB6F894DEBF0FBECDBFED0108950F93F4 +:10782000083090F0982F872F762F652F542F432FF5 +:10783000322F22270850F4CF220F331F441F551F29 +:10784000661F771F881F991F0A95B2F70F91089539 +:1078500097FB10F8169400080F93083098F0085022 +:10786000232F342F452F562F672F782F892F902DB8 +:10787000F4CF059497958795779567955795479594 +:10788000379527950A95AAF70F9108952A0D3B1D64 +:107890004C1D5D1D6E1D7F1D801F911F08950024CE +:1078A000A7FD00942A0F301D401D501D601D701D46 +:1078B000801D901D08952A193B094C095D096E0928 +:1078C0007F09800B910B08950024A7FD00942A17CF +:1078D0003005400550056005700580059005089548 +:1078E000A1E21A2EAA1BBB1BFD010DC0AA1FBB1FC4 +:1078F000EE1FFF1FA217B307E407F50720F0A21B36 +:10790000B30BE40BF50B661F771F881F991F1A94A2 +:1079100069F760957095809590959B01AC01BD01CC +:10792000CF010895EE0FFF1F0024001C0BBE07902F +:10793000F691E02D0994A29FB001B39FC001A39FCF +:10794000700D811D1124911DB29F700D811D112498 +:10795000911D08955058BB27AA270E94C23C0C9441 +:10796000673E0E94593E38F00E94603E20F039F494 +:107970009F3F19F426F40C94463E0EF4E095E7FB85 +:107980000C94403EE92F0E94783E58F3BA176207E4 +:1079900073078407950720F079F4A6F50C949A3EB6 +:1079A0000EF4E0950B2EBA2FA02D0B01B90190011A +:1079B0000C01CA01A0011124FF27591B99F0593F5E +:1079C00050F4503E68F11A16F040A22F232F342FA6 +:1079D0004427585FF3CF469537952795A795F040F4 +:1079E0005395C9F77EF41F16BA0B620B730B840B09 +:1079F000BAF09150A1F0FF0FBB1F661F771F881FC1 +:107A0000C2F70EC0BA0F621F731F841F48F4879518 +:107A100077956795B795F7959E3F08F0B0CF93950A +:107A2000880F08F09927EE0F9795879508950E9483 +:107A30002B3D0C94673E0E94603E58F00E94593ED8 +:107A400040F029F45F3F29F00C94403E51110C9412 +:107A50009B3E0C94463E0E94783E68F39923B1F316 +:107A6000552391F3951B550BBB27AA276217730764 +:107A7000840738F09F5F5F4F220F331F441FAA1FF8 +:107A8000A9F335D00E2E3AF0E0E832D091505040B4 +:107A9000E695001CCAF72BD0FE2F29D0660F771F62 +:107AA000881FBB1F261737074807AB07B0E809F048 +:107AB000BB0B802DBF01FF2793585F4F3AF09E3FCD +:107AC000510578F00C94403E0C949B3E5F3FE4F3EC +:107AD000983ED4F3869577956795B795F7959F5F10 +:107AE000C9F7880F911D9695879597F90895E1E05C +:107AF000660F771F881FBB1F621773078407BA07BB +:107B000020F0621B730B840BBA0BEE1F88F7E09515 +:107B100008950E94903D6894B1110C949B3E089585 +:107B20000E94803E88F09F5798F0B92F9927B7514F +:107B3000B0F0E1F0660F771F881F991F1AF0BA9511 +:107B4000C9F714C0B13091F00E949A3EB1E0089597 +:107B50000C949A3E672F782F8827B85F39F0B93F89 +:107B6000CCF3869577956795B395D9F73EF49095C4 +:107B70008095709561957F4F8F4F9F4F089597FB2C +:107B800016F40E94493E0C94033EE89409C097FB0A +:107B90003EF490958095709561957F4F8F4F9F4FE4 +:107BA0009923A9F0F92F96E9BB279395F695879528 +:107BB00077956795B795F111F8CFFAF4BB0F11F4EB +:107BC00060FF1BC06F5F7F4F8F4F9F4F16C0882392 +:107BD00011F096E911C0772321F09EE8872F762FC8 +:107BE00005C0662371F096E8862F70E060E02AF009 +:107BF0009A95660F771F881FDAF7880F96958795F5 +:107C000097F90895E894F92F96EBFF2381F0121667 +:107C100013061406440B9395F6958795779567950B +:107C200057954040FF23B9F71BC099270895882333 +:107C300051F49850D2F7872B762F652F542F432F6E +:107C4000322F20E0B1F3121613061406440B8823DA +:107C50003AF09A95440F551F661F771F881FCAF781 +:107C600055234AF4440F551F11F460FF04C06F5FA1 +:107C70007F4F8F4F9F4F880F9695879597F908955F +:107C800097F99F6780E870E060E008959FEF80ECCF +:107C90000895909580957095609550954095309594 +:107CA00021953F4F4F4F5F4F6F4F7F4F8F4F9F4FEC +:107CB000089500240A941616170618060906089552 +:107CC00000240A9412161306140605060895092EB8 +:107CD0000394000C11F4882352F0BB0F40F4BF2B27 +:107CE00011F460FF04C06F5F7F4F8F4F9F4F089567 +:107CF00057FD9058440F551F59F05F3F71F047955D +:107D0000880F97FB991F61F09F3F79F08795089541 +:107D1000121613061406551FF2CF4695F1DF08C060 +:107D2000161617061806991FF1CF8695710561057D +:107D300008940895E894BB2766277727CB0197F925 +:107D400008950E94B43E0C94673E0E94593E38F05C +:107D50000E94603E20F0952311F00C94403E0C945C +:107D6000463E11240C949B3E0E94783E70F3959FF2 +:107D7000C1F3950F50E0551F629FF001729FBB2722 +:107D8000F00DB11D639FAA27F00DB11DAA1F649FBE +:107D90006627B00DA11D661F829F2227B00DA11D71 +:107DA000621F739FB00DA11D621F839FA00D611DF7 +:107DB000221F749F3327A00D611D231F849F600D18 +:107DC000211D822F762F6A2F11249F5750409AF041 +:107DD000F1F088234AF0EE0FFF1FBB1F661F771FCD +:107DE000881F91505040A9F79E3F510580F00C9498 +:107DF000403E0C949B3E5F3FE4F3983ED4F386955F +:107E000077956795B795F795E7959F5FC1F7FE2B37 +:107E1000880F911D9695879597F90895FA01EE0FB1 +:107E2000FF1F309621053105A1F16115710561F43F +:107E30008038BFE39B0749F168949038810561F071 +:107E40008038BFEF9B0741F099234AF5FF3FE105DA +:107E50003105210519F1E8940894E795D901AA2381 +:107E600029F4AB2FBE2FF85FD0F310C0FF5F70F482 +:107E7000A695E0F7F73950F019F0FF3A38F49F77FC +:107E80009F930DD00F9007FC9058089546F00C94E6 +:107E9000463E60E070E080E89FE308954FE79F77FB +:107EA0005F934F933F932F930E9432402F913F91C6 +:107EB0004F915F910E94A13E0C946B3F0E949D3FA9 +:107EC000880B990B089529F416F00C94403E0C94FD +:107ED0009A3E0C94463E0E94803EA8F39638A0F746 +:107EE00007F80F92E8942BE33AEA48EB5FE70E9429 +:107EF000B73E0F920F920F924DB75EB70F920E944E +:107F00007A40ECE8F0E00E94C13F4F915F91EF9121 +:107F1000FF91E595EE1FFF1F49F0FE57E0684427EB +:107F2000EE0F441FFA95E1F74195550B0E94F43F7F +:107F30000F9007FE0C94E83F0895990F0008550F25 +:107F4000AA0BE0E8FEEF16161706E807F907C0F0DF +:107F500012161306E407F50798F0621B730B840BE7 +:107F6000950B39F40A2661F0232B242B252B21F4C1 +:107F700008950A2609F4A140A6958FEF811D811D61 +:107F80000895DF93CF931F930F93FF92EF92DF92A9 +:107F90007B018C01689406C0DA2EEF010E94B43E8A +:107FA000FE01E894A5912591359145915591A6F34F +:107FB000EF010E94C23CFE019701A801DA9469F723 +:107FC000DF90EF90FF900F911F91CF91DF91089577 +:107FD0009B01AC0160E070E080E89FE30C94173DEA +:107FE0000C94403E0C94AE400E94803ED8F39923FE +:107FF000C9F3940F511DA3F39150504094F059F0E0 +:10800000882332F0660F771F881F91505040C1F7C8 +:108010009E3F51052CF7880F911D9695879597F9EE +:1080200008955F3FACF0983E9CF0BB27869577950E +:108030006795B79508F4B1609395C1F7BB0F58F7F2 +:1080400011F460FFE8CF6F5F7F4F8F4F9F4FE3CFFB +:108050000C949B3E16F00C94AE400C94463E6894F3 +:108060000C94403E0E94803EA8F39923C1F3AEF3E6 +:10807000DF93CF931F930F93FF92C92FDD278823A0 +:108080002AF02197660F771F881FDAF720E030E08B +:1080900040E85FEB9FE3883920F0803E38F021967E +:1080A0008F770E94AB3CE4EBF0E004C00E94AB3C55 +:1080B000E1EEF0E00E94C13F8B01BE01EC01FB2E1E +:1080C0006F5771097595771F880B990B0E94C73DF3 +:1080D00028E132E741E35FE30E94B43EAF2D98010F +:1080E000AE01FF900F911F91CF91DF910E94C23C92 +:1080F0000C94673EFA01DC01AA0FBB1F9B01AC0187 +:10810000BF5728F4222733274427507820C0B7517F +:1081100090F4AB2F0024469537952795011CA39525 +:10812000D2F3002071F0220F331F441FB395DAF30E +:108130000ED00C94AA3C61307105A0E88A07B946BC +:1081400030F49B01AC01662777278827907830961A +:1081500021F0208331834283538308959F3F31F080 +:10816000915020F4879577956795B795880F911D65 +:108170009695879597F90895FB01DC0102C005905B +:108180000D9241505040D8F70895FB01DC01215079 +:10819000304030F001900D920416C9F7CD010895DA +:1081A000882799270895FB01DC014150504048F091 +:1081B00001900D920020C9F701C01D92415050401E +:1081C000E0F70895CF92DF92EF92FF920F931F9303 +:1081D000CF93DF93FA01238120FD03C080E090E07C +:1081E0001AC016161706D4F77A018C01EB016C0140 +:1081F000C130D10569F0C7010E94CF468F3FFFEF24 +:108200009F0761F3F60181936F0121970A9781F728 +:10821000F6011082C801DF91CF911F910F91FF905D +:10822000EF90DF90CF9008950F931F93CF93DF933C +:10823000CDB7DEB70F811885F8018381886083830D +:10824000AE01455F5F4F69857A85C8010E94B741DD +:10825000F8012381277F2383DF91CF911F910F9115 +:1082600008950F931F93CF93DF93FB01238121FD8B +:1082700003C08FEF9FEF2CC022FF16C046815781AD +:10828000248135814217530744F4A081B1819D01B7 +:108290002F5F3F4F318320838C93268137812F5F5F +:1082A0003F4F3783268314C08B01EC01FB01008410 +:1082B000F185E02D0995892BE1F6D80116968D916F +:1082C0009C911797019617969C938E931697CE01C3 +:1082D000DF91CF911F910F9108950F931F93CF932B +:1082E000DF93CDB7DEB7AE01495F5F4FDA016D9125 +:1082F0007D91AD0100EE14E0F80182819381DC01F3 +:1083000013962C911397286013962C930E94B741D3 +:10831000D8011296ED91FC9113972381277F238337 +:10832000DF91CF911F910F910895CF93DF93CDB738 +:10833000DEB72E970FB6F894DEBF0FBECDBF85E037 +:108340008C838B899C899A838983AE01495E5F4FB8 +:108350006D897E89CE0101960E9480452E960FB6CA +:10836000F894DEBF0FBECDBFDF91CF9108952F925D +:108370003F924F925F926F927F928F929F92AF92B5 +:10838000BF92CF92DF92EF92FF920F931F93CF9302 +:10839000DF93CDB7DEB72B970FB6F894DEBF0FBED5 +:1083A000CDBF6C017B018A01FC011782168283819B +:1083B00081FFCCC1CE0101963C01F6019381F7010A +:1083C00093FD859193FF81917F01882309F4BAC1C0 +:1083D000853239F493FD859193FF81917F01853238 +:1083E00029F4B60190E00E943141E7CF912C212C75 +:1083F000312CFFE1F315D8F08B3279F038F480326C +:1084000079F08332A1F4232D20611DC08D3261F0FB +:10841000803369F4232D216016C0832D8260382EAD +:10842000E32DE4603E2E2AC0F32DF8601DC037FC1A +:108430002DC020ED280F2A3040F08E32B9F436FCE2 +:1084400081C1232D2064322E19C036FE06C08AE079 +:10845000989E200D1124922E11C0EAE02E9E200D30 +:108460001124222EF32DF0623F2E08C08C3621F409 +:10847000832D8068382E02C0883641F4F70193FDC1 +:10848000859193FF81917F018111B3CF982F9F7DBB +:108490009554933028F40C5F1F4F9FE399830DC0D0 +:1084A000833631F0833771F0833509F059C021C02C +:1084B000F801808189830E5F1F4F88248394912C5B +:1084C000530113C02801F2E04F0E511CF801A080A7 +:1084D000B18036FE03C0692D70E002C06FEF7FEF00 +:1084E000C5010E94C4464C018201F32DFF773F2E47 +:1084F00016C0280122E0420E511CF801A080B18074 +:1085000036FE03C0692D70E002C06FEF7FEFC5013A +:108510000E94B9464C01F32DF0683F2E820133FCD6 +:108520001BC0822D90E088169906B0F4B60180E257 +:1085300090E00E9431412A94F4CFF50137FC8591F7 +:1085400037FE81915F01B60190E00E943141211018 +:108550002A9421E0821A91088114910471F7E8C0ED +:10856000843611F0893641F5F80137FE07C0608185 +:108570007181828193810C5F1F4F08C0608171817E +:10858000072E000C880B990B0E5F1F4FF32DFF7603 +:108590003F2E97FF09C090958095709561957F4F0C +:1085A0008F4F9F4FF0683F2E2AE030E0A3010E94DA +:1085B0002647882E861845C0853731F4232D2F7E17 +:1085C000B22E2AE030E025C0932D997FB92E8F3648 +:1085D000C1F018F4883579F0B5C0803719F08837C4 +:1085E00021F0B0C0E92FE061BE2EB4FE0DC0FB2D1E +:1085F000F460BF2E09C034FE0AC0292F2660B22EB7 +:1086000006C028E030E005C020E130E002C020E1F3 +:1086100032E0F801B7FE07C06081718182819381E9 +:108620000C5F1F4F06C06081718180E090E00E5F9B +:108630001F4FA3010E942647882E8618FB2DFF7727 +:108640003F2E36FE0DC0232D2E7FA22E891458F406 +:1086500034FE0BC032FC09C0832D8E7EA82E05C0CF +:10866000B82CA32C03C0B82C01C0B92CA4FE0FC099 +:10867000FE01E80DF11D8081803321F49A2D997E51 +:10868000A92E09C0A2FE06C0B394B39404C08A2DDB +:10869000867809F0B394A3FC11C0A0FE06C0B21402 +:1086A00088F4280C922C9B180EC0B21460F4B6010A +:1086B00080E290E00E943141B394F7CFB21418F4F5 +:1086C0002B1802C0982C212CA4FE10C0B60180E308 +:1086D00090E00E943141A2FE17C0A1FC03C088E7D0 +:1086E00090E002C088E590E0B6010CC08A2D867843 +:1086F00059F0A1FE02C08BE201C080E2A7FC8DE22E +:10870000B60190E00E943141891438F4B60180E34B +:1087100090E00E9431419A94F7CF8A94F301E80DDA +:10872000F11D8081B60190E00E9431418110F5CFAA +:10873000222009F442CEB60180E290E00E9431414D +:108740002A94F6CFF6018681978102C08FEF9FEFC2 +:108750002B960FB6F894DEBF0FBECDBFDF91CF9141 +:108760001F910F91FF90EF90DF90CF90BF90AF904F +:108770009F908F907F906F905F904F903F902F9041 +:10878000089520FD09C0FC0123FD05C022FF02C0A1 +:108790007383628351834083089544FD17C046FD6F +:1087A00017C0AB01BC01DA01FB01AA0FBB1FEE1F12 +:1087B000FF1F1094D1F74A0F5B1F6E1F7F1FCB0165 +:1087C000BA01660F771F881F991F09C033E001C0E7 +:1087D00034E0660F771F881F991F3150D1F7620F61 +:1087E000711D811D911D08950F931F93CF93DF93EA +:1087F0008C01C8010E94CF46EC0197FD08C00E9481 +:10880000A546892BB1F7B801CE010E940D47CE01D4 +:10881000DF91CF911F910F9108958F929F92AF9208 +:10882000BF92EF92FF920F931F93CF93DF938C0130 +:10883000D62F7A01B22E0E94CF469C0133272B32CD +:10884000310531F02D32310561F48B2D8068B82E61 +:10885000D15011F480E068C0C8010E94CF4697FD56 +:10886000F9CFCB2DCD7F2B2D207309F58033F9F473 +:10887000AA24AA94AD0E09F443C0C8010E94CF46B1 +:1088800097FD3EC09C012F7D33272835310549F4E3 +:10889000C264D250A9F1C8010E94CF4697FF07C019 +:1088A0002FC0B6FE02C0C26001C0C261DA2D812CA9 +:1088B000912C540120ED280F283080F0C4FF04C013 +:1088C000B8010E940D4719C02A3040F0C6FFF8CF0A +:1088D0002F7D3FEE320F363098F727504C2FC501D1 +:1088E000B4010E94CD434B015C01C260D15059F0EC +:1088F000C8010E94CF4697FFDDCFC1FD04C0AACFBB +:10890000812C912C5401C7FF08C0B094A09490947E +:108910008094811C911CA11CB11C2C2FB501A401B9 +:10892000C7010E94C14381E0DF91CF911F910F9158 +:10893000FF90EF90BF90AF909F908F9008955F92BF +:108940006F927F928F929F92AF92BF92CF92DF925F +:10895000EF92FF920F931F93CF93DF93CDB7DEB7C4 +:10896000A0970FB6F894DEBF0FBECDBF5C01962E68 +:108970007A01F9018E010F5F1F4F680180E2D80173 +:108980001D928A95E9F7D50113968C9080E090E0CE +:10899000612C712C30E061E070E083FC259183FE56 +:1089A00021918F01522E211103C080E090E092C0EE +:1089B0002E3511F4009751F1432F50E04817590715 +:1089C0003CF42D3559F12D3219F4772009F103C00B +:1089D000772009F46AC0452D469546954695D601FF +:1089E000A40FB11D452D47708B0102C0000F111F50 +:1089F0004A95E2F7A8015C91452B4C93651459F018 +:108A0000561410F45394E7CF5A94E5CF31E004C0E4 +:108A10007724739401C0712C0196BFCF772019F091 +:108A20008E8180628E83311103C08824839417C0A5 +:108A3000F6019E012F5D3F4F8081809581932E1717 +:108A40003F07D1F7F2CFE114F10429F0D7018C935D +:108A5000F70131967F019A94812C9920F9F0C50194 +:108A60000E94CF4697FD18C0FC01FF2723E0F59533 +:108A7000E7952A95E1F7EC0DFD1D208130E0AC0172 +:108A80004770552702C0359527954A95E2F720FD96 +:108A9000DACFB5010E940D47811087CFE114F104B0 +:108AA00011F0D7011C92C80115C0422F469546957A +:108AB0004695D601A40FB11D422F47708B0102C00D +:108AC000000F111F4A95E2F7A8015C91452B4C93CA +:108AD000622EA2CFA0960FB6F894DEBF0FBECDBF18 +:108AE000DF91CF911F910F91FF90EF90DF90CF908A +:108AF000BF90AF909F908F907F906F905F90089500 +:108B00005F926F927F928F929F92AF92BF92CF921D +:108B1000DF92EF92FF920F931F93CF93DF936C013D +:108B2000EB015A01FC0117821682512CF601E380F9 +:108B3000FE01E3FC8591E3FE8191182FEF0188236C +:108B400009F4EEC090E00E94A546892B21F0C601F1 +:108B50000E94F443EBCF153241F4FE01E3FC159182 +:108B6000E3FE1191EF01153281F4C6010E94CF4658 +:108B700097FDD4C0412F50E09C01332724173507BF +:108B8000A9F2B6010E940D47CBC01A3239F4E3FCBA +:108B90001591E3FE1191EF0101E001C000E0F12C1D +:108BA00020ED210F2A3080F402606F2D70E080E00C +:108BB00090E040E20E94CD43F62EFE01E3FC1591C9 +:108BC000E3FE1191EF01ECCF01FF03C0F11003C0F0 +:108BD000A7C0FF24FA94183619F01C3651F010C0C3 +:108BE000FE01E3FC1591E3FE1191EF01183641F40B +:108BF00008600460FE01E3FC1591E3FE1191EF01B2 +:108C0000112309F48DC0612F70E08EE091E00E9485 +:108C1000AE46892B09F484C000FD07C0F5018080B1 +:108C20009180C50102965C0102C0812C912C1E36F8 +:108C300051F4F6014681578160E070E0202FC401B5 +:108C40000E94C14373CF1336A9F401FD02C0FF2473 +:108C5000F394C6010E94CF4697FD60C08114910431 +:108C600029F0F4018083C40101964C01FA94F110BB +:108C7000F0CF50C01B3559F49E01A4016F2DC601E1 +:108C80000E949F44EC01892B09F044C03EC0C601FC +:108C90000E94F44397FD42C01F3661F128F4143658 +:108CA00039F1193651F128C0133771F0153701F138 +:108CB00023C08114910429F0F4016082C40101965B +:108CC0004C01FA94FF2071F0C6010E94CF463C018E +:108CD00097FD08C00E94A546892B59F3B601C30130 +:108CE0000E940D4781149104A9F0F401108212C072 +:108CF000006203C0006101C00064202FA4016F2D39 +:108D0000C6010E940D44811105C0F6018381807364 +:108D100029F406C000FD0ACF539408CF552019F05E +:108D2000852D90E002C08FEF9FEFDF91CF911F91D3 +:108D30000F91FF90EF90DF90CF90BF90AF909F90FA +:108D40008F907F906F905F90089591110C9484475D +:108D5000803219F089508550C8F70895FC010590BC +:108D6000061621F00020D9F7C00108953197CF01F0 +:108D70000895FC010590615070400110D8F780956E +:108D800090958E0F9F1F0895FC01615070400190D7 +:108D90000110D8F7809590958E0F9F1F0895CF935F +:108DA000DF93EC012B8120FF33C026FF0AC02F7B0D +:108DB0002B838E819F8101969F838E838A8190E091 +:108DC00029C022FF0FC0E881F9818081082E000CA4 +:108DD000990B009719F420622B831AC03196F983FE +:108DE000E8830EC0EA85FB85099597FF09C02B81B2 +:108DF000019611F080E201C080E1822B8B8308C0D4 +:108E00002E813F812F5F3F4F3F832E83992702C0E2 +:108E10008FEF9FEFDF91CF910895FB01238120FF1A +:108E200012C026FD10C08F3F3FEF930761F0828391 +:108E30002F7D206423832681378121503109378398 +:108E40002683992708958FEF9FEF0895FA01AA27A7 +:108E5000283051F1203181F1E8946F936E7F6E5F7D +:108E60007F4F8F4F9F4FAF4FB1E03ED0B4E03CD02B +:108E7000670F781F891F9A1FA11D680F791F8A1F0E +:108E8000911DA11D6A0F711D811D911DA11D20D075 +:108E900009F468943F912AE0269F11243019305D2F +:108EA0003193DEF6CF010895462F4770405D419320 +:108EB000B3E00FD0C9F7F6CF462F4F70405D4A336D +:108EC00018F0495D31FD4052419302D0A9F7EACF35 +:108ED000B4E0A6959795879577956795BA95C9F764 +:108EE00000976105710508959B01AC010A2E069457 +:108EF0005795479537952795BA95C9F7620F731F10 +:108F0000841F951FA01D0895992788270895F89418 +:028F1000FFCF91 +:108F1200FFFF0000000100000000000048090000FF +:108F220000000002000000006909000000000303C5 +:108F32002C022E02300232023402360238023A0287 +:108F420000000002000000005A37000000005A042E +:108F520058045604530451044D044B04460444047B +:108F620040043D04290424040203710293036A02AB +:108F7200600256021C0439042904D707CC07C20731 +:108F820001040000000271CB257800424D453238C1 +:108F92003000000000006B20BB21C619B51900008B +:108FA20000002A2217222122483A3F000000000036 +:108FB200F322CE22E522BD22000000004B26152618 +:108FC20033264B3A00000000CF2809287F284E3A6A +:108FD20000000000A2294C295329513A0000000048 +:108FE200FA29E529E629543A00000000CE2BB42BD9 +:108FF2009B2B573A00000000D22D422D522D5A3A97 +:1090020000000000E02ED42EDB2E5D3A00000000AE +:10901200342F282F2F2F603A000000003230043006 +:109022001B30633A00000000BD32A730B830C030B8 +:10903200000000002536CF35F135663A4100420086 +:109042004300440045004600470044500000000031 +:1090520000F736C936D036693A0000000095376B02 +:069062003784376C3A0070 +:00000001FF diff --git a/software/test-software/nano-1284/src b/software/test-software/nano-1284/src new file mode 120000 index 0000000..5cd551c --- /dev/null +++ b/software/test-software/nano-1284/src @@ -0,0 +1 @@ +../src \ No newline at end of file diff --git a/software/test-software/nano-328/Makefile b/software/test-software/nano-328/Makefile new file mode 100644 index 0000000..be62fec --- /dev/null +++ b/software/test-software/nano-328/Makefile @@ -0,0 +1,262 @@ +$(shell mkdir -p dist >/dev/null) +$(shell mkdir -p build >/dev/null) +$(shell mkdir -p sim >/dev/null) +$(shell mkdir -p sim/build >/dev/null) +$(shell mkdir -p release/sim >/dev/null) + +# -------------------------------------------------------------------------------- +# Variables configured by engineer + +NAME=nano-x-base_test-software_nano-m328p_16mhz +DEVICE=atmega328p +AVRDUDE_DEVICE=m328p +CPU_FREQUENCY=16000000 +BAUDRATE=38400 +START_ADDRESS=0 + +# -------------------------------------------------------------------------------- +# Automatic created Makefile variables + +SRC= $(wildcard src/*.c src/*.cpp src/*/*.c src/*/*.cpp) +HDR= $(wildcard src/*.h src/*.hpp src/*/*.h src/*/*.hpp) +MAINSRC= $(wildcard src/main.c src/main.cpp) +OBJ_CPP = $(SRC:src/%.cpp=build/%.o) +OBJ = $(OBJ_CPP:src/%.c=build/%.o) +OBJ_SIM_CPP = $(SRC:src/%.cpp=sim/build/%.o) +OBJ_SIM = $(OBJ_SIM_CPP:src/%.c=sim/build/%.o) + +CC= avr-g++ +CFLAGS= -Wall -mmcu=$(DEVICE) -Os -DF_CPU=$(CPU_FREQUENCY) -DBAUD_RATE=$(BAUDRATE) -DDOUBLE_SPEED -DNUM_LED_FLASHES=4 '-DMAX_TIME_COUNT=F_CPU>>4' -c +#LFLAGS= -Wall -mmcu=$(DEVICE) -Os -DF_CPU=$(CPU_FREQUENCY) -Wl,-u,vfprintf -lprintf_flt -lm +LFLAGS= -Wall -mmcu=$(DEVICE) -Os -DF_CPU=$(CPU_FREQUENCY) -Wl,--section-start=.text=$(START_ADDRESS) + +CFLAGS_SIM= -Wall -mmcu=$(DEVICE) -Og -DF_CPU=$(CPU_FREQUENCY) -g -DBAUD_RATE=$(BAUDRATE) -DDOUBLE_SPEED -DNUM_LED_FLASHES=4 '-DMAX_TIME_COUNT=F_CPU>>4' -c +#LFLAGS_SIM= -Wall -mmcu=$(DEVICE) -Og -DF_CPU=$(CPU_FREQUENCY) -g -Wl,-u,vfprintf -lprintf_flt -lm +LFLAGS_SIM= -Wall -mmcu=$(DEVICE) -Og -DF_CPU=$(CPU_FREQUENCY) -g -Wl,--section-start=.text=$(START_ADDRESS) + +# -------------------------------------------------------------------------------- +# make targets + +.PHONY: all +all: dist/$(NAME).elf sim/$(NAME).elf dist/$(NAME).s dist/$(NAME).hex dist/$(NAME).bin sim/$(NAME).s info + +.PHONY: info +info: + @echo + @avr-size --mcu=$(DEVICE) --format=avr dist/$(NAME).elf + +# -------------------------------------------------------------------------------- +# dependency make for hierarchical source file structure + +.depend: $(SRC) $(HDR) + $(CC) -mmcu=$(DEVICE) -MM $(SRC) | sed --regexp-extended 's/^(.*\.o)\: src\/(.*)(\.cpp|\.c) (.*)/build\/\2\.o\: src\/\2\3 \4/g' > .depend + +ifneq (clean,$(filter clean,$(MAKECMDGOALS))) +-include .depend +endif + +# -------------------------------------------------------------------------------- +# elf, hex and assembler file creation + +dist/$(NAME).elf: .depend $(OBJ) + $(CC) $(LFLAGS) -o $@ $(OBJ) + +dist/%.s: dist/%.elf + avr-objdump -d $< > $@ + +dist/%.hex: dist/%.elf + avr-objcopy -O ihex $(HEX_FLASH_FLAGS) $< $@ + +dist/%.bin: dist/%.elf + avr-objcopy -O binary $(HEX_FLASH_FLAGS) $< $@ + +# -------------------------------------------------------------------------------- +# check if the macros __DATE__ or __TIME__ are used in src/main.cpp or src/main.c + +DATE_USED= +ifneq ($(shell cat $(MAINSRC) | grep __DATE__),) + DATE_USED=true +endif +TIME_USED= +ifneq ($(shell cat $(MAINSRC) | grep __TIME__),) + TIME_USED=true +endif + +ifeq (true, $(filter true, $(DATE_USED) $(TIME_USED))) +build/main.o: $(MAIN_SRC) $(SRC) $(HDR) + @mkdir -p $(dir $@) + $(CC) $(CFLAGS) -o $@ $< +endif + +# -------------------------------------------------------------------------------- + +build/%.o: src/%.c + @mkdir -p $(dir $@) + $(CC) $(CFLAGS) -o $@ $< + +build/%.o: src/%.cpp + @mkdir -p $(dir $@) + $(CC) $(CFLAGS) -o $@ $< + +# -------------------------------------------------------------------------------- +# simulation/debugging with gdb or simuc + +sim/$(NAME).elf: .depend $(OBJ_SIM) + $(CC) $(LFLAGS_SIM) -o $@ $(OBJ_SIM) + @ln -sf $(NAME).elf sim/$(DEVICE).elf + +sim/build/%.o: src/%.c + @mkdir -p $(dir $@) + $(CC) $(CFLAGS_SIM) -o $@ $< + +sim/build/%.o: src/%.cpp + @mkdir -p $(dir $@) + $(CC) $(CFLAGS_SIM) -o $@ $< + +sim/%.s: sim/%.elf + avr-objdump -d $< > $@ + +ifeq (m16, $(AVRDUDE_DEVICE)) +simuc: sim/$(NAME).elf + simuc --board sure $< +endif + +ifeq (m328p, $(AVRDUDE_DEVICE)) +simuc: sim/$(NAME).elf + simuc --board arduino $< +endif + +ifeq (m644p, $(AVRDUDE_DEVICE)) +simuc: sim/$(NAME).elf + simuc --board nano-644 $< +endif + +ifeq (m1284p, $(AVRDUDE_DEVICE)) +simuc: sim/$(NAME).elf + simuc --board nano-1284 $< +endif + +gdb: sim/$(NAME).elf + avr-gdb $< + +# ------------------------------------------------------------- +# flash to target with arduino bootloader in bootloader-section + +.PHONY: flash +flash: dist/$(NAME).elf all + avrdude -c arduino -P /dev/ttyUSB0 -b $(BAUDRATE) -p $(AVRDUDE_DEVICE) -e -U flash:w:$< + +.PHONY: flash0 +flash0: dist/$(NAME).elf all + avrdude -c arduino -P /dev/ttyUSB0 -b $(BAUDRATE) -p $(AVRDUDE_DEVICE) -e -U flash:w:$< + +.PHONY: flash1 +flash1: dist/$(NAME).elf all + avrdude -c arduino -P /dev/ttyUSB1 -b $(BAUDRATE) -p $(AVRDUDE_DEVICE) -e -U flash:w:$< + +.PHONY: flash2 +flash2: dist/$(NAME).elf all + avrdude -c arduino -P /dev/ttyUSB2 -b $(BAUDRATE) -p $(AVRDUDE_DEVICE) -e -U flash:w:$< + +.PHONY: flash-read +flash-read: + avrdude -c arduino -P /dev/ttyUSB0 -b $(BAUDRATE) -p $(AVRDUDE_DEVICE) -U flash:r:/tmp/flash.bin + +.PHONY: flash-disassemble +flash-disassemble: flash-read + avr-objdump -b binary -D -m avr5 /tmp/flash.bin > /tmp/flash.s + less /tmp/flash.s + +.PHONY: flash-hexdump +flash-hexdump: flash-read + hexdump -C /tmp/flash.bin | less + +# ---------------------------------------------- +# flash to target with fischl programming device + +.PHONY: isp-flash-$(AVRDUDE_DEVICE) +isp-$(AVRDUDE_DEVICE): + avrdude -c usbasp -p $(AVRDUDE_DEVICE) -U lock:r:-:h + avrdude -c usbasp -p $(AVRDUDE_DEVICE) + +.PHONY: isp-flash +isp-flash: dist/$(NAME).elf all + avrdude -c usbasp -p $(AVRDUDE_DEVICE) -e -U flash:w:$< + +.PHONY: isp-flash-$(AVRDUDE_DEVICE) +isp-flash-$(AVRDUDE_DEVICE): dist/$(NAME).elf all + avrdude -c usbasp -p $(AVRDUDE_DEVICE) -e -U flash:w:$< + +.PHONY: isp-read-flash-$(AVRDUDE_DEVICE) +isp-read-flash-$(AVRDUDE_DEVICE): + avrdude -c usbasp -p m32$(AVRDUDE_DEVICE)8p -U flash:r:/tmp/flash-arduino-atmega328p__$(shell date +"%Y-%m-%d_%H%M%S") + +.PHONY: isp-fuse +isp-fuse: isp-fuse-$(AVRDUDE_DEVICE) + +.PHONY: isp-fuse-$(AVRDUDE_DEVICE) +ifeq (m16, $(AVRDUDE_DEVICE)) +isp-fuse-$(AVRDUDE_DEVICE): + avrdude -c usbasp -p $(AVRDUDE_DEVICE) -U lfuse:w:0x18:m -U hfuse:w:0xD8:m -U lock:w:0xEF:m +endif +ifeq (m328p, $(AVRDUDE_DEVICE)) +isp-fuse-$(AVRDUDE_DEVICE): + avrdude -c usbasp -p $(AVRDUDE_DEVICE) -U lfuse:w:0xEF:m -U hfuse:w:0xD8:m -U efuse:w:0xFD:m -U lock:w:0xEF:m +endif +ifeq (m644p, $(AVRDUDE_DEVICE)) +isp-fuse-$(AVRDUDE_DEVICE): + avrdude -c usbasp -p $(AVRDUDE_DEVICE) -U lfuse:w:0xEF:m -U hfuse:w:0xD8:m -U efuse:w:0xFD:m -U lock:w:0xEF:m +endif +ifeq (m1284p, $(AVRDUDE_DEVICE)) +isp-fuse-$(AVRDUDE_DEVICE): + avrdude -c usbasp -p $(AVRDUDE_DEVICE) -U lfuse:w:0xEF:m -U hfuse:w:0xD8:m -U efuse:w:0xFD:m -U lock:w:0xEF:m +endif + +# -------------------------------------------------------- +# picocom sends CR for ENTER -> convert cr (\r) to lf (\n) + +.PHONY: picocom +picocom: + picocom -b $(BAUDRATE) --omap crlf --raise-dtr /dev/ttyUSB0 + +.PHONY: picocom0 +picocom0: + picocom -b $(BAUDRATE) --omap crlf --raise-dtr /dev/ttyUSB0 + +.PHONY: picocom1 +picocom1: + picocom -b $(BAUDRATE) --omap crlf --raise-dtr /dev/ttyUSB1 + +.PHONY: picocom2 +picocom2: + picocom -b $(BAUDRATE) --omap crlf --raise-dtr /dev/ttyUSB2 + +# -------------------------------------------------------- + +.PHONY: help +help: + @echo + @echo "Possible targets are:" + @echo " clean" + @echo " all help info" + @echo " flash flash0 flash1 flash2 flash-read flash-disassemble flash-hexdump" + @echo " isp-$(AVRDUDE_DEVICE) isp-flash-$(AVRDUDE_DEVICE) isp-fuse-$(AVRDUDE_DEVICE)" + @echo " picocom picocom0 picocom1 picocom2" + @echo " gdb simuc" + @echo + +# -------------------------------------------------------- + +.PHONY: release +release: dist/$(NAME).elf sim/$(NAME).elf dist/$(NAME).hex dist/$(NAME).bin + ../create-release release $(word 1, $^) release/sim $(word 2, $^) + +# -------------------------------------------------------- + +.PHONY: clean +clean: + @rm -r dist + @rm -r build + @rm -r sim + @find . -type f -name ".depend" -exec rm {} \; + @echo "clean done" diff --git a/software/test-software/nano-328/release/v2024-10-31_172629/nano-x-base_test-software_nano-m328p_16mhz.bin b/software/test-software/nano-328/release/v2024-10-31_172629/nano-x-base_test-software_nano-m328p_16mhz.bin new file mode 100755 index 0000000..30364ad Binary files /dev/null and b/software/test-software/nano-328/release/v2024-10-31_172629/nano-x-base_test-software_nano-m328p_16mhz.bin differ diff --git a/software/test-software/nano-328/release/v2024-10-31_172629/nano-x-base_test-software_nano-m328p_16mhz.elf b/software/test-software/nano-328/release/v2024-10-31_172629/nano-x-base_test-software_nano-m328p_16mhz.elf new file mode 100755 index 0000000..c95f711 Binary files /dev/null and b/software/test-software/nano-328/release/v2024-10-31_172629/nano-x-base_test-software_nano-m328p_16mhz.elf differ diff --git a/software/test-software/nano-328/release/v2024-10-31_172629/nano-x-base_test-software_nano-m328p_16mhz.hex b/software/test-software/nano-328/release/v2024-10-31_172629/nano-x-base_test-software_nano-m328p_16mhz.hex new file mode 100644 index 0000000..3cb471f --- /dev/null +++ b/software/test-software/nano-328/release/v2024-10-31_172629/nano-x-base_test-software_nano-m328p_16mhz.hex @@ -0,0 +1,1667 @@ +:100000000C9448030C9470030C9470030C947003CC +:100010000C9470030C9470030C9470030C94FC0605 +:100020000C9470030C9470030C9470030C94700384 +:100030000C9470030C9470030C9470030C94700374 +:100040000C9470030C9470030C948D060C94700344 +:100050000C9470030C9470030C9470030C94700354 +:100060000C94C0060C94700307634236B79BD8A764 +:100070001A39685618AEBAAB558C1D3CB7CC5763CD +:10008000BD6DEDFD753EF6177231BF000000803F7B +:1000900008000000BE922449123EABAAAA2ABECD97 +:1000A000CCCC4C3E00000080BEABAAAAAA3E000009 +:1000B0000000BF000000803F000000000008417801 +:1000C000D3BB4387D1133D190E3CC3BD4282AD2B38 +:1000D0003E68EC8276BED98FE1A93E4C80EFFFBE30 +:1000E00001C4FF7F3F00000000006364696E6F7011 +:1000F000737578585B000A2534643A20005D3A2015 +:10010000000A0A5B000A53656C65637420756E69AA +:10011000743A2000253378202E2E2E20004552528E +:100120004F523A20496E76616C696420486172646E +:1001300077617265202825642900417661696C61C8 +:10014000626C6520756E6974733A0A0A00486172C0 +:1001500064776172653A20255300202F2000202FFC +:1001600020000A0A48617264776172652025532075 +:100170006465746563746564202841444337483D71 +:1001800030782530325829000A496E76616C6964EE +:100190002048617264776172652D56657273696F6C +:1001A0006E3A204144433748203D202564202841B1 +:1001B000546D656761333238502C203556290A005A +:1001C000563F3F005632610056316100446F6E6504 +:1001D000004552524F52000A000A3D3D3D3D3D3D13 +:1001E0003D3D3D3D3D3D3D3D3D3D3D3D3D3D3D3D3F +:1001F0003D3D3D3D3D3D3D3D3D3D3D3D3D3D3D0A62 +:10020000200041546D656761333238500031373A10 +:1002100032363A3239004F63742033312032303273 +:1002200034003F0025356420283078253032782985 +:1002300020000D20203D3E20456E636F64657220D6 +:10024000287075736820746F20636C656172293A39 +:100250002000456E636F64657200656E64000A205D +:1002600049324320534C4156453A2066726F6D2007 +:100270006D61737465723A20307825303278202DA4 +:100280003E20746F206D61737465723A203078255A +:1002900030327800453100202D3E204552524F52D9 +:1002A00000307825303278002C202066726F6D2067 +:1002B000736C6176653A2000202D3E204552524FE6 +:1002C00052000A204932432D4D41535445523A20A1 +:1002D000746F20736C6176653A20307825303278FF +:1002E00000453100453300290062616400706F6F82 +:1002F00072006661697200676F6F6400657863659C +:100300006C6C656E74003F002C2065636F323D2578 +:10031000642800292C2074766F633D256470706218 +:10032000003F00756E6865616C74687900706F6F6E +:1003300072006D6F64657261746500676F6F640051 +:10034000657863656C6C656E7400206171693D252C +:10035000642800453200252E3166C2B0432F252E79 +:1003600031662525293A20004531290020207C20AE +:10037000454E533136302028002C20483D20252E74 +:1003800032662525002C20543D20252E3266C2B031 +:1003900043000A203D3E20424D3238303A20503D45 +:1003A00020252E3366626172004F4B0045340045B4 +:1003B00033004532004F4B2C20454E533136302010 +:1003C0002E2E2E200045310020424D323830202E76 +:1003D0002E2E20004932432D536C61766500493240 +:1003E000432D4D6173746572004932432D53706122 +:1003F000726B66756E20456E762D436F6D626F0071 +:100400004945454534383500656E64004552524FC4 +:100410005228256429004F4B004C4344200045528C +:10042000524F5220256429004F4B2900696E697490 +:10043000204C43442028004C6364005465737420AE +:100440004C454420442564004C6564004D6F646253 +:1004500075730020206E6F20726F746174696F6E07 +:100460002028543D253034782920200020206E3D5E +:100470002025356420552F6D696E2028543D253088 +:10048000347829002053454E534F523D25642000B7 +:10049000206E4641554C543D256400204144433272 +:1004A0003D25336400202050574D2F4F4330413DB0 +:1004B000253364000D20203D3E20414443303D253E +:1004C000336400454E3D3100454E3D30000D205314 +:1004D00057333D25642D3E000A004D6F746F720046 +:1004E0000A202042616E6B30202D20475042256447 +:1004F000203D2030000A202042616E6B30202D20EC +:100500004750422564203D2031000A202042616E80 +:100510006B30202D204750412564203D2030000ABB +:10052000202042616E6B30202D20475041256420F1 +:100530003D2031000A203D3E207374617274202EEC +:100540002E2E004552524F52202D206E4353206EC6 +:100550006F7420636F6E74726F6C61626C650A00F9 +:100560002900204F4B00204A5033392E322F3320A0 +:100570006A756D706572656420286C656674293FC4 +:1005800000204552524F520020287265616420308D +:100590007825303278202D3E203078253032780092 +:1005A000506F7274457870002534642028307825A7 +:1005B00030337829000D20203D3E204D6561737554 +:1005C000726520414443303A20000A00506F74693C +:1005D000002025332E3166203D3E205357393A36D0 +:1005E000203D2025642025642520642025642020CA +:1005F00000253464202830782530337829000D20F8 +:10060000203D3E204D656173757265204144433243 +:100610003A20000A0052325200416C6C00426C7564 +:100620006500477265656E0052656400526762003E +:100630003F0043686172202564202D202573202D02 +:100640003E2025303278004C312F4C32204F4E0066 +:100650004C312F4C32204F4E004F4646004F4E003B +:10066000536567370052656C656173652053572584 +:1006700064200050726573732053572564005377CC +:100680006974636800556172743100001A26D926B6 +:1006900011241FBECFEFD8E0DEBFCDBF12E0A0E037 +:1006A000B1E0EEEEF6E602C005900D92AE32B10773 +:1006B000D9F724E0AEE2B2E001C01D92AA3BB20736 +:1006C000E1F713E0C8E4D3E004C02197FE010E94E3 +:1006D0002829C634D107C9F70E949B240C9475338E +:1006E0000C940000FC01108211820895FC0191819C +:1006F000992311F0915091830895FC01608384E661 +:100700008093B80084E08093BC0081E0089584E089 +:100710008093BC001092B80008954150FB0194E80A +:1007200024EC4F3FD1F0442319F02093BC0002C0C9 +:100730009093BC008091BC0087FFFCCF8091B900F2 +:10074000887F442319F0803519F009C0883539F4C1 +:100750008091BB0081934150E4CF81E0089580E017 +:100760000895DC01FB0184E835E0442389F022236D +:1007700011F0949101C090819093BB008093BC00D4 +:1007800011963C9311979091BC0097FFFCCF02C04B +:1007900081E008959091B90041503196987F983248 +:1007A00021F380E00895FC0184EA8093BC0085E099 +:1007B00081838091BC0087FFFCCF9091B900987F26 +:1007C000983011F09031B1F49081990F962B90935D +:1007D000BB0084E88093BC0085E081838091BC00ED +:1007E00087FFFCCF9091B900987F611105C081E02F +:1007F000983129F080E0089581E09034D9F7089588 +:100800000F931F93CF93DF93D62F8A01C22F60E0FF +:100810000E94D303811102C080E016C0F80124E8D1 +:10082000D093BB002093BC009091BC0097FFFCCFFD +:100830009091B900987F983279F7D1919FEF9C0FF2 +:10084000CC2311F0C92FECCFDF91CF911F910F91E5 +:10085000089584E98093BC008091BC0084FDFCCFA6 +:1008600081E00895FF920F931F93CF93DF93EC01E4 +:100870008B01F42E61E00E94D303882379F04F2D81 +:10088000B801CE010E948D03882341F0CE01DF9193 +:10089000CF911F910F91FF900C94290480E0DF917C +:1008A000CF911F910F91FF900895FF920F931F9387 +:1008B000CF93DF93EC018B01F42E60E00E94D30311 +:1008C000882381F020E04F2DB801CE010E94B103B2 +:1008D000882341F0CE01DF91CF911F910F91FF90BE +:1008E0000C94290480E0DF91CF911F910F91FF902C +:1008F0000895FF920F931F93CF93DF93EC018B0129 +:10090000F42E60E00E94D303882381F021E04F2D74 +:10091000B801CE010E94B103882341F0CE01DF91DE +:10092000CF911F910F91FF900C94290480E0DF91EB +:10093000CF911F910F91FF900895CF92DF92EF9288 +:10094000FF920F931F93CF93DF93EC016B01142F52 +:10095000790160E00E94D303882301F120E0412F58 +:10096000B601CE010E94B1038823C1F061E0CE013F +:100970000E94D303882391F0402FB701CE010E943B +:100980008D03882359F0CE01DF91CF911F910F91F4 +:10099000FF90EF90DF90CF900C94290480E0DF91DE +:1009A000CF911F910F91FF90EF90DF90CF9008951E +:1009B000FC01108211821282138614860895FC01B4 +:1009C0009081992311F091509083089567FD0CC098 +:1009D000660F642B6093BA0084E68093B80085E4C8 +:1009E0008093BC0081E0089580E0089584E08093C6 +:1009F000BC001092B8000895FB012FB7F8949181C4 +:100A000081E0890F8183DB01A90FB11D12964C9300 +:100A1000883008F0118281819081891305C08F5F31 +:100A20008083883008F010822FBF0895462FBC01C4 +:100A3000655F7F4F0C94FC04FB019FB7F8948081A5 +:100A40002181821304C09FBF8FEF9FEF089521E0A3 +:100A5000280F2083DB01A80FB11D12968C9128303E +:100A600018F49FBF90E008951082FBCFBC016F5F28 +:100A70007F4F0C941C052091B900287F203819F075 +:100A8000283A49F013C04091BB00BC016F5F7F4F13 +:100A90000E94FC0409C0BC01655F7F4F0E941C05D9 +:100AA00097FD80E08093BB0085E801C085EC8093D2 +:100AB000BC000895CF93DF93909135048091340466 +:100AC0009817D1F3E091350481E08E0F80933504BF +:100AD000F0E0EA5CFB4FC081CD3009F4CAE0D0E021 +:100AE0006091B6047091B704CE010E948A2DCE01A8 +:100AF000DF91CF9108950F931F93CF93C82F8B0150 +:100B00008A3019F48DE00E947B058091B6049091A3 +:100B1000B7040817190731F48091C00085FFFCCF96 +:100B2000C093C60080E090E0CF911F910F9108958F +:100B3000089580E090E00895089508950895089537 +:100B400008950895813041F0823019F484EC91E0E9 +:100B5000089580EC91E0089588EC91E00895CF939A +:100B600087E680937C0087E880937A0080917A0002 +:100B7000806480937A0080917A0086FDFCCF109289 +:100B80005E0480917900883D30F480917900803C4A +:100B900010F081E03AC080917900883D20F4809186 +:100BA0007900803B88F580915E049FEF980F92302A +:100BB00078F0809179001F928F9388E891E09F935D +:100BC0008F930E94C62D0F900F900F900F9014C01E +:100BD000C09179000E94A2051F92CF939F938F939B +:100BE00082E691E09F938F930E94C62D0F900F9005 +:100BF0000F900F900F900F9010927C0010927A003F +:100C000080915E04CF91089582E080935E04CBCF03 +:100C1000F8946093620470936304809364049093E7 +:100C20006504789408950E940806F89480916204FF +:100C300090916304A0916404B09165047894892B29 +:100C40008A2B8B2B31F0809100019091010101964C +:100C500061F380910001909101010895CF93DF939A +:100C6000CFEFDFEFD0930101C09300010E94130684 +:100C7000D0930101C0930001DF91CF910895CF93EC +:100C8000DF93CDB7DEB728970FB6F894DEBF0FBE5F +:100C9000CDBF709156046091570450915804409113 +:100CA000590430915A0420915B0490915C04809126 +:100CB0005D0479836A835B834C833D832E839F83AA +:100CC00088878FB7F894E09156047091570460912B +:100CD00058045091590440915A0430915B0420917A +:100CE0005C0490915D04E9837A836B835C834D831C +:100CF0003E832F8398878FBF29813A814B815C8106 +:100D00006D817E818F81988528960FB6F894DEBF1D +:100D10000FBECDBFDF91CF9108951F920F920FB6F6 +:100D20000F9211242F933F938F939F93EF93FF93F1 +:100D30008091C600282F30E03093010120930001FC +:100D4000E091340491E09E0F90933404F0E0EA5C6B +:100D5000FB4F80839091340480913504981305C033 +:100D6000809135048F5F80933504FF91EF919F91BF +:100D70008F913F912F910F900FBE0F901F9018955C +:100D80001F920F920FB60F9211242F933F934F9300 +:100D90005F936F937F938F939F93AF93BF93EF93E3 +:100DA000FF9380916A03882319F08AED92E00DC0C9 +:100DB0008091D902882319F089E492E006C08091DD +:100DC000FB03882329F08BE693E00E94271903C0D8 +:100DD00080E88093BC00FF91EF91BF91AF919F910C +:100DE0008F917F916F915F914F913F912F910F90D4 +:100DF0000FBE0F901F9018951F920F920FB60F9273 +:100E000011242F933F934F935F936F937F938F930F +:100E10009F93AF93BF93EF93FF9380912704882311 +:100E200021F085E294E00E949F15809120048823A0 +:100E300021F08EE194E00E94721E809161048F5F28 +:100E40008A3018F4809361046AC010926104809122 +:100E5000620490916304A0916404B0916504892BAD +:100E60008A2B8B2B99F08091620490916304A0915E +:100E70006404B09165040197A109B10980936204EB +:100E800090936304A0936404B09365042091560486 +:100E900030915704409158045091590460915A047C +:100EA00070915B0480915C0490915D04A1E00E94CC +:100EB000E5282093560430935704409358045093E8 +:100EC000590460935A0470935B0480935C0490937C +:100ED0005D0483E593E00E94760385E593E00E943C +:100EE000DF0482EC92E00E94760384EC92E00E94A0 +:100EF000DF0484EE93E00E94760386EE93E00E9486 +:100F0000DF0480914002882319F0815080934002D1 +:100F100080913602882319F08150809336028091A7 +:100F20005F049091600401969093600480935F0445 +:100F30008838934160F080912D04811104C095B1EF +:100F400080E2892785B91092600410925F04FF91B6 +:100F5000EF91BF91AF919F918F917F916F915F9131 +:100F60004F913F912F910F900FBE0F901F901895AA +:100F7000CF93DF93EC01198218828091A70481112D +:100F80000EC087EA94E00E949905892B41F085EA1A +:100F900094E00E94720387EA94E00E949C05198AFB +:100FA0001A8A1B8A1C8A8AE694E09B838A8388E6D5 +:100FB00094E09D838C8386E694E09F838E8385EA0C +:100FC00094E099838883DF91CF910895CF93DF9345 +:100FD00000D0CDB7DEB74A83FC01808191810097B4 +:100FE00039F0698342E0BE016F5F7F4F0E94550474 +:100FF0000F900F90DF91CF910895CF92EF920F93C2 +:10100000CF93DF93EC016295660F660F607C4770AB +:101010002770822F880F880F880F262F242B282BCC +:101020002FAB0295000F007E88AD8F71082B08AFA3 +:101030008E2D8770880F880F880F9EA9292F207CFE +:101040009C2D9770E22EE82AE92AE894E7F8EEAAA8 +:1010500040E064EFCE010E94E60748AD4295469518 +:10106000477062EFCE010E94E6079EA9492F4770A4 +:1010700060E2469F90011124892F8695869586957A +:10108000877064E0869FA0011124422B532B97FBAD +:10109000992790F9492B65EFCE010E94E6079FA999 +:1010A000492F477080E2489F90011124892F86952F +:1010B00086958695877064E0869FA0011124422B57 +:1010C000532B9295969596959370492B64EFCE018C +:1010D000DF91CF910F91EF90CF900C94E6070F9393 +:1010E000CF93DF931F92CDB7DEB7FC018081918152 +:1010F000009749F0698301E09E012F5F3F4F41E077 +:10110000B9010E949D0489810F90DF91CF910F91C9 +:1011100008950F93CF93DF9300D0CDB7DEB7FC01D6 +:1011200080819181009749F0698302E09E012F5FE1 +:101130003F4F41E0B9010E949D0489819A8198271F +:10114000892798270F900F90DF91CF910F910895E5 +:101150000E94890898278927982708950C94890860 +:101160000C94A8080F93CF93DF9300D01F92CDB7B4 +:10117000DEB7FC0180819181009749F0698303E02B +:101180009E012F5F3F4F41E0B9010E949D042981DC +:101190006A81862F90E0A0E0B0E0BA2FA92F982FA7 +:1011A0008827A22B2B81BC01CD01622B0F900F90C1 +:1011B0000F90DF91CF910F9108956F927F928F9250 +:1011C0009F92AF92BF92CF92DF92EF92FF920F93D6 +:1011D0001F93CF93DF93EC019FA9892F807C8034EC +:1011E00009F043C0492F477060E2469F90011124E7 +:1011F000892F8695869586958770E4E08E9FA0015D +:101200001124422B532B9295969596959370492BCA +:1012100064EFCE010E94E6070E943F06922E832EC5 +:10122000742E652E63EFCE010E946F0883FF1FC0EE +:101230000E943F06A92CB82CC72CD62CE12CF12CEF +:1012400000E010E00E94F128203D374041055105A3 +:10125000610571058105910509F038F48FE99FE07A +:101260000197F1F700C00000DDCF80E001C081E010 +:10127000DF91CF911F910F91FF90EF90DF90CF9072 +:10128000BF90AF909F908F907F906F9008951F9325 +:10129000CF93DF93EC0168E80E94A8089E8B8D8BAA +:1012A0006AE8CE010E94A808988F8F8B6CE8CE0167 +:1012B0000E94A8089A8F898F6EE8CE010E94A80824 +:1012C0009C8F8B8F60E9CE010E94A8089E8F8D8F26 +:1012D00062E9CE010E94A80898A38F8F64E9CE012D +:1012E0000E94A8089AA389A366E9CE010E94A808D3 +:1012F0009CA38BA368E9CE010E94A8089EA38DA39E +:101300006AE9CE010E94A80898A78FA36CE9CE01D4 +:101310000E94A8089AA789A76EE9CE010E94A80892 +:101320009CA78BA761EACE010E946F088DA761EE92 +:10133000CE010E94A8089FA78EA763EECE010E944F +:101340006F0888AB64EECE010E946F08182F65EE1F +:10135000CE010E946F0890E11902900111248F7054 +:10136000282B3AAB29AB66EECE010E946F08182FEE +:1013700065EECE010E946F0890E1190290011124E0 +:1013800090E044E0959587954A95E1F7822B932B61 +:101390009CAB8BAB67EECE010E946F088DABDF91EB +:1013A000CF911F91089563EF0E946F088170089597 +:1013B000CF92DF92EF92FF920F931F93CF93DF9321 +:1013C000EC0160ED0E946F0890E0A0E0B0E089873A +:1013D0009A87AB87BC8780369105A105B10569F571 +:1013E00046EB60EECE010E94E6078FE39CE9019791 +:1013F000F1F700C00000CE010E94D3098111F5CFA2 +:10140000CE010E944709C12CD12CE12CF12C05E022 +:1014100010E025E030E045E050E063E070E0CE0110 +:101420000E94FD079FEF21EE84E091502040804014 +:10143000E1F700C0000081E001C080E0DF91CF91C2 +:101440001F910F91FF90EF90DF90CF900895CF9371 +:10145000DF93EC01888199810E947D03882329F024 +:10146000CE01DF91CF910C94D80980E0DF91CF912C +:1014700008954F925F926F927F928F929F92AF9258 +:10148000BF92CF92DF92EF92FF92CF93DF93EC0166 +:101490006AEF0E94B2086115710520E88207910584 +:1014A00009F485C06B017C0184E0F594E794D7943E +:1014B000C7948A95D1F74D885E88C701B60128E0A8 +:1014C00030E040E050E00E944327612C712CD301B2 +:1014D000C201880F991FAA1FBB1F281B390B4A0B7B +:1014E0005B0BAF89B88D0E946D274B015C01C70172 +:1014F000B60120E130E040E050E00E944327CA01FD +:10150000B90164197509860997099B01AC010E940C +:1015100013279B01AC017CE055954795379527959E +:101520007A95D1F7A98DBA8D0E946D272B013C01C8 +:10153000C501B40120E038E040E050E00E944327BC +:1015400069017A01C301B20120E030E440E050E0DB +:101550000E944327BA01A9014C0D5D1D6E1D7F1D20 +:1015600089899A89AB89BC899A01AB01280F391FF7 +:101570004A1F5B1F2D873E874F87588BA5E0B0E041 +:101580000E94622760587F4F8F4F9F4F20E031E0CD +:1015900040E050E00E944327CA01B9010E945A2A44 +:1015A00020E030E048EC52E40E94AA2904C060E048 +:1015B00070E080EC9FE7DF91CF91FF90EF90DF909C +:1015C000CF90BF90AF909F908F907F906F905F90E3 +:1015D0004F9008952F923F924F925F926F927F9219 +:1015E0008F929F92AF92BF92CF92DF92EF92FF9233 +:1015F0000F931F93CF93DF93CDB7DEB76D970FB6E1 +:10160000F894DEBF0FBECDBF1C010E94390A67EF00 +:10161000C1010E94B2086F87788B898B9A8B611504 +:1016200071058048910509F49AC2F1018585968576 +:10163000A785B0896C017D01FF0CCC08DC2C7601FC +:101640009C01AD016C2D7C2D8C2D9C2D345F414077 +:101650005109610971098109910929873A874B87E5 +:101660005C873B014C0159016A017B018C010E949E +:101670007527422E3D874E875B8B6C8B7D8B8E8BC7 +:101680009B8FD1015E963C915E975D962C91932F36 +:10169000990F990B492F592F692F792F892F0E9464 +:1016A00075270CE00E94A5282C8F3D8F49835F8B06 +:1016B000688F798F582E9A8FF10130A1278D932F43 +:1016C000990F990BA42CBD84CE84DB88EC88FD880F +:1016D0000E891B8D492F592F692F792F892F0E9431 +:1016E0007527F22E032F142FB52FF62FE72FD82EA4 +:1016F000E92EA0E00E94FA2884F421503F4F4F4F7A +:101700005F4F6F4F7F4F8F4F9F4FF22E032F142F3E +:10171000B52FF62FE72FD82EE92E2F2D302F412F62 +:101720005B2F6F2F7E2F8D2D9E2D08E00E94BE28EF +:10173000AC8CBD8CC980DF88E88CF98C052D1A8DA6 +:101740000E94DC2870588F4F9F4FD1015B96ED911E +:10175000FC915C975F01C12CD12CE12CF12C87010D +:10176000E983BA82CB82DC82ED82FE820F83188706 +:10177000C12CD12CE12CF12C00E010E00E94752747 +:10178000122F3F8B4983B52FF62FE72FF82E092F05 +:10179000A0E00E94FA2884F421503109410951093E +:1017A0006E4F7F4F8F4F9F4F122F3F8B4983B52F27 +:1017B000F62FE72FF82E092F212F3F8949815B2F24 +:1017C0006F2F7E2F8F2D902F01E20E94BE282D8F2C +:1017D000532E49835F8B688F798F8A8F9C8FA0E00F +:1017E0000E94FA2809F4C0C1D10196963C919697BF +:1017F00095962C91932F990F990BA42CBD84CE8490 +:10180000DB88EC88FD880E891B8D492F592F692FA5 +:10181000792F892F0E9475272D873E87442E5B8B59 +:101820006C8B7D8B8E8B9B8FF10134A123A1932F29 +:10183000990F990BA984BA84CB84DC847301840149 +:10184000492F592F692F792F892F0E94752701E180 +:101850000E94A528AD84BE84C42CDB88EC88FD885A +:101860000E891B8D0E94DC2859016A017B01482EDC +:10187000192F4F85588969897A8934E0759567955C +:10188000579547953A95D1F780E090E0A0E1B0E018 +:10189000841B950BA60BB70B3C014D01990C6608F8 +:1018A000762C43019C01AD01662D762D862D962D5B +:1018B0000FE10E94A528722E832E942E652EB62F3E +:1018C000A72F8A879B87F10132A121A1932F990F1E +:1018D000990B492F592F692F792F892F03E20E94E5 +:1018E000A528042D0E94DC2859016A017B018C0186 +:1018F000272D382D492D562D6B2F7A2F8A859B85C4 +:101900000E94F128E5E3AE2EFCE0BF2EC12CD12CC5 +:10191000E12CF12C00E010E00E947527AD8CB52C75 +:10192000C980DF88E88CF98C0A8D1C8D0E94D02735 +:101930002C8B3B8B2A013B014C01F22E032F142FE1 +:10194000B52DF62FE72DD82EE92CA0E00E94FA281D +:1019500084F42150304E4F4F5F4F6F4F7F4F8F4F6A +:101960009F4FF22E032F142FB52FF62FE72FD82ECF +:10197000E92E2F2D302F412F5B2F6F2F7E2F8D2D96 +:101980009E2D0DE00E94BE2829873A874B875C87F1 +:101990006F8779838D879E87D1019C963C919C9718 +:1019A0009B962C91932F990F990BA984BA846A0165 +:1019B0007B01082F1E85492F592F692F792F892FD9 +:1019C0000E9475270E947527F22E032F142FB52F22 +:1019D000F62FE72FD82EE92EA0E00E94FA2884F4F3 +:1019E0002150310941095E4F6F4F7F4F8F4F9F4FFD +:1019F000F22E032F142FB52FF62FE72FD82EE92E16 +:101A00002F2D302F412F5B2F6F2F7E2F8D2D9E2D51 +:101A100009E10E94BE28AC88BB8862017301840181 +:101A20000E94DC2829873A874B875C876F877983F8 +:101A30008D879E87F10132A521A5932F990F990BD0 +:101A4000492F592F692F792F892F0E947527122F1F +:101A50003C8B4B8BB52FF62FE72FF82E092FA0E0EC +:101A60000E94FA2884F421503109484F5F4F6F4F8C +:101A70007F4F8F4F9F4F122F3C8B4B8BB52FF62FE5 +:101A8000E72FF82E092F212F3C894B895B2F6F2FD1 +:101A90007E2F8F2D902F03E10E94BE2859016A01ED +:101AA0007B018C0129853A854B855C856F85798121 +:101AB0008D859E850E94DC28122F39874983B52F9A +:101AC000F62FE72FF82E092FA0E00E94FA2884F4C1 +:101AD00021503F4F4F4F5F4F6F4F7F4F8F4F9F4F63 +:101AE000122F39874983B52FF62FE72FF82E092FAC +:101AF000212F398549815B2F6F2F7E2F8F2D902FBE +:101B000008E00E94BE282983F32F6A017B01E82F99 +:101B1000192FD10197968D919C919897092E000CC1 +:101B2000AA0BBB0B4C015D01BB0C8808982C54011F +:101B30009C01AD01682D782D882D982D04E00E9420 +:101B4000A528A980BF2E0E2F0E94DC280E94522AB1 +:101B500020E030E040E85BE30E94342B08C060E006 +:101B600070E080EC9FE703C060E070E0CB016D9611 +:101B70000FB6F894DEBF0FBECDBFDF91CF911F919E +:101B80000F91FF90EF90DF90CF90BF90AF909F901C +:101B90008F907F906F905F904F903F902F9008951F +:101BA0004F925F926F927F928F929F92AF92BF926D +:101BB000CF92DF92EF92FF92CF93DF9300D000D0CD +:101BC00000D0CDB7DEB79E838D830E94390A6DEFBA +:101BD0008D819E810E948908A0E0B0E0811520E8F7 +:101BE0009207A105B10509F4D3C0ED81FE8185847A +:101BF0009684A784B088FCE29F1AF1E0AF0AB1088E +:101C00003EE0880F991FAA1FBB1F3A95D1F7ED81BF +:101C1000FE8141A952A9052E000C660B770B24E129 +:101C2000440F551F661F771F2A95D1F76C017D0160 +:101C3000C41AD50AE60AF70AA3A9B4A9A501940112 +:101C40000E946D27A7019601261B370B480B590BE5 +:101C5000CA01B901705C8F4F9F4F412C30E8532E61 +:101C6000612C712CA30192010E94432729833A839E +:101C70004B835C83ED81FE81A0A9B0E0A5019401B6 +:101C80000E94622720E038E040E050E00E944327B5 +:101C900069017A01F0E8DF0EE11CF11CED81FE81A3 +:101CA000A5A90A2E000CBB0BA50194010E946D276B +:101CB000812C44E0942EA12CB12CA50194010E940A +:101CC0004327CA01B901A70196010E941327A50164 +:101CD00094010E944327405E5F4FED81FE81A6A5DF +:101CE000B7A50E946D27705E8F4F9F4F20E030E4B4 +:101CF00040E050E00E94432769817A818B819C817A +:101D00000E9413276B017C01A30192010E944327CB +:101D1000CA01B9010E9413279B01AC0167E05595E8 +:101D20004795379527956A95D1F7ED81FE81A5A551 +:101D3000B0E00E94622720E130E040E050E00E94E5 +:101D40004327D701C601821B930BA40BB50BB7FF2A +:101D500003C080E090E0DC0181309105A105F9E14C +:101D6000BF0724F080E090E0A0E0B9E1BC01CD0124 +:101D70002CE095958795779567952A95D1F70E94E0 +:101D8000582A20E030E040E85AE30E94342B04C097 +:101D900060E070E080EC9FE726960FB6F894DEBF17 +:101DA0000FBECDBFDF91CF91FF90EF90DF90CF902E +:101DB000BF90AF909F908F907F906F905F904F906B +:101DC0000895CF92DF92EF92FF926A017B010E9409 +:101DD000EA0A20E030E048EC52E40E94AA29A70178 +:101DE00096010E94AA2921E03EED42E45EE30E94B2 +:101DF000A12B9B01AC0160E070E080E89FE30E94B2 +:101E00003D2920E03AE24DE257E40E94342BFF9056 +:101E1000EF90DF90CF900895CF92DF92EF92FF92F4 +:101E20000F931F93CB01BA016801790120E03AE2D8 +:101E30004DE257E40E94AA299B01AC0160E070E0EA +:101E400080E89FE30E943D2926EF38E248EA50E40B +:101E50000E94A12B9B01AC01C701B6010E94AA29D7 +:101E60001F910F91FF90EF90DF90CF900895FC01AC +:101E700061857285838594850895FC012189328965 +:101E800043895489A5E0B0E00E946227672F782F2C +:101E9000892F992787FD9A950E945A2A20E030E0E1 +:101EA00048EC52E40E94AA290895CF93DF93EC01F5 +:101EB000CB01BA0120E030E048EC52E40E94342B20 +:101EC0000E941C2A982F872F762F662725E030E066 +:101ED00040E050E00E944327298B3A8B4B8B5C8B70 +:101EE000DF91CF9108950F931F93CF93DF938C01D0 +:101EF000EB0188E2FB0111928A95E9F74BE050E093 +:101F000063E571E0CE010E944F2D1B8681E090E0D9 +:101F1000A0E0B0E08C879D87AE87BF87F801808105 +:101F20009181092E000CAA0BBB0B888B998BAA8B75 +:101F3000BB8B8DE090E0A0E0B0E08C8B9D8BAE8BF6 +:101F4000BF8B1CA21DA21EA21FA280E090E0A0E2F7 +:101F5000B2EC8C8F9D8FAE8FBF8F80E090E0AAEAAD +:101F6000B2E4888F998FAA8FBB8F8AE097EDA3E2A6 +:101F7000BCE388A399A3AAA3BBA3DF91CF911F9130 +:101F80000F910895CF93DF93EB0124E2FB011192AF +:101F90002A95E9F744E250E060E070E04883598315 +:101FA0006A837B83FC0180819181092E000CAA0B3E +:101FB000BB0B8C839D83AE83BF838DE090E0A0E05C +:101FC000B0E088879987AA87BB870E943F06288B45 +:101FD000398B4A8B5B8B8CE694E00E94390A6C8BC0 +:101FE0007D8B8E8B9F8B81E0DF91CF9108950F9336 +:101FF0001F93CF93DF938C01EB0188E2FB011192D9 +:102000008A95E9F74BE050E063E571E0CE010E946C +:102010004F2D1B8681E090E0A0E0B0E08C879D878B +:10202000AE87BF87F80180819181092E000CAA0B31 +:10203000BB0B888B998BAA8BBB8B86E090E0A0E0D2 +:10204000B0E08C8B9D8BAE8BBF8B1CA21DA21EA201 +:102050001FA280E090E0A6E9B3E48C8F9D8FAE8F45 +:10206000BF8F80E090E8A9E8B4E4888F998FAA8FA9 +:10207000BB8F86EA9BE9A4E4BCE388A399A3AAA347 +:10208000BBA3DF91CF911F910F910895CF93DF9361 +:10209000EB0124E2FB0111922A95E9F744E250E0BA +:1020A00060E070E0488359836A837B83FC01808110 +:1020B0009181092E000CAA0BBB0B8C839D83AE83F0 +:1020C000BF8386E090E0A0E0B0E088879987AA8788 +:1020D000BB870E943F06288B398B4A8B5B8B8CE633 +:1020E00094E00E94EA0A20E030E048EC52E40E94CA +:1020F000AA296C8B7D8B8E8B9F8B81E0DF91CF919A +:1021000008950F931F93CF93DF938C01EB0188E227 +:10211000FB0111928A95E9F74BE050E063E571E02D +:10212000CE010E944F2D1B8681E090E0A0E0B0E040 +:102130008C879D87AE87BF87F80180819181092EAA +:10214000000CAA0BBB0B888B998BAA8BBB8B8CE0EA +:1021500090E0A0E0B0E08C8B9D8BAE8BBF8B1CA27F +:102160001DA21EA21FA21C8E1D8E1E8E1F8E80E021 +:1021700090E0A8ECB2E4888F998FAA8FBB8F80E0A3 +:1021800090E0A0E4B0E488A399A3AAA3BBA3DF9145 +:10219000CF911F910F910895CF93DF93EB0124E22C +:1021A000FB0111922A95E9F744E250E060E070E00B +:1021B000488359836A837B83FC0180819181092E46 +:1021C000000CAA0BBB0B8C839D83AE83BF838CE07A +:1021D00090E0A0E0B0E088879987AA87BB870E943B +:1021E0003F06288B398B4A8B5B8B8CE694E00E94F0 +:1021F000D00D6C8B7D8B8E8B9F8B81E0DF91CF918F +:102200000895CF93DF93EC010E9472031A828CE74A +:102210008CAB8AE08DAB8EE78EAB8FEA8FAB88AF4D +:1022200082EA89AF1AAE80E88BAFDF91CF91089533 +:10223000CF93DF9300D0CDB7DEB74A83698342E006 +:10224000BE016F5F7F4F0E9455040F900F90DF918A +:10225000CF9108950F93CF93DF931F92CDB7DEB741 +:102260009A01698301E041E0BE016F5F7F4F0E94E8 +:102270009D040F90DF91CF910F9108950F93CF930D +:10228000DF931F92CDB7DEB79A01698302E041E088 +:10229000BE016F5F7F4F0E949D040F90DF91CF9131 +:1022A0000F9108950F931F93CF93DF9300D0CDB775 +:1022B000DEB78A01AE014F5F5F4F0E943E11882357 +:1022C00041F029813A81322723273227F8013183CF +:1022D00020830F900F90DF91CF911F910F91089560 +:1022E0000F93CF93DF931F92CDB7DEB76983022F91 +:1022F0009E012F5F3F4F41E0B9010E949D040F9066 +:10230000DF91CF910F91089540EF60E10E94181185 +:10231000EFE3FCE93197F1F700C0000008950F9357 +:102320001F93CF93DF9300D0CDB7DEB78C01AE0102 +:102330004F5F5F4F60E00E943E118FE39CE9019781 +:10234000F1F700C0000089819A818036E1E09E07A4 +:1023500021F4F801128281E008C08136914021F415 +:1023600081E0F801828301C080E00F900F90DF913F +:10237000CF911F910F9108950F931F93CF93DF93E8 +:102380001F92CDB7DEB78C0140E062E10E941811C8 +:10239000811108C08FE39CE90197F1F700C00000AC +:1023A00080E016C04CEC62E1C8010E94181188233D +:1023B00089F38FE39CE90197F1F700C00000AE01BB +:1023C0004F5F5F4F60E2C8010E942A11882311F31A +:1023D0000F90DF91CF911F910F9108950F931F934D +:1023E000CF93DF9300D01F92CDB7DEB78C010E9450 +:1023F000BC11882359F18FE39CE90197F1F700C0E4 +:1024000000004EE062E1C8010E9418118823F1F03B +:1024100023E0AE014F5F5F4F6CE4C8010E94701172 +:102420008823A1F02981F80123839A8194839B81D9 +:10243000958391E0273008F490E0F8019283EFE370 +:10244000FCE93197F1F700C0000007C08FE39CE979 +:102450000197F1F700C0000080E00F900F900F90FF +:10246000DF91CF911F910F910895633021F4FC010A +:102470002281222359F0462F60E10E941811EFE3D8 +:10248000FCE93197F1F700C00000089580E008955D +:10249000CF93DF93EC0163E50E947D038FE39CE91A +:1024A0000197F1F700C00000CE010E94841188233B +:1024B000A9F0CE010E948F11882381F061E0CE0146 +:1024C0000E943512882351F0CE010E94BC1188234E +:1024D00029F0CE01DF91CF910C94EE1180E0DF91D5 +:1024E000CF910895CF93DF9361157105D9F0EC0179 +:1024F0007F836E8361E00E943512882399F0CE01BC +:102500000E94BC11882371F042EC62E1CE010E946E +:102510001811882339F0EFE3FCE93197F1F700C097 +:10252000000007C08FE39CE90197F1F700C00000AD +:1025300080E0DF91CF9108956F927F928F929F926A +:10254000AF92BF92CF92DF92EF920F931F93CF93F0 +:10255000DF931F92CDB7DEB73C01CB01342FE02FC4 +:10256000AFE3BCE91197F1F700C0000068E170E04B +:102570000E942F278B014FEF460F4295440F440FC7 +:10258000407C3111406221114061E1114860E1104D +:10259000446060E4C3010E941811882309F471C0EB +:1025A000A80141505109569547955695479561E4C4 +:1025B000C3010E941811882309F463C0A60156952F +:1025C000479562E4C3010E941811882309F459C099 +:1025D000A5015695479563E4C3010E94181188230D +:1025E00009F44FC0A4015695479564E4C3010E94C5 +:1025F0001811811146C049895A895695479565E455 +:10260000C3010E94181181113CC0F3014681415061 +:1026100066E4C3010E941811811133C0D3011696DC +:102620008D919C911797019711F440E801C040E00B +:1026300067E4C3010E941811882319F1EFE3FCE954 +:102640003197F1F700C00000AE014F5F5F4F6FE4BC +:10265000C3010E942A118823A1F0AFE3BCE91197BE +:10266000F1F700C00000F30126813781B901606CE9 +:10267000498150E06417750729F02F5F3F4F37837A +:10268000268380E00F90DF91CF911F910F91EF9003 +:10269000DF90CF90BF90AF909F908F907F906F9082 +:1026A0000895AB0160E20C942A110F93CF93DF934E +:1026B0001F92CDB7DEB79B0141E2498305E041E0BF +:1026C000BE016F5F7F4F0E949D040F90DF91CF91FD +:1026D0000F9108950F931F93CF93DF93CDB7DEB77C +:1026E00029970FB6F894DEBF0FBECDBF8C016623CD +:1026F000F1F0AE01475F5F4F60E2C8010E942A110E +:102700008823E9F08FE99FE00197F1F700C000000E +:10271000898581FFEECF898581FF11C027E0AE0159 +:102720004F5F5F4F61E2C8010E94701108C0AE01A7 +:10273000475F5F4F60E20E942A118111ECCF80E079 +:1027400029960FB6F894DEBF0FBECDBFDF91CF91B3 +:102750001F910F9108950F931F93CF93DF93CDB7E0 +:10276000DEB729970FB6F894DEBF0FBECDBF8C0140 +:102770006623C1F08FE99FE00197F1F700C00000E8 +:10278000AE01475F5F4F60E2C8010E942A118111CC +:1027900002C080E00AC1898580FFECCF898580FF77 +:1027A000F8CF09C0AE01475F5F4F60E20E942A1177 +:1027B0008111F4CFEECF28E0AE014F5F5F4F68E4A8 +:1027C000C8010E947011882321F369817A8180E019 +:1027D00090E00E94582A20E030E040E05AE30E9456 +:1027E000342B9B01AC0160E070E080E090E40E943B +:1027F000A12B0E94232AF8016787708B818B928B13 +:102800006B817C8180E090E00E94582A20E030E0DB +:1028100040E05AE30E94342B9B01AC0160E070E081 +:1028200080E090E40E94A12B0E94232AF801678B8C +:10283000708F818F928F6D817E8180E090E00E9409 +:10284000582A20E030E040E05AE30E94342B9B01FC +:10285000AC0160E070E080E090E40E94A12B0E9457 +:10286000232AF801678F70A381A392A36F817885D3 +:1028700080E090E00E94582A20E030E040E05AE3F7 +:102880000E94342B9B01AC0160E070E080E090E49A +:102890000E94A12B0E94232AF80167A370A781A799 +:1028A00092A728E0AE014F5F5F4F68E2C8010E9427 +:1028B0007011882309F46DCF69817A8180E090E0FE +:1028C0000E94582A20E030E040E05AE30E94342B76 +:1028D0009B01AC0160E070E080E090E40E94A12BDD +:1028E0000E94232AF801638B748B858B968B6B81F6 +:1028F0007C8180E090E00E94582A20E030E040E0B7 +:102900005AE30E94342B9B01AC0160E070E080E050 +:1029100090E40E94A12B0E94232AF801638F748FF8 +:10292000858F968F6D817E8180E090E00E94582A8D +:1029300020E030E040E05AE30E94342B9B01AC01E0 +:1029400060E070E080E090E40E94A12B0E94232AC6 +:10295000F80163A374A385A396A36F81788580E0B3 +:1029600090E00E94582A20E030E040E05AE30E94C4 +:10297000342B9B01AC0160E070E080E090E40E94A9 +:10298000A12B0E94232AF80163A774A785A796A705 +:10299000AE014F5F5F4F68E3C8010E942A11882390 +:1029A00009F4F7CE9981F80193AB29960FB6F89404 +:1029B000DEBF0FBECDBFDF91CF911F910F91089564 +:1029C000CF93DF9300D000D0CDB7DEB769837A8391 +:1029D0004B835C8324E0AE014F5F5F4F63E10E9455 +:1029E00000040F900F900F900F90DF91CF910895FA +:1029F0008F929F92AF92BF92CF92DF92EF92FF920F +:102A00000F931F93CF93DF93EC014A015B01C90140 +:102A1000B80120E030E040E054E40E94342B0E94F2 +:102A2000232A6B017C0123E333E948E853E4C50121 +:102A3000B4010E943E2920E030E040E852E40E94C8 +:102A4000342B0E94232AA601CE01DF91CF911F9142 +:102A50000F91FF90EF90DF90CF90BF90AF909F903D +:102A60008F900C94E01408958FEF089582E292E025 +:102A70000895089520982AB12F762AB9289A2BB163 +:102A800020692BB921E0FC0122830895FC01128208 +:102A900028988BB18F768BB920988AB18F768AB9B6 +:102AA0000895EF92FF920F931F93CF93DF936111DD +:102AB0002CC0EC0102E312E084E2E82E82E0F82E62 +:102AC0006AE070E080E090E00E9413060196F9F45D +:102AD0001F930F930E94C62D8B811F928F93282FD7 +:102AE000082E000C330B3F938F93FF92EF920E94BE +:102AF000C62D8DB79EB708960FB6F8949EBF0FBE31 +:102B00008DBF4F99DDCF1B82DBCF8FEF01C080E0FF +:102B1000DF91CF911F910F91FF90EF90089589B1B0 +:102B20008095881F8827881F089589B182958170B4 +:102B300091E08927089583B1809581700895FC0103 +:102B40008281811102C01382089529B131E022955A +:102B500021702327279522272795220F220B83B147 +:102B60003827379533273795330F330B80E020FB19 +:102B700080F930FB81F990911F0198279370D1F46F +:102B800090911E0190FD0EC0982791FF0BC093817C +:102B900081FD04C09F3729F09F5F03C0903809F082 +:102BA0009150938380911E0120FB80F930FB81F9C5 +:102BB00080931E0180911F0120FB80F930FB81F979 +:102BC00080931F010895FC018281938183309105D8 +:102BD00040F4880F991FFC01E65BFE4F80819181D4 +:102BE000089582E791E00895E8EBF0E02DE020837E +:102BF0002CE1208324E6208324E02093BC0020E6FF +:102C000020937C0027E820937A0080579F4F21E093 +:102C1000FC012083089580579F4FFC01108284E0BF +:102C20008093BC001092B80010927C0010927A0041 +:102C300008952F923F924F925F926F927F928F9260 +:102C40009F92AF92BF92CF92DF92EF92FF920F933B +:102C50001F93CF93DF93CDB7DEB761970FB6F8948C +:102C6000DEBF0FBECDBF8C016111A5C2FC01828108 +:102C70009381009709F0E8C188EC93E09F938F93CC +:102C80000E94C62D98012C5F3F4F3D872C8767E738 +:102C9000C9010E94270A0F900F90811103C085EC93 +:102CA00093E08BC285EB93E09F938F930E94C62D98 +:102CB00058013DE3A30EB11CC5010E9448120F90BC +:102CC0000F90811103C082EB93E077C262E0C501EF +:102CD0000E943512811103C08FEA93E06EC200E0BA +:102CE00010E022E832E440E050E068EC71E4C50115 +:102CF0000E94F814811103C08CEA93E05EC289EA55 +:102D000093E09F938F930E94C62D0F900F908FEFAB +:102D10008F83412C512C32014E865F86688A798AD6 +:102D20008C859D850E94EA0A20E030E543EC57E45B +:102D30000E94AA299F938F937F936F93E2E9F3E018 +:102D4000FF93EF930E94C62D8C859D850E94390AC2 +:102D500068877987382E292E9F938F9339853F93E3 +:102D600088858F93E5E8F3E0FF93EF930E94C62DEB +:102D70008C859D850E94D00D4B018A879B879F93F0 +:102D80008F939F926F9389E793E09F938F930E9415 +:102D9000C62D0FB6F894DEBF0FBECDBF3F813F3FBB +:102DA00009F19A858B85282D392D492F582FFC0143 +:102DB000682D792D8F2F9E2F0E94F12B811112C02B +:102DC00078856985C101272F362F492F582FDB01C0 +:102DD000F1016B2F7A2F8F2F9E2F0E94F12B8823CA +:102DE00009F4FBC165E0C62ED12CE12CF12C05E0E5 +:102DF00010E025E030E045E050E063E070E08C85D5 +:102E00009D850E94FD078F81803208F413C1ECE696 +:102E1000F3E0FF93EF930E94C62D0F900F903F8138 +:102E200013162CF5632F330F770B880B990B0E9429 +:102E30005A2A6B017C019B01AC01C301B2010E94C3 +:102E4000AA294B018A879B87A70196016E857F85FA +:102E5000888999890E94AA2968877987382E292E1E +:102E6000412C512C32014E865F86688A798A9A8578 +:102E70008B85082D192D292F382FF885E985C1015B +:102E80004F2F5E2F692F722DC5010E94F8148111FA +:102E900005C088E693E09F938F93C7C08B858F937F +:102EA0009A859F939F928F922F923F92E985EF93FD +:102EB000F885FF9326E533E03F932F930E94C62DBC +:102EC00062E0C5010E9435120FB6F894DEBF0FBE56 +:102ED000CDBF811103C083E593E093C014E68FE575 +:102EE0009AEE0197F1F700C00000BE016A5F7F4FC4 +:102EF000C5010E945113882309F48AC08E8181FF85 +:102F000087C0BE016F5F7F4FC5010E9455138823A4 +:102F100009F481C089811F928F93EAE4F3E0FF9363 +:102F2000EF930E94C62D0F900F900F900F90898104 +:102F3000833091F038F4813061F0823099F48BE382 +:102F400093E012C0843059F0853061F483E293E05D +:102F50000BC080E493E008C082E393E005C08DE2FB +:102F600093E002C081E293E09F938F930E94C62D6D +:102F70000F900F908B818F938A818F9383E193E0E1 +:102F80009F938F930E94C62D8D818F938C818F93F9 +:102F900028E033E03F932F930E94C62D8C819D81C2 +:102FA0000FB6F894DEBF0FBECDBF8039F1E09F07AA +:102FB00018F486E093E01DC0883522E0920718F4EB +:102FC0008CEF92E016C0803233E0930718F487EF5D +:102FD00092E00FC0883EE3E09E0718F482EF92E093 +:102FE00008C08C3D954018F48DEE92E002C089EE49 +:102FF00092E09F938F930E94C62D0F900F9087EEC3 +:1030000092E09F938F930E94C62D0F900F9003C064 +:10301000115009F064CF61E0C5010E9435128111A1 +:1030200008C024EE32E03F932F930E94C62D0F90EC +:103030000F901F8268EE73E080E090E00E9413061C +:10304000019609F46DCEC1C08130910509F071C0BF +:1030500007581F4F61E0C8010E947D03811103C022 +:1030600081EE92E0AAC092EC692E92E0792E28EBD4 +:10307000E22E22E0F22E38EAC32E32E0D32E47E9C8 +:10308000A42E42E0B42E51EA852E52E0952E809176 +:103090007A00806480937A0080917A0086FDFCCF6C +:1030A0008091790089831F928F937F926F920E9403 +:1030B000C62D41E0BE016F5F7F4FC8010E945504DD +:1030C0000F900F900F900F90811106C0FF92EF921A +:1030D0000E94C62D0F900F90DF92CF920E94C62DB6 +:1030E00041E0BE016F5F7F4FC8010E9432040F9024 +:1030F0000F90882361F089811F928F939F928F9206 +:103100000E94C62D0F900F900F900F9006C0BF9297 +:10311000AF920E94C62D0F900F9068EE73E080E092 +:1031200090E00E941306019609F4B1CF0E94870334 +:103130004CC0029709F03FC005581F4F40E061E0C6 +:10314000C8010E94E604811103C084E992E035C001 +:103150008EE5C82E82E0D82EC8010E9436057C017B +:103160000196F1F080917A00806480937A008091DA +:103170007A0086FDFCCF60917900C8010E94160597 +:10318000809179001F928F93FF92EF92DF92CF92FE +:103190000E94C62D0F900F900F900F900F900F90E0 +:1031A00060E070E0CB010E9413060196A9F2C8010D +:1031B0000E94F6040AC08AE592E09F938F930E94D2 +:1031C000C62D0F900F908FEF29C064EF71E080E063 +:1031D00090E00E94130680E021C078856985C101D6 +:1031E000272F362F492F582F6E857F8588899989FB +:1031F0000E943E296E877F87888B998B9A858B8565 +:10320000282D392D492F582FC301B2010E943E2984 +:103210002B013C018F818F5F8F83E4CD61960FB6C8 +:10322000F894DEBF0FBECDBFDF91CF911F910F91FC +:10323000FF90EF90DF90CF90BF90AF909F908F90D6 +:103240007F906F905F904F903F902F900895FC017A +:10325000228133812230310541F4579A5F9A855893 +:103260009F4F0E943B055F9808958091BC00806845 +:103270008093BC00089508958FEF08955A9A089599 +:103280005A9808955B9A08955B980895439A089513 +:103290004398089560FF02C05C9A01C05C9861FF8A +:1032A00002C0289A01C0289862FF02C05F9A01C03C +:1032B0005F9863FF02C05E9A01C05E9864FF02C01F +:1032C0002A9A01C02A9865FF02C02B9A01C02B9848 +:1032D00066FF02C02C9A01C02C9867FF02C02D9A8D +:1032E00008952D980895FC018281811104C0209ACF +:1032F0008AB1806D8AB984B18C6384B908952091B4 +:103300005E04213011F40C947319FC018281811147 +:1033100004C020988AB18F728AB984B1837C84B941 +:10332000089580915E04813041F48FE99FE0019718 +:10333000F1F700C0000080E0089589B182958170A6 +:10334000189902C090E001C092E0282F292B99B172 +:10335000892F881F8827881F880F880F822B4E99F6 +:1033600002C030E001C038E0832B1A9902C030E07F +:1033700001C030E1832B1B9902C020E001C020E294 +:10338000822B1C9902C090E001C090E4892B1D990A +:1033900002C090E001C090E8892B0895409A0895FA +:1033A000409808951F93CF93DF93EC01162F0E944E +:1033B0004819CE010E9473198A81612F8823A1F0D8 +:1033C000607FCE010E944A19CE010E94461980E515 +:1033D0008A95F1F7CE010E94481985E08A95F1F7A8 +:1033E0000000612F6295607FCE010E944A19CE01D4 +:1033F0000E94461980E58A95F1F7CE010E9448198E +:1034000085E08A95F1F70000DF91CF911F91089533 +:103410001F93CF93DF93EC01162F0E944419CE0126 +:103420000E944019612FCE01DF91CF911F910C9422 +:10343000D219EF92FF920F931F93CF93DF93EC017A +:103440007B018B8187FD61C080915E04813041F4F6 +:103450008FE99FE00197F1F700C0000081E056C0BE +:10346000CE010E947F196FEFCE010E944A19CE0152 +:103470000E944219CE010E94401995E09A95F1F7F9 +:103480000000CE010E94461980E58A95F1F7CE0131 +:103490000E949119082FCE010E94481995E09A9533 +:1034A000F1F70000CE010E94461980E58A95F1F7F8 +:1034B000CE010E94911982958F70007F182F102BDA +:1034C000CE010E94481995E09A95F1F70000CE01CF +:1034D0000E94441910788BE0E816F10430F09BE06C +:1034E000E91AF10811F01111C2CF8B81813021F45A +:1034F000112311F08BEF8B8360E0CE010E944A19FB +:10350000CE010E94731981E0111180E0DF91CF910B +:103510001F910F91FF90EF900895CF93DF93EC01EF +:1035200062E370E00E94191A811102C08AEF8B8356 +:10353000DF91CF9108951F93CF93DF93EC01162F66 +:103540000E948D1A612F6068CE010E94081ACE0178 +:10355000DF91CF911F910C948D1A1F93CF93DF931E +:10356000EC0160E00E944A19CE010E9473198FEFAE +:1035700099EF0197F1F700C000001B8210E08A81EB +:10358000882311F068E201C068E0CE010E94081AA9 +:10359000111105C08FE19EE40197F1F704C08FE897 +:1035A00091E00197F1F700C000001F5F143039F778 +:1035B0006CE0CE010E94081A62E370E0CE010E9426 +:1035C000191A811102C08FEF1BC06CE0CE010E945E +:1035D000081A62E370E0CE010E94191A811102C03C +:1035E0008DEF0EC061E0CE010E94081A60EB74E01E +:1035F000CE010E94191A811102C08CEF01C081E036 +:103600008B83DF91CF911F910895CF93DF93EC01CE +:103610000E944419CE010E944019CE010E9448190F +:1036200060E0CE010E944A1984B18D6384B987B1EC +:10363000896087B98AB18C6D8AB9CE010E94AD1AB2 +:103640008CE294E09F938F930E94C62D8B810F9004 +:103650000F90813049F488E294E09F938F930E9409 +:10366000C62D0F900F9010C0282F082E000C330B82 +:103670003F938F938EE194E09F938F930E94C62D8A +:103680000F900F900F900F90CE01DF91CF910C947F +:10369000CE19CF93DF93FC012381213061F4EC013B +:1036A0000E948D1A6CE0CE010E94081ACE01DF91B3 +:1036B000CF910C948D1ADF91CF910895CF93DF9322 +:1036C000FC012381213061F4EC010E948D1A68E035 +:1036D000CE010E94081ACE01DF91CF910C948D1A71 +:1036E000DF91CF910895CF93DF93FC0123812130A7 +:1036F00061F4EC010E948D1A61E0CE010E94081A6B +:10370000CE01DF91CF910C948D1ADF91CF91089566 +:103710000E94731B85B1827C85B988B1867F88B988 +:103720008BB183728BB984B1827C84B987B1867F77 +:1037300087B98AB183728AB90895CF93DF93EC0178 +:103740008B818130B9F44431A8F4613039F048F00C +:10375000623031F0633071F44C5A03C0405C01C0F8 +:103760004C5E642FCE010E949B1ACE01DF91CF9157 +:103770000C948D1ADF91CF9108951F93CF93DF930F +:10378000FC0123812130A1F4162FEC010E94441981 +:10379000CE010E943E19612FCE010E94D219CE01A6 +:1037A0000E944019CE01DF91CF911F910C948D1A88 +:1037B000DF91CF911F910895FF920F931F93CF93A5 +:1037C000DF938C0161114FC0C0E084E1F82ED0E29C +:1037D000DC0F8C2F6F2D0E942327911105C040E034 +:1037E000682FC8010E949D1B6D2FC8010E94BD1B40 +:1037F000C8010E948D1ACF5FC03549F789E194E076 +:103800009F938F930E94C62DF80183810F900F9094 +:10381000813049F486E194E09F938F930E94C62DF6 +:103820000F900F9010C0282F082E000C330B3F93E1 +:103830008F938CE094E09F938F930E94C62D0F90FE +:103840000F900F900F9061E070E080E090E00E9498 +:1038500013060196C1F364EF71E080E090E00E94EE +:10386000130680E009C088E094E09F938F930E9444 +:10387000C62D0F900F908FEFDF91CF911F910F9179 +:10388000FF9008950F931F93CF93DF93EC018B016B +:10389000F80161918F01662339F08B81813021F429 +:1038A000CE010E94BD1BF4CFDF91CF911F910F91EC +:1038B00008958BB1837D8BB929988AB18C628AB9BE +:1038C000219A08958AB1837D8AB921988BB1837D2D +:1038D0008BB9299808958130910549F030F08230F4 +:1038E000910539F0039739F008955D9A0895299A62 +:1038F00008955B9A08955A9A0895CB0141110C944A +:103900006B1C6130710551F038F06230710541F087 +:103910006330710539F008955D98089529980895E8 +:103920005B9808955A9808956130710559F038F000 +:103930006230710561F06330710561F008959BB1EB +:1039400080E20AC095B182E0892785B908959BB1CC +:1039500088E002C09BB184E089278BB90895CB0130 +:103960000C946B1C40E00C947D1CCF936031E8F507 +:10397000C62FC370C23091F0C330B9F0C13039F0F6 +:1039800063E070E00E94B21C80E090E014C060E050 +:1039900070E00E94B21C81E090E00DC061E070E038 +:1039A0000E94B21C82E090E006C062E070E00E94DB +:1039B000B21C83E090E00E946B1C6C2F70E06F5F84 +:1039C0007F4F7F936F938BE394E09F938F930E943D +:1039D000C62D64EF71E080E090E00E9413060F9026 +:1039E0000F900F900F9080E001C08FEFCF9108955E +:1039F00008958FEF0895089586B183FB882780F995 +:103A000091E0892708952A9808955298FC0112821E +:103A100010927C0010927A0014BC15BC0E94031D09 +:103A200022983B988AB18F728AB943988BB18F7371 +:103A30008BB908952A9A0895CF93DF93EC01529A97 +:103A400080E680937C0087E880937A0083E884BDD9 +:103A500084E085BD229A3B98569A8AB18F768AB9BE +:103A6000439A8BB1806A8BB9CE010E941A1D81E006 +:103A70008A83DF91CF9108952F923F924F925F9268 +:103A80006F927F928F929F92AF92BF92CF92DF926E +:103A9000EF92FF920F931F93CF93DF936111FDC0BD +:103AA000EC0188ED94E09F938F930E94C62D0F90B8 +:103AB0000F9038EC232E34E0332E44EB642E44E098 +:103AC000742E05EA14E05BE9E52E54E0F52E60E97A +:103AD000C62E64E0D62E74E8A72E74E0B72EE3E578 +:103AE0004E2EE4E05E2EFCE68F2EF4E09F2E6AE080 +:103AF00070E080E090E00E941306019609F0CFC0CC +:103B000086B183FB882780F91F928F938DEC94E018 +:103B10009F938F930E94C62D0F900F900F900F9040 +:103B2000CE01339905C00E94031D3F922F9206C01B +:103B30000E941A1D83EC94E09F938F930E94C62DE0 +:103B40000F900F9080917A00806480937A0080912A +:103B50007A0086FDFCCF809179001F928F937F922F +:103B60006F920E94C62D82EE80937C002091790096 +:103B700030E0255031094BE5429FC001439F900D35 +:103B800011240F900F900F900F9097FDCF9626E085 +:103B9000959587952A95E1F78F3F910519F014F0D7 +:103BA0008FEF90E097FF02C080E090E08095823038 +:103BB00008F480E087BD1F928F931F930F930E949C +:103BC000C62D80917A00806480937A000F900F90C8 +:103BD0000F900F9080917A0086FDFCCF8091790044 +:103BE0001F928F93FF92EF920E94C62D80E68093E2 +:103BF0007C0089B1082E000C990B892F881F88271B +:103C0000881F1F928F93DF92CF920E94C62D89B199 +:103C1000829581701F928F93BF92AF920E94C62DA2 +:103C2000F8946B817C8178948DB79EB70C960FB613 +:103C3000F8949EBF0FBE8DBF6115710519F17F937A +:103C40006F9380E090E00E94582A9B01AC0160E0F5 +:103C500070E080E792E40E94AA2927E137EB41ED6A +:103C600058E30E94AA290E941C2A7F936F939F9277 +:103C70008F920E94C62D0F900F900F900F900F9073 +:103C80000F9035CF1F921F925F924F920E94C62DC8 +:103C90000F900F900F900F902ACF8FEF01C080E010 +:103CA000DF91CF911F910F91FF90EF90DF90CF9018 +:103CB000BF90AF909F908F907F906F905F904F904C +:103CC0003F902F90089589B18095881F8827881F7D +:103CD000089589B18295817008959BB184E0892708 +:103CE0008BB908951F93CF93DF93EC0111E080917E +:103CF000AF049091B0044C991CC010E02091B30423 +:103D0000222309F12091B1043091B204233031050E +:103D1000D0F0820F931F9C838B831092B204109279 +:103D2000B1041092B0041092AF04CE010E946D1E37 +:103D30000AC0811520E4920748F501969093B004DB +:103D40008093AF040DC08091B1049091B2048115AD +:103D500020E49207F0F401969093B2048093B104AA +:103D60008091AF049091B0048115904438F4809113 +:103D7000B1049091B2048115904410F01C821B8212 +:103D80001093B304DF91CF911F91089580E090E4E8 +:103D9000D5CF80E090E4E0CF419839982A9884B15B +:103DA000837D84B91CBC08958091640084708093E5 +:103DB0006400419A399A2A9A84B18C6284B98CB58C +:103DC00083658CBD80915E04823011F45F9A579AAE +:103DD000089580915E04823009F45F98089580917F +:103DE0005E04823009F45F9A08950F931F93CF9376 +:103DF000DF93EC01062F142F0E94E91E80E48EBD94 +:103E00000DB407FEFDCF0EBD0DB407FEFDCF1EBDE8 +:103E10000DB407FEFDCFCE010E94EF1E8AE18A9508 +:103E2000F1F700C080E0DF91CF911F910F910895CD +:103E30001F93CF93DF93EC01162F0E94E91E81E4BC +:103E40008EBD0DB407FEFDCF1EBD0DB407FEFDCF28 +:103E50001EBC0DB407FEFDCFCE010E94EF1E8EB535 +:103E6000DF91CF911F910895CF93DF93C42FD22F6D +:103E70001F924F931F926F9388E895E09F938F93C3 +:103E80000E94C62D0F900F900F900F900F900F90E3 +:103E9000CD1769F081E895E09F938F930E94C62D1E +:103EA0000F900F90CF3F59F486E695E002C082E66E +:103EB00095E09F938F930E94C62D0F900F9080E600 +:103EC00095E09F938F930E94C62D0F900F90DF91E6 +:103ED000CF9108952F923F924F925F926F927F926F +:103EE0008F929F92AF92BF92CF92DF92EF92FF920A +:103EF0000F931F93CF93DF93EC0180915E04813089 +:103F000049F483E495E09F938F930E94C62D0F9010 +:103F10000F90D9C06111D7C084E3282E85E0382ED8 +:103F2000CC24C394D12C2FE1422E25E0522E3AE02E +:103F3000632E35E0732E45EFA42E44E0B42E50EEF0 +:103F4000852E54E0952E64EF71E080E090E00E94B1 +:103F50001306019609F0B9C03F922F920E94C62D18 +:103F60000F900F90E12CF12C86010E2C01C0000F58 +:103F70000A94EAF7402F409560E0CE010E94F51EBA +:103F8000402F62E1CE010E94F51EFF92EF925F92F8 +:103F90004F920E94C62D62E1CE010E94181F202F71 +:103FA000482F62E1CE010E94341F68EC70E080E08F +:103FB00090E00E94130640E062E1CE010E94F51EEF +:103FC000FF92EF927F926F920E94C62D62E1CE0126 +:103FD0000E94181F20E0482F62E1CE010E94341F8A +:103FE0004FEF60E0CE010E94F51E68EC70E080E0CB +:103FF00090E00E9413068FEFE81AF80A8DB79EB77B +:1040000008960FB6F8949EBF0FBE8DBF98E0E916D4 +:10401000F10409F0A9CF00E010E07601002E01C004 +:10402000EE0C0A94EAF74E2D409561E0CE010E9415 +:10403000F51E4E2D63E1CE010E94F51E1F930F93D6 +:10404000BF92AF920E94C62D63E1CE010E94181F5D +:104050002E2D482F63E1CE010E94341F68EC70E0E2 +:1040600080E090E00E94130640E063E1CE010E94F0 +:10407000F51E1F930F939F928F920E94C62D63E1AE +:10408000CE010E94181F20E0482F63E1CE010E945C +:10409000341F4FEF61E0CE010E94F51E68EC70E026 +:1040A00080E090E00E9413060F5F1F4F8DB79EB710 +:1040B00008960FB6F8949EBF0FBE8DBF083011054D +:1040C00009F0ABCF40CF8FEF01C080E0DF91CF91FF +:1040D0001F910F91FF90EF90DF90CF90BF90AF9026 +:1040E0009F908F907F906F905F904F903F902F9018 +:1040F000089580E480937C0087E880937A00089597 +:1041000010927C0010927A0008950F931F93CF9322 +:10411000DF9361113AC08AEC95E09F938F930E94E0 +:10412000C62D0F900F9005EB15E0C8EAD5E06AE0C8 +:1041300070E080E090E00E941306019641F51F9325 +:104140000F930E94C62D80917A00806480937A003C +:104150000F900F9080917A0086FDFCCF209178001F +:104160003091790080917800909179003F932F935E +:104170009F938F93DF93CF930E94C62D0F900F9044 +:104180000F900F900F900F90D2CF8FEF01C080E073 +:10419000DF91CF911F910F91089582E480937C006D +:1041A00087E880937A00089510927C0010927A003C +:1041B0000895AF92BF92CF92DF92EF92FF920F934A +:1041C0001F93CF93DF93611185C083E196E09F93A6 +:1041D0008F930E94C62D0F900F903EEFE32E35E097 +:1041E000F32E01EF15E0C1EDD5E06AE070E080E06C +:1041F00090E00E941306019609F06EC0FF92EF92C4 +:104200000E94C62D80917A00806480937A000F907E +:104210000F9080917A0086FDFCCF2091780030913C +:10422000790080917800909179003F932F939F932C +:104230008F931F930F930E94C62D60917800709109 +:10424000790080E090E00E94582A23EC35EF48EA9C +:104250005FE30E94342B2AE939E941E852E40E94E5 +:10426000AA292DEC3CEC4CE05FE30E943E29D62EBF +:10427000C72EB82EA92EA6019501652F742F832F66 +:10428000922F0E94232A862F90E061701F926F93D5 +:1042900081FB222720F91F922F9382FB222720F9EE +:1042A0001F922F9323E0959587952A95E1F79F9389 +:1042B0008F93AF92BF92CF92DF92DF93CF930E9402 +:1042C000C62D8DB79EB744960FB6F8949EBF0FBE0D +:1042D0008DBF8BCF8FEF01C080E0DF91CF911F9119 +:1042E0000F91FF90EF90DF90CF90BF90AF90089527 +:1042F000442371F06130710539F020F062307105AE +:1043000029F008955C980895289808955F98089575 +:104310006130710539F020F06230710529F008959F +:104320005C9A0895289A08955F9A089561307105FE +:1043300049F020F06230710551F008959BB180E1A1 +:10434000892707C095B18EEF892785B908958BB16C +:1043500080588BB9089541E00C94782140E00C948A +:104360007821CF93DF93EC0160E070E00E94AE21F2 +:1043700061E070E0CE010E94AE2162E070E0CE010B +:104380000E94AE21209A8AB180698AB9DF91CF91CB +:104390000895CF93DF93EC0160E070E00E94AE21BE +:1043A00061E070E0CE010E94AE2162E070E0CE01DB +:1043B0000E94AE2120988AB18F768AB9DF91CF9181 +:1043C0000895CF93DF93EC01613009F43FC058F1B9 +:1043D000623009F44EC0633009F064C060E070E000 +:1043E0000E94AB2161E070E0CE010E94AB2162E04F +:1043F00070E0CE010E94AB2189E196E09F938F93FC +:104400000E94C62D68EB7BE080E090E00E941306DE +:1044100060E070E0CE010E94AE2161E070E0CE016C +:104420000E94AE2136C060E070E00E94AB2188E2BD +:1044300096E09F938F930E94C62D68EB7BE080E00F +:1044400090E00E94130660E070E025C061E070E03B +:104450000E94AB2182E296E09F938F930E94C62D2B +:1044600068EB7BE080E090E00E94130661E070E082 +:1044700012C062E070E00E94AB218DE196E09F9354 +:104480008F930E94C62D68EB7BE080E090E00E9455 +:10449000130662E070E0CE010E94AE210F900F90F3 +:1044A00080E001C08FEFDF91CF91089508958FEFE5 +:1044B000089580E396E00895ECEBF0E08081806859 +:1044C0008083089560FF02C05C9A01C05C9861FF20 +:1044D00002C0289A01C0289862FF02C05F9A01C0FA +:1044E0005F9863FF02C05E9A01C05E9864FF02C0DD +:1044F0002A9A01C02A9865FF02C02B9A01C02B9806 +:1045000066FF02C02C9A01C02C9867FF02C02D9A4A +:1045100001C02D9880915E04813019F0823061F0E5 +:10452000089570FF02C05B9A01C05B9871FF02C0E2 +:104530005A9A08955A98089570FF02C0429A01C08D +:10454000429871FF02C0439A08954398089580915C +:104550005E04813019F08230B1F0089560FF02C02E +:10456000409A01C0409861FF02C0419A01C0419841 +:1045700062FF02C0429A01C0429863FF02C0439AA0 +:1045800008954398089560FF02C05D9A01C05D9848 +:1045900061FF02C0299A01C0299862FF02C05B9A9C +:1045A00001C05B9863FF02C05A9A08955A98089513 +:1045B000CF93DF93EC0181E08A8360E070E0CE016D +:1045C0000E94622260E0CE010E94A72280915E04D8 +:1045D000813059F0823091F484B18F6384B987B10E +:1045E0008E6087B98AB18C6F08C084B18F6384B93B +:1045F00087B18F6087B98AB18C6D8AB9DF91CF910D +:104600000895CF93DF93EC011A8260E070E00E947E +:10461000622260E0CE010E94A72280915E04813078 +:1046200059F0823091F484B1807C84B987B1817F64 +:1046300087B98AB1837008C084B1807C84B987B19E +:10464000807F87B98AB183728AB9DF91CF9108954B +:1046500080915E04813019F0823039F0089566232C +:1046600011F029980895299A0895662311F0419828 +:104670000895419A0895CF92DF92EF92FF920F939F +:104680001F93CF93DF937C01611117C06FE00E94ED +:10469000A7226FEF73E0C7010E94622261E0C701A9 +:1046A0000E9428238DE596E09F938F930E94C62D4C +:1046B00060ED77E080E090E028C0613069F489E542 +:1046C00096E09F938F930E94C62D68EE73E080E082 +:1046D00090E00E94130620C0623039F460E071E07F +:1046E0000E94622280E596E008C06330C1F460E079 +:1046F00072E00E94622287E496E09F938F930E946B +:10470000C62D68EE73E080E090E00E94130660E042 +:1047100070E0C7010E9462220F900F9044C0643283 +:1047200008F043C0C62FD0E024978E0183E0159592 +:1047300007958A95E1F7C770DD27CC24C394D12C67 +:10474000B601002E01C0660F0A94EAF7C7010E9465 +:10475000A7220C2E02C0CC0CDD1C0A94E2F7B60195 +:10476000C7010E946222DF92CF92CC0FDD1FC05E94 +:10477000DE4F89818F9388818F931F930F9382E3FC +:1047800096E09F938F930E94C62D60E971E080E0D0 +:1047900090E00E9413068DB79EB708960FB6F89466 +:1047A0009EBF0FBE8DBF80E001C08FEFDF91CF9124 +:1047B0001F910F91FF90EF90DF90CF90089587B1F8 +:1047C000807F87B988B18F6088B9089588B1807F6C +:1047D00088B987B1807F87B908956130710581F00C +:1047E00058F06230710581F063307105A1F486B133 +:1047F00083FB882780F90CC086B18095817008956D +:1048000086B18695817004C086B182FB882780F9C5 +:1048100091E08927089580E008950F931F93CF9327 +:10482000DF93603108F04EC08C01C62FC695C69547 +:10483000D0E06370613021F0633009F44BC021C0D7 +:10484000BE010E94ED23811145C0CE0101969F93C8 +:104850008F9383E796E09F938F930E94C62D0F90CE +:104860000F900F900F90BE01C8010E94ED2381119F +:104870002BC060E070E0CB010E941306019621F589 +:10488000F2CFBE010E94ED23882321F1CE010196D3 +:104890009F938F9385E696E09F938F930E94C62DFA +:1048A0000F900F900F900F90BE01C8010E94ED2352 +:1048B000882351F060E070E0CB010E94130601965E +:1048C00019F4F2CF8FEF07C06AE070E080E090E06B +:1048D0000E94130680E0DF91CF911F910F91089500 +:1048E00008958FEF089508950F931F93CF93DF934B +:1048F000EC018B0188E791E099838883CE010496CF +:104900000E94B807CE01CD960E940111CE018758B2 +:104910009F4F0E947203CE0185589F4F0E94D8047A +:10492000FE01E057FF4F10821B830A83DF91CF9176 +:104930001F910F910895CF93DF93CDB7DEB7A09766 +:104940000FB6F894DEBF0FBECDBF259A2D9882E03A +:104950008093C00098E99093C10096E09093C200C4 +:104960001092C50093E39093C4008093B0008093AD +:10497000B10096E99093B3008093700080E191E0DC +:104980009093B7048093B60482E091E09093B504CD +:104990008093B40478948AE1E0E3F1E0DE011196BB +:1049A00001900D928A95E1F70E94AF0507ED11E0A5 +:1049B000F9EDEF2EF1E0FF2E6E012BE1C20ED11CBE +:1049C0001E013FE1230E311C6AE5462E61E0562EA2 +:1049D0007DE0672E72E0772EEDE4AE2EE1E0BE2E94 +:1049E0001F930F930E94C62DFF92EF920E94C62D37 +:1049F00082E092E09F938F930E94C62D2EE531E0D6 +:104A00003F932F930E94C62DA6E1B2E0BF93AF93D0 +:104A10000E94C62D5F924F920E94C62D7F926F9288 +:104A20000E94C62DFF92EF920E94C62D80915E04D7 +:104A30009FEF980F0FB6F894DEBF0FBECDBF923038 +:104A4000C8F40E94A2059F938F93BF92AF920E94D9 +:104A5000C62DFF92EF920E94C62D1F930F930E94C6 +:104A6000C62D8AE391E09F938F930E94C62D18A2D2 +:104A70001F8E0DC01F928F938DE191E09F938F93B6 +:104A80000E94C62D0F900F900F900F90FFCF0FB682 +:104A9000F894DEBF0FBECDBF8F8D98A18D309105EC +:104AA00048F5FC01EE0FFF1FA1E0B0E0AC0FBD1F09 +:104AB000EA0FFB1F808091809F938F9324E131E068 +:104AC0003F932F930E94C62DD401ED91FC91068057 +:104AD000F781E02DC40109959F938F930E94C62D05 +:104AE0001F930F930E94C62D8F8D98A1019698A3B6 +:104AF0008F8FCDCF85E091E09F938F930E94C62D3D +:104B000010923504109234044091B4045091B504CD +:104B100064E070E0C6010E945E2D3F922F9280E516 +:104B200091E09F938F93DF92CF920E94EC2D0FB66E +:104B3000F894DEBF0FBECDBF019709F051CF8F8D26 +:104B400098A18D30910508F04BCF880F991FE1E0B7 +:104B5000F0E0EC0FFD1FE80FF91FA080B18081E0AD +:104B600091E09F938F930E94C62DD501ED91FC910A +:104B70000680F781E02DC50109959F938F930E94D0 +:104B8000C62D8DEF90E09F938F930E94C62D8FEFDF +:104B90009FEF9093010180930001D501ED91FC916D +:104BA0000280F381E02DC50109950F900F900F90C1 +:104BB0000F900F900F90812C912C36EF632E30E0E8 +:104BC000732E44244A94542C9F928F927F926F921A +:104BD0000E94C62DD501ED91FC910190F081E02D50 +:104BE000682DC50109950F900F900F900F9087FDCC +:104BF00018C080910001909101014B9739F48FEF1B +:104C00009FEF90930101809300010BC0509201012E +:104C100040920001BFEF8B1A9B0A2FEF821691047E +:104C200099F6D501ED91FC910480F581E02DC50147 +:104C30000995CACE8CE991E09093330480933204B5 +:104C400089E192E0909331048093300484EE91E006 +:104C500090932F0480932E048CEF91E090932C047A +:104C600080932B0410922D048CEC91E090932A04F5 +:104C7000809329048AE691E090932604809325048A +:104C8000109228041092270488ED91E09093240458 +:104C90008093230484EB91E090931F0480931E047F +:104CA00010922004109222041092210480EC91E0D2 +:104CB00090931D0480931C0480E991E09093190463 +:104CC0008093180481E090915E04913009F480E0B3 +:104CD00080931A0410921B0485E292E090931604CC +:104CE000809315041092170488EA91E090930204CF +:104CF00080930104109203041092040484E891E06C +:104D00009093FD038093FC031092FE038FEF9FEFBF +:104D1000909300048093FF0360E070E08BE693E0E3 +:104D20000E94742461E070E08AED92E00E94742495 +:104D300062E070E089E492E00E94742480EF91E0E8 +:104D4000909343028093420284E492E00E947203B3 +:104D50001092460210924802109247028EE591E0AE +:104D600090933902809338021092400221E030E0A3 +:104D700030933F0220933E0210923A0210923B027F +:104D800010923C0210923D0290932F0280932E02CB +:104D90001092360282E090E09093350280933402C4 +:104DA00010923002109231021092320210923302AD +:104DB00008958CE694E00E94B80788E191E0909312 +:104DC0006B0480936A0490936904809368049093C1 +:104DD000670480936604089582E592E0089580E078 +:104DE00094E0089587E394E0089588E494E00895BA +:104DF0008CE494E008958AED94E0089580EA95E0CB +:104E000008958CEC95E0089585E196E008958CE294 +:104E100096E0089580E696E008958EE796E008957E +:104E200085E896E00895DB018F939F930E946227A7 +:104E3000BF91AF91A29F800D911DA39F900DB29F36 +:104E4000900D11240895991B79E004C0991F9617BD +:104E500008F0961B881F7A95C9F780950895AA1BBC +:104E6000BB1B51E107C0AA1FBB1FA617B70710F055 +:104E7000A61BB70B881F991F5A95A9F78095909587 +:104E8000BC01CD010895052E97FB1EF400940E94ED +:104E90005A2757FD07D00E94062907FC03D04EF47D +:104EA0000C945A2750954095309521953F4F4F4F80 +:104EB0005F4F089590958095709561957F4F8F4FC6 +:104EC0009F4F08950E942E29A59F900DB49F900D8D +:104ED000A49F800D911D11240895B7FF0C946227A3 +:104EE0000E946227821B930B0895DF93CF931F9339 +:104EF0000F939A9DF02D219FF00D8B9DF00D8A9DB3 +:104F0000E02DF10D039FF00D029FE00DF11D4E9D70 +:104F1000E00DF11D5E9DF00D4F9DF00D7F936F93A1 +:104F2000BF92AF925F934F93D5010E942E298B01C0 +:104F3000AC01D7010E942E29EB01E80FF91FD60121 +:104F40000E94C5272F913F91D6010E942E29C60F9E +:104F5000D71FE81FF91FAF91BF910E94C5272F915E +:104F60003F910E942E29C60FD71FE81FF91FD601B7 +:104F70000E942E29E60FF71F9801BE01CF011124D0 +:104F80000F911F91CF91DF9108950E942E29460F16 +:104F9000571FC81FD91F08F431960895689401C09F +:104FA000E894F92FF12B12F00C940228A0E0B0E065 +:104FB000ECEDF7E20C947428092E059422F40E947B +:104FC0005E28112392F4F0E80F26FFEFE094F094AE +:104FD00000951095B094C094D094A194BF0ACF0AC4 +:104FE000DF0AEF0AFF0A0F0B1F0B0E940D2807FCB8 +:104FF0000E945E28CDB7DEB7ECE00C949028689450 +:1050000001C0E8948F929F92CF93DF930E940D2866 +:10501000DF91CF919F908F90089588249924F40177 +:10502000E401B0E49F93AA279A158B049C04ED0534 +:10503000FE05CF05D007A10798F4AD2FDC2FCF2FA9 +:10504000FE2FE92D982C892E982F872F762F652FEC +:10505000542F432F322F2227B85031F7BF9127C04A +:105060001B2EBF91BB27220F331F441F551F661FE6 +:10507000771F881F991F881C991CEE1FFF1FCC1FCC +:10508000DD1FAA1FBB1F8A149B04EC05FD05CE057E +:10509000DF05A007B10748F08A189B08EC09FD0955 +:1050A000CE09DF09A00BB10B21601A94E1F62EF4B2 +:1050B0009401AF01BE01CD01000C0895609570957B +:1050C0008095909530954095509521953F4F4F4F45 +:1050D0005F4F6F4F7F4F8F4F9F4F08952F923F929B +:1050E0004F925F926F927F928F929F92AF92BF92F8 +:1050F000CF92DF92EF92FF920F931F93CF93DF93A4 +:10510000CDB7DEB7CA1BDB0B0FB6F894DEBF0FBE00 +:10511000CDBF09942A88398848885F846E847D844D +:105120008C849B84AA84B984C884DF80EE80FD804F +:105130000C811B81AA81B981CE0FD11D0FB6F894C5 +:10514000DEBF0FBECDBFED0108950F93083090F084 +:10515000982F872F762F652F542F432F322F2227FA +:105160000850F4CF220F331F441F551F661F771FAF +:10517000881F991F0A95B2F70F91089597FB10F8B1 +:10518000169400080F93083098F00850232F342FFE +:10519000452F562F672F782F892F902DF4CF059408 +:1051A000979587957795679557954795379527955F +:1051B0000A95AAF70F9108952A0D3B1D4C1D5D1D00 +:1051C0006E1D7F1D801F911F08950024A7FD009470 +:1051D0002A0F301D401D501D601D701D801D901D2B +:1051E00008952A193B094C095D096E097F09800B56 +:1051F000910B08950024A7FD00942A17300540055F +:10520000500560057005800590050895A1E21A2EED +:10521000AA1BBB1BFD010DC0AA1FBB1FEE1FFF1F5A +:10522000A217B307E407F50720F0A21BB30BE40BAA +:10523000F50B661F771F881F991F1A9469F76095F1 +:105240007095809590959B01AC01BD01CF010895AB +:10525000EE0FFF1F0590F491E02D0994A29FB0017D +:10526000B39FC001A39F700D811D1124911DB29F9A +:10527000700D811D1124911D08955058BB27AA2738 +:105280000E9455290C94FA2A0E94EC2A38F00E94B8 +:10529000F32A20F039F49F3F19F426F40C94D92A0C +:1052A0000EF4E095E7FB0C94D32AE92F0E940B2B18 +:1052B00058F3BA17620773078407950720F079F44B +:1052C000A6F50C942D2B0EF4E0950B2EBA2FA02DE5 +:1052D0000B01B90190010C01CA01A0011124FF27A3 +:1052E000591B99F0593F50F4503E68F11A16F0409E +:1052F000A22F232F342F4427585FF3CF469537959D +:105300002795A795F0405395C9F77EF41F16BA0B61 +:10531000620B730B840BBAF09150A1F0FF0FBB1F0F +:10532000661F771F881FC2F70EC0BA0F621F731F58 +:10533000841F48F4879577956795B795F7959E3FB5 +:1053400008F0B0CF9395880F08F09927EE0F979546 +:10535000879508950E94BE290C94FA2A0E94F32A88 +:1053600058F00E94EC2A40F029F45F3F29F00C9499 +:10537000D32A51110C942E2B0C94D92A0E940B2B5A +:1053800068F39923B1F3552391F3951B550BBB2774 +:10539000AA2762177307840738F09F5F5F4F220FB9 +:1053A000331F441FAA1FA9F335D00E2E3AF0E0E8B0 +:1053B00032D091505040E695001CCAF72BD0FE2FFA +:1053C00029D0660F771F881FBB1F2617370748078E +:1053D000AB07B0E809F0BB0B802DBF01FF27935846 +:1053E0005F4F3AF09E3F510578F00C94D32A0C940D +:1053F0002E2B5F3FE4F3983ED4F38695779567951F +:10540000B795F7959F5FC9F7880F911D969587957A +:1054100097F90895E1E0660F771F881FBB1F621799 +:1054200073078407BA0720F0621B730B840BBA0B57 +:10543000EE1F88F7E09508950E94232A6894B11121 +:105440000C942E2B08950E94132B88F09F5798F0F0 +:10545000B92F9927B751B0F0E1F0660F771F881F79 +:10546000991F1AF0BA95C9F714C0B13091F00E9493 +:105470002D2BB1E008950C942D2B672F782F8827C2 +:10548000B85F39F0B93FCCF3869577956795B395BA +:10549000D9F73EF490958095709561957F4F8F4F29 +:1054A0009F4F089597FB16F40E94DC2A0C94962ACD +:1054B000E89409C097FB3EF49095809570956195AE +:1054C0007F4F8F4F9F4F9923A9F0F92F96E9BB2764 +:1054D0009395F695879577956795B795F111F8CFE0 +:1054E000FAF4BB0F11F460FF1BC06F5F7F4F8F4F4B +:1054F0009F4F16C0882311F096E911C0772321F041 +:105500009EE8872F762F05C0662371F096E8862FD8 +:1055100070E060E02AF09A95660F771F881FDAF72F +:10552000880F9695879597F90895E894F92F96EB4B +:10553000FF2381F0121613061406440B9395F6957B +:1055400087957795679557954040FF23B9F71BC01E +:1055500099270895882351F49850D2F7872B762FF6 +:10556000652F542F432F322F20E0B1F3121613066C +:105570001406440B88233AF09A95440F551F661F72 +:10558000771F881FCAF755234AF4440F551F11F49B +:1055900060FF04C06F5F7F4F8F4F9F4F880F9695BE +:1055A000879597F9089597F99F6780E870E060E024 +:1055B00008959FEF80EC0895909580957095609583 +:1055C00050954095309521953F4F4F4F5F4F6F4F0E +:1055D0007F4F8F4F9F4F089500240A941616170689 +:1055E00018060906089500240A94121613061406D4 +:1055F00005060895092E0394000C11F4882352F037 +:10560000BB0F40F4BF2B11F460FF04C06F5F7F4FEE +:105610008F4F9F4F089557FD9058440F551F59F0D5 +:105620005F3F71F04795880F97FB991F61F09F3F8F +:1056300079F087950895121613061406551FF2CFB8 +:105640004695F1DF08C0161617061806991FF1CF08 +:1056500086957105610508940895E894BB2766272F +:105660007727CB0197F908950E94472B0C94FA2ACB +:105670000E94EC2A38F00E94F32A20F0952311F0C2 +:105680000C94D32A0C94D92A11240C942E2B0E940A +:105690000B2B70F3959FC1F3950F50E0551F629F40 +:1056A000F001729FBB27F00DB11D639FAA27F00D7B +:1056B000B11DAA1F649F6627B00DA11D661F829FA2 +:1056C0002227B00DA11D621F739FB00DA11D621F87 +:1056D000839FA00D611D221F749F3327A00D611DA4 +:1056E000231F849F600D211D822F762F6A2F112486 +:1056F0009F5750409AF0F1F088234AF0EE0FFF1FB9 +:10570000BB1F661F771F881F91505040A9F79E3F0F +:10571000510580F00C94D32A0C942E2B5F3FE4F3B8 +:10572000983ED4F3869577956795B795F795E79565 +:105730009F5FC1F7FE2B880F911D9695879597F96E +:105740000895FA01EE0FFF1F309621053105A1F1F2 +:105750006115710561F48038BFE39B0749F16894D6 +:105760009038810561F08038BFEF9B0741F09923A5 +:105770004AF5FF3FE1053105210519F1E894089448 +:10578000E795D901AA2329F4AB2FBE2FF85FD0F3F8 +:1057900010C0FF5F70F4A695E0F7F73950F019F0EC +:1057A000FF3A38F49F779F930DD00F9007FC9058E5 +:1057B000089546F00C94D92A60E070E080E89FE3F9 +:1057C00008954FE79F775F934F933F932F930E94E6 +:1057D000C52C2F913F914F915F910E94342B0C94D7 +:1057E000FE2B0E94302C880B990B089529F416F09B +:1057F0000C94D32A0C942D2B0C94D92A0E94132B91 +:10580000A8F39638A0F707F80F92E8942BE33AEA4A +:1058100048EB5FE70E944A2B0F920F920F924DB711 +:105820005EB70F920E940D2DE8E6F0E00E94542C26 +:105830004F915F91EF91FF91E595EE1FFF1F49F0AA +:10584000FE57E0684427EE0F441FFA95E1F74195B3 +:10585000550B0E94872C0F9007FE0C947B2C08950B +:10586000990F0008550FAA0BE0E8FEEF1616170671 +:10587000E807F907C0F012161306E407F50798F0D9 +:10588000621B730B840B950B39F40A2661F0232BF2 +:10589000242B252B21F408950A2609F4A140A6956E +:1058A0008FEF811D811D0895DF93CF931F930F9379 +:1058B000FF92EF92DF927B018C01689406C0DA2E92 +:1058C000EF010E94472BFE01E894A59125913591A7 +:1058D00045915591A6F3EF010E945529FE019701CC +:1058E000A801DA9469F7DF90EF90FF900F911F9174 +:1058F000CF91DF9108959B01AC0160E070E080E8FA +:105900009FE30C94AA290C94D32A0C94412D0E9455 +:10591000132BD8F39923C9F3940F511DA3F391507E +:10592000504094F059F0882332F0660F771F881F9B +:1059300091505040C1F79E3F51052CF7880F911DA3 +:105940009695879597F908955F3FACF0983E9CF047 +:10595000BB27869577956795B79508F4B1609395C1 +:10596000C1F7BB0F58F711F460FFE8CF6F5F7F4FAF +:105970008F4F9F4FE3CF0C942E2B16F00C94412D9C +:105980000C94D92A68940C94D32A0E94132BA8F360 +:105990009923C1F3AEF3DF93CF931F930F93FF923D +:1059A000C92FDD2788232AF02197660F771F881FCC +:1059B000DAF720E030E040E85FEB9FE3883920F041 +:1059C000803E38F021968F770E943E29E0E9F0E092 +:1059D00004C00E943E29EDEBF0E00E94542C8B01A4 +:1059E000BE01EC01FB2E6F5771097595771F880B6F +:1059F000990B0E945A2A28E132E741E35FE30E94B3 +:105A0000472BAF2D9801AE01FF900F911F91CF91C1 +:105A1000DF910E9455290C94FA2AFA01DC01AA0FA1 +:105A2000BB1F9B01AC01BF5728F422273327442713 +:105A3000507820C0B75190F4AB2F0024469537958D +:105A40002795011CA395D2F3002071F0220F331F7C +:105A5000441FB395DAF30ED00C943D2961307105E3 +:105A6000A0E88A07B94630F49B01AC016627772786 +:105A700088279078309621F02083318342835383A6 +:105A800008959F3F31F0915020F487957795679561 +:105A9000B795880F911D9695879597F90895FB0105 +:105AA000DC014150504048F001900D920020C9F7B0 +:105AB00001C01D9241505040E0F70895A0E0B0E0D1 +:105AC000E4E6FDE20C947828FA01238120FD03C06E +:105AD00080E090E01AC016161706D4F77A018C0100 +:105AE000EB016C01C130D10569F0C7010E94BD32E4 +:105AF0008F3FFFEF9F0761F3F60181936F012197BD +:105B00000A9781F7F6011082C801CDB7DEB7E8E049 +:105B10000C9494280F931F93CF93DF93FB01238161 +:105B200021FD03C08FEF9FEF2CC022FF16C04681DE +:105B30005781248135814217530744F4A081B181F4 +:105B40009D012F5F3F4F318320838C9326813781C6 +:105B50002F5F3F4F3783268314C08B01EC01FB017D +:105B60000084F185E02D0995892BE1F6D801169680 +:105B70008D919C911797019617969C938E931697EB +:105B8000CE01DF91CF911F910F910895A0E0B0E079 +:105B9000ECECFDE20C947C28AE01495F5F4FDA012A +:105BA0006D917D91AD0104EB14E0F8018281938148 +:105BB000DC0113962C911397286013962C930E9466 +:105BC000052ED8011296ED91FC9113972381277F22 +:105BD0002383E4E00C949828AEE0B0E0E2EFFDE22D +:105BE0000C947E2885E08C838B899C899A83898399 +:105BF000AE01495E5F4F6D897E89CE0101960E949C +:105C000082312E96E2E00C949A28ABE0B0E0EBE013 +:105C1000FEE20C946E286C017B018A01FC01178264 +:105C20001682838181FFCCC1CE0101963C01F60131 +:105C30009381F70193FD859193FF81917F018823E3 +:105C400009F4BAC1853239F493FD859193FF8191AE +:105C50007F01853229F4B60190E00E948A2DE7CFBA +:105C6000912C212C312CFFE1F315D8F08B3279F0F7 +:105C700038F4803279F08332A1F4232D20611DC0E5 +:105C80008D3261F0803369F4232D216016C0832D9D +:105C90008260382EE32DE4603E2E2AC0F32DF8609A +:105CA0001DC037FC2DC020ED280F2A3040F08E3269 +:105CB000B9F436FC81C1232D2064322E19C036FE82 +:105CC00006C08AE0989E200D1124922E11C0EAE0B1 +:105CD0002E9E200D1124222EF32DF0623F2E08C09F +:105CE0008C3621F4832D8068382E02C0883641F42A +:105CF000F70193FD859193FF81917F018111B3CFCE +:105D0000982F9F7D9554933028F40C5F1F4F9FE38D +:105D100099830DC0833631F0833771F0833509F0F4 +:105D200059C021C0F801808189830E5F1F4F8824EC +:105D30008394912C530113C02801F2E04F0E511CA3 +:105D4000F801A080B18036FE03C0692D70E002C06A +:105D50006FEF7FEFC5010E94B2324C018201F32D3B +:105D6000FF773F2E16C0280122E0420E511CF80199 +:105D7000A080B18036FE03C0692D70E002C06FEFD5 +:105D80007FEFC5010E94A7324C01F32DF0683F2E32 +:105D9000820133FC1BC0822D90E088169906B0F476 +:105DA000B60180E290E00E948A2D2A94F4CFF5019A +:105DB00037FC859137FE81915F01B60190E00E942A +:105DC0008A2D21102A9421E0821A910881149104CD +:105DD00071F7E8C0843611F0893641F5F80137FED5 +:105DE00007C060817181828193810C5F1F4F08C061 +:105DF00060817181072E000C880B990B0E5F1F4F7D +:105E0000F32DFF763F2E97FF09C0909580957095F2 +:105E100061957F4F8F4F9F4FF0683F2E2AE030E013 +:105E2000A3010E941433882E861845C0853731F4AB +:105E3000232D2F7EB22E2AE030E025C0932D997FAE +:105E4000B92E8F36C1F018F4883579F0B5C0803797 +:105E500019F0883721F0B0C0E92FE061BE2EB4FE02 +:105E60000DC0FB2DF460BF2E09C034FE0AC0292FDF +:105E70002660B22E06C028E030E005C020E130E008 +:105E800002C020E132E0F801B7FE07C060817181F5 +:105E9000828193810C5F1F4F06C06081718180E019 +:105EA00090E00E5F1F4FA3010E941433882E8618C6 +:105EB000FB2DFF773F2E36FE0DC0232D2E7FA22E09 +:105EC000891458F434FE0BC032FC09C0832D8E7E39 +:105ED000A82E05C0B82CA32C03C0B82C01C0B92C27 +:105EE000A4FE0FC0FE01E80DF11D8081803321F476 +:105EF0009A2D997EA92E09C0A2FE06C0B394B39430 +:105F000004C08A2D867809F0B394A3FC11C0A0FECA +:105F100006C0B21488F4280C922C9B180EC0B21440 +:105F200060F4B60180E290E00E948A2DB394F7CF2E +:105F3000B21418F42B1802C0982C212CA4FE10C007 +:105F4000B60180E390E00E948A2DA2FE17C0A1FC5A +:105F500003C088E790E002C088E590E0B6010CC07D +:105F60008A2D867859F0A1FE02C08BE201C080E242 +:105F7000A7FC8DE2B60190E00E948A2D891438F4C6 +:105F8000B60180E390E00E948A2D9A94F7CF8A941C +:105F9000F301E80DF11D8081B60190E00E948A2D89 +:105FA0008110F5CF222009F442CEB60180E290E0C4 +:105FB0000E948A2D2A94F6CFF6018681978102C02D +:105FC0008FEF9FEF2B96E2E10C948A2820FD09C009 +:105FD000FC0123FD05C022FF02C07383628351834D +:105FE0004083089544FD17C046FD17C0AB01BC01B6 +:105FF000DA01FB01AA0FBB1FEE1FFF1F1094D1F7A0 +:106000004A0F5B1F6E1F7F1FCB01BA01660F771F00 +:10601000881F991F09C033E001C034E0660F771F65 +:10602000881F991F3150D1F7620F711D811D911D7D +:1060300008950F931F93CF93DF938C01C8010E94A3 +:10604000BD32EC0197FD08C00E949332892BB1F755 +:10605000B801CE010E94FB32CE01DF91CF911F919A +:106060000F9108958F929F92AF92BF92EF92FF92FD +:106070000F931F93CF93DF938C01D62F7A01B22E0B +:106080000E94BD329C0133272B32310531F02D3275 +:10609000310561F48B2D8068B82ED15011F480E069 +:1060A00068C0C8010E94BD3297FDF9CFCB2DCD7FCE +:1060B0002B2D207309F58033F9F4AA24AA94AD0E90 +:1060C00009F443C0C8010E94BD3297FD3EC09C0147 +:1060D0002F7D33272835310549F4C264D250A9F108 +:1060E000C8010E94BD3297FF07C02FC0B6FE02C094 +:1060F000C26001C0C261DA2D812C912C540120EDC7 +:10610000280F283080F0C4FF04C0B8010E94FB3281 +:1061100019C02A3040F0C6FFF8CF2F7D3FEE320F76 +:10612000363098F727504C2FC501B4010E94F22F4A +:106130004B015C01C260D15059F0C8010E94BD32D0 +:1061400097FFDDCFC1FD04C0AACF812C912C540153 +:10615000C7FF08C0B094A09490948094811C911CB7 +:10616000A11CB11C2C2FB501A401C7010E94E62F70 +:1061700081E0DF91CF911F910F91FF90EF90BF9041 +:10618000AF909F908F900895A0E2B0E0EAECF0E32A +:106190000C9471285C01962E7A01F9018E010F5F33 +:1061A0001F4F680180E2D8011D928A95E9F7D50159 +:1061B00013968C9080E090E0612C712C30E061E0CF +:1061C00070E083FC259183FE21918F01522E2111D5 +:1061D00003C080E090E092C02E3511F4009751F199 +:1061E000432F50E0481759073CF42D3559F12D3213 +:1061F00019F4772009F103C0772009F46AC0452D0E +:10620000469546954695D601A40FB11D452D47707C +:106210008B0102C0000F111F4A95E2F7A8015C91A3 +:10622000452B4C93651459F0561410F45394E7CF52 +:106230005A94E5CF31E004C07724739401C0712CE7 +:106240000196BFCF772019F08E8180628E83311145 +:1062500003C08824839417C0F6019E012F5D3F4F31 +:106260008081809581932E173F07D1F7F2CFE114FB +:10627000F10429F0D7018C93F70131967F019A94AC +:10628000812C9920F9F0C5010E94BD3297FD18C0FC +:10629000FC01FF2723E0F595E7952A95E1F7EC0D42 +:1062A000FD1D208130E0AC014770552702C03595B7 +:1062B00027954A95E2F720FDDACFB5010E94FB321F +:1062C000811087CFE114F10411F0D7011C92C801AD +:1062D00015C0422F469546954695D601A40FB11D8F +:1062E000422F47708B0102C0000F111F4A95E2F741 +:1062F000A8015C91452B4C93622EA2CFA096EFE0B3 +:106300000C948D28A0E0B0E0E8E8F1E30C9471284B +:106310006C01EB015A01FC0117821682512CF60127 +:10632000E380FE01E3FC8591E3FE8191182FEF01EC +:10633000882309F4EEC090E00E949332892B21F06B +:10634000C6010E941930EBCF153241F4FE01E3FC87 +:106350001591E3FE1191EF01153281F4C6010E94FF +:10636000BD3297FDD4C0412F50E09C013327241744 +:106370003507A9F2B6010E94FB32CBC01A3239F4BC +:10638000E3FC1591E3FE1191EF0101E001C000E093 +:10639000F12C20ED210F2A3080F402606F2D70E087 +:1063A00080E090E040E20E94F22FF62EFE01E3FC36 +:1063B0001591E3FE1191EF01ECCF01FF03C0F11045 +:1063C00003C0A7C0FF24FA94183619F01C3651F008 +:1063D00010C0FE01E3FC1591E3FE1191EF011836A8 +:1063E00041F408600460FE01E3FC1591E3FE1191A5 +:1063F000EF01112309F48DC0612F70E08AEE90E067 +:106400000E949C32892B09F484C000FD07C0F5016D +:1064100080809180C50102965C0102C0812C912C84 +:106420001E3651F4F6014681578160E070E0202F5E +:10643000C4010E94E62F73CF1336A9F401FD02C0F8 +:10644000FF24F394C6010E94BD3297FD60C0811401 +:10645000910429F0F4018083C40101964C01FA945F +:10646000F110F0CF50C01B3559F49E01A4016F2DDF +:10647000C6010E94C430EC01892B09F044C03EC023 +:10648000C6010E94193097FD42C01F3661F128F401 +:10649000143639F1193651F128C0133771F0153718 +:1064A00001F123C08114910429F0F4016082C40138 +:1064B00001964C01FA94FF2071F0C6010E94BD3292 +:1064C0003C0197FD08C00E949332892B59F3B60115 +:1064D000C3010E94FB3281149104A9F0F4011082DF +:1064E00012C0006203C0006101C00064202FA4013B +:1064F0006F2DC6010E943230811105C0F6018381E3 +:10650000807329F406C000FD0ACF539408CF5520AC +:1065100019F0852D90E002C08FEF9FEFCDB7DEB769 +:10652000EFE00C948D2891110C947233803219F0A5 +:1065300089508550C8F70895FC010590061621F092 +:106540000020D9F7C00108953197CF010895FC01CB +:106550000590615070400110D8F7809590958E0F8E +:106560009F1F0895FC016150704001900110D8F701 +:10657000809590958E0F9F1F0895CF93DF93EC0128 +:106580002B8120FF33C026FF0AC02F7B2B838E81F7 +:106590009F8101969F838E838A8190E029C022FF8C +:1065A0000FC0E881F9818081082E000C990B0097BB +:1065B00019F420622B831AC03196F983E8830EC048 +:1065C000EA85FB85099597FF09C02B81019611F09B +:1065D00080E201C080E1822B8B8308C02E813F8145 +:1065E0002F5F3F4F3F832E83992702C08FEF9FEF8E +:1065F000DF91CF910895FB01238120FF12C026FD7A +:1066000010C08F3F3FEF930761F082832F7D20649E +:1066100023832681378121503109378326839927A7 +:1066200008958FEF9FEF0895FA01AA27283051F1BE +:10663000203181F1E8946F936E7F6E5F7F4F8F4FB3 +:106640009F4FAF4FB1E03ED0B4E03CD0670F781F12 +:10665000891F9A1FA11D680F791F8A1F911DA11DF7 +:106660006A0F711D811D911DA11D20D009F4689430 +:106670003F912AE0269F11243019305D3193DEF6D8 +:10668000CF010895462F4770405D4193B3E00FD08E +:10669000C9F7F6CF462F4F70405D4A3318F0495D79 +:1066A00031FD4052419302D0A9F7EACFB4E0A6955C +:1066B0009795879577956795BA95C9F7009761057E +:1066C000710508959B01AC010A2E069457954795D4 +:1066D00037952795BA95C9F7620F731F841F951FC9 +:0E66E000A01D0895992788270895F894FFCFEC +:1066EE00FFFF000000010000000000005A0500003E +:1066FE0000000002000000007B0500000000030304 +:10670E000402060208020A020C020E021002120213 +:10671E00320430042E042B042904250423041E0401 +:10672E001C041804DA0249026B03E903DE03D403E6 +:10673E00257800424D4532383000000000003415F7 +:10674E003315331536150000000051153A15461550 +:10675E00EC263F00000000001916F4150B16E31589 +:10676E00000000003C193B193B19EF260000000009 +:10677E00DC1B051B881BF22600000000B51C591CF3 +:10678E00621CF52600000000F91CF81CF81CF82607 +:10679E00000000003C1D1C1D051DFB260000000016 +:1067AE006A1FD41ECC1EFE26000000008520792014 +:1067BE008020012700000000D920CD20D4200427FE +:1067CE0000000000E121B121C921072700000000CF +:1067DE005722562256225922000000003B23D8226F +:1067EE0001230A27410042004300440045004600B1 +:1067FE004700445000000000000D24DF23E6230D67 +:0E680E00270000000071247024702410270061 +:00000001FF diff --git a/software/test-software/nano-328/src b/software/test-software/nano-328/src new file mode 120000 index 0000000..5cd551c --- /dev/null +++ b/software/test-software/nano-328/src @@ -0,0 +1 @@ +../src \ No newline at end of file diff --git a/software/test-software/nano-644/Makefile b/software/test-software/nano-644/Makefile new file mode 100644 index 0000000..75c25e3 --- /dev/null +++ b/software/test-software/nano-644/Makefile @@ -0,0 +1,262 @@ +$(shell mkdir -p dist >/dev/null) +$(shell mkdir -p build >/dev/null) +$(shell mkdir -p sim >/dev/null) +$(shell mkdir -p sim/build >/dev/null) +$(shell mkdir -p release/sim >/dev/null) + +# -------------------------------------------------------------------------------- +# Variables configured by engineer + +NAME=nano-x-base_test-software_nano-m644p_12mhz +DEVICE=atmega644p +AVRDUDE_DEVICE=m644p +CPU_FREQUENCY=12000000 +BAUDRATE=115200 +START_ADDRESS=0 + +# -------------------------------------------------------------------------------- +# Automatic created Makefile variables + +SRC= $(wildcard src/*.c src/*.cpp src/*/*.c src/*/*.cpp) +HDR= $(wildcard src/*.h src/*.hpp src/*/*.h src/*/*.hpp) +MAINSRC= $(wildcard src/main.c src/main.cpp) +OBJ_CPP = $(SRC:src/%.cpp=build/%.o) +OBJ = $(OBJ_CPP:src/%.c=build/%.o) +OBJ_SIM_CPP = $(SRC:src/%.cpp=sim/build/%.o) +OBJ_SIM = $(OBJ_SIM_CPP:src/%.c=sim/build/%.o) + +CC= avr-g++ +CFLAGS= -Wall -mmcu=$(DEVICE) -Os -DF_CPU=$(CPU_FREQUENCY) -DBAUD_RATE=$(BAUDRATE) -DDOUBLE_SPEED -DNUM_LED_FLASHES=4 '-DMAX_TIME_COUNT=F_CPU>>4' -c +#LFLAGS= -Wall -mmcu=$(DEVICE) -Os -DF_CPU=$(CPU_FREQUENCY) -Wl,-u,vfprintf -lprintf_flt -lm +LFLAGS= -Wall -mmcu=$(DEVICE) -Os -DF_CPU=$(CPU_FREQUENCY) -Wl,--section-start=.text=$(START_ADDRESS) + +CFLAGS_SIM= -Wall -mmcu=$(DEVICE) -Og -DF_CPU=$(CPU_FREQUENCY) -g -DBAUD_RATE=$(BAUDRATE) -DDOUBLE_SPEED -DNUM_LED_FLASHES=4 '-DMAX_TIME_COUNT=F_CPU>>4' -c +#LFLAGS_SIM= -Wall -mmcu=$(DEVICE) -Og -DF_CPU=$(CPU_FREQUENCY) -g -Wl,-u,vfprintf -lprintf_flt -lm +LFLAGS_SIM= -Wall -mmcu=$(DEVICE) -Og -DF_CPU=$(CPU_FREQUENCY) -g -Wl,--section-start=.text=$(START_ADDRESS) + +# -------------------------------------------------------------------------------- +# make targets + +.PHONY: all +all: dist/$(NAME).elf sim/$(NAME).elf dist/$(NAME).s dist/$(NAME).hex dist/$(NAME).bin sim/$(NAME).s info + +.PHONY: info +info: + @echo + @avr-size --mcu=$(DEVICE) --format=avr dist/$(NAME).elf + +# -------------------------------------------------------------------------------- +# dependency make for hierarchical source file structure + +.depend: $(SRC) $(HDR) + $(CC) -mmcu=$(DEVICE) -MM $(SRC) | sed --regexp-extended 's/^(.*\.o)\: src\/(.*)(\.cpp|\.c) (.*)/build\/\2\.o\: src\/\2\3 \4/g' > .depend + +ifneq (clean,$(filter clean,$(MAKECMDGOALS))) +-include .depend +endif + +# -------------------------------------------------------------------------------- +# elf, hex and assembler file creation + +dist/$(NAME).elf: .depend $(OBJ) + $(CC) $(LFLAGS) -o $@ $(OBJ) + +dist/%.s: dist/%.elf + avr-objdump -d $< > $@ + +dist/%.hex: dist/%.elf + avr-objcopy -O ihex $(HEX_FLASH_FLAGS) $< $@ + +dist/%.bin: dist/%.elf + avr-objcopy -O binary $(HEX_FLASH_FLAGS) $< $@ + +# -------------------------------------------------------------------------------- +# check if the macros __DATE__ or __TIME__ are used in src/main.cpp or src/main.c + +DATE_USED= +ifneq ($(shell cat $(MAINSRC) | grep __DATE__),) + DATE_USED=true +endif +TIME_USED= +ifneq ($(shell cat $(MAINSRC) | grep __TIME__),) + TIME_USED=true +endif + +ifeq (true, $(filter true, $(DATE_USED) $(TIME_USED))) +build/main.o: $(MAIN_SRC) $(SRC) $(HDR) + @mkdir -p $(dir $@) + $(CC) $(CFLAGS) -o $@ $< +endif + +# -------------------------------------------------------------------------------- + +build/%.o: src/%.c + @mkdir -p $(dir $@) + $(CC) $(CFLAGS) -o $@ $< + +build/%.o: src/%.cpp + @mkdir -p $(dir $@) + $(CC) $(CFLAGS) -o $@ $< + +# -------------------------------------------------------------------------------- +# simulation/debugging with gdb or simuc + +sim/$(NAME).elf: .depend $(OBJ_SIM) + $(CC) $(LFLAGS_SIM) -o $@ $(OBJ_SIM) + @ln -sf $(NAME).elf sim/$(DEVICE).elf + +sim/build/%.o: src/%.c + @mkdir -p $(dir $@) + $(CC) $(CFLAGS_SIM) -o $@ $< + +sim/build/%.o: src/%.cpp + @mkdir -p $(dir $@) + $(CC) $(CFLAGS_SIM) -o $@ $< + +sim/%.s: sim/%.elf + avr-objdump -d $< > $@ + +ifeq (m16, $(AVRDUDE_DEVICE)) +simuc: sim/$(NAME).elf + simuc --board sure $< +endif + +ifeq (m328p, $(AVRDUDE_DEVICE)) +simuc: sim/$(NAME).elf + simuc --board arduino $< +endif + +ifeq (m644p, $(AVRDUDE_DEVICE)) +simuc: sim/$(NAME).elf + simuc --board nano-644 $< +endif + +ifeq (m1284p, $(AVRDUDE_DEVICE)) +simuc: sim/$(NAME).elf + simuc --board nano-1284 $< +endif + +gdb: sim/$(NAME).elf + avr-gdb $< + +# ------------------------------------------------------------- +# flash to target with arduino bootloader in bootloader-section + +.PHONY: flash +flash: dist/$(NAME).elf all + avrdude -c arduino -P /dev/ttyUSB0 -b $(BAUDRATE) -p $(AVRDUDE_DEVICE) -e -U flash:w:$< + +.PHONY: flash0 +flash0: dist/$(NAME).elf all + avrdude -c arduino -P /dev/ttyUSB0 -b $(BAUDRATE) -p $(AVRDUDE_DEVICE) -e -U flash:w:$< + +.PHONY: flash1 +flash1: dist/$(NAME).elf all + avrdude -c arduino -P /dev/ttyUSB1 -b $(BAUDRATE) -p $(AVRDUDE_DEVICE) -e -U flash:w:$< + +.PHONY: flash2 +flash2: dist/$(NAME).elf all + avrdude -c arduino -P /dev/ttyUSB2 -b $(BAUDRATE) -p $(AVRDUDE_DEVICE) -e -U flash:w:$< + +.PHONY: flash-read +flash-read: + avrdude -c arduino -P /dev/ttyUSB0 -b $(BAUDRATE) -p $(AVRDUDE_DEVICE) -U flash:r:/tmp/flash.bin + +.PHONY: flash-disassemble +flash-disassemble: flash-read + avr-objdump -b binary -D -m avr5 /tmp/flash.bin > /tmp/flash.s + less /tmp/flash.s + +.PHONY: flash-hexdump +flash-hexdump: flash-read + hexdump -C /tmp/flash.bin | less + +# ---------------------------------------------- +# flash to target with fischl programming device + +.PHONY: isp-flash-$(AVRDUDE_DEVICE) +isp-$(AVRDUDE_DEVICE): + avrdude -c usbasp -p $(AVRDUDE_DEVICE) -U lock:r:-:h + avrdude -c usbasp -p $(AVRDUDE_DEVICE) + +.PHONY: isp-flash +isp-flash: dist/$(NAME).elf all + avrdude -c usbasp -p $(AVRDUDE_DEVICE) -e -U flash:w:$< + +.PHONY: isp-flash-$(AVRDUDE_DEVICE) +isp-flash-$(AVRDUDE_DEVICE): dist/$(NAME).elf all + avrdude -c usbasp -p $(AVRDUDE_DEVICE) -e -U flash:w:$< + +.PHONY: isp-read-flash-$(AVRDUDE_DEVICE) +isp-read-flash-$(AVRDUDE_DEVICE): + avrdude -c usbasp -p m32$(AVRDUDE_DEVICE)8p -U flash:r:/tmp/flash-arduino-atmega328p__$(shell date +"%Y-%m-%d_%H%M%S") + +.PHONY: isp-fuse +isp-fuse: isp-fuse-$(AVRDUDE_DEVICE) + +.PHONY: isp-fuse-$(AVRDUDE_DEVICE) +ifeq (m16, $(AVRDUDE_DEVICE)) +isp-fuse-$(AVRDUDE_DEVICE): + avrdude -c usbasp -p $(AVRDUDE_DEVICE) -U lfuse:w:0x18:m -U hfuse:w:0xD8:m -U lock:w:0xEF:m +endif +ifeq (m328p, $(AVRDUDE_DEVICE)) +isp-fuse-$(AVRDUDE_DEVICE): + avrdude -c usbasp -p $(AVRDUDE_DEVICE) -U lfuse:w:0xEF:m -U hfuse:w:0xD8:m -U efuse:w:0xFD:m -U lock:w:0xEF:m +endif +ifeq (m644p, $(AVRDUDE_DEVICE)) +isp-fuse-$(AVRDUDE_DEVICE): + avrdude -c usbasp -p $(AVRDUDE_DEVICE) -U lfuse:w:0xEF:m -U hfuse:w:0xD8:m -U efuse:w:0xFD:m -U lock:w:0xEF:m +endif +ifeq (m1284p, $(AVRDUDE_DEVICE)) +isp-fuse-$(AVRDUDE_DEVICE): + avrdude -c usbasp -p $(AVRDUDE_DEVICE) -U lfuse:w:0xEF:m -U hfuse:w:0xD8:m -U efuse:w:0xFD:m -U lock:w:0xEF:m +endif + +# -------------------------------------------------------- +# picocom sends CR for ENTER -> convert cr (\r) to lf (\n) + +.PHONY: picocom +picocom: + picocom -b $(BAUDRATE) --omap crlf --raise-dtr /dev/ttyUSB0 + +.PHONY: picocom0 +picocom0: + picocom -b $(BAUDRATE) --omap crlf --raise-dtr /dev/ttyUSB0 + +.PHONY: picocom1 +picocom1: + picocom -b $(BAUDRATE) --omap crlf --raise-dtr /dev/ttyUSB1 + +.PHONY: picocom2 +picocom2: + picocom -b $(BAUDRATE) --omap crlf --raise-dtr /dev/ttyUSB2 + +# -------------------------------------------------------- + +.PHONY: help +help: + @echo + @echo "Possible targets are:" + @echo " clean" + @echo " all help info" + @echo " flash flash0 flash1 flash2 flash-read flash-disassemble flash-hexdump" + @echo " isp-$(AVRDUDE_DEVICE) isp-flash-$(AVRDUDE_DEVICE) isp-fuse-$(AVRDUDE_DEVICE)" + @echo " picocom picocom0 picocom1 picocom2" + @echo " gdb simuc" + @echo + +# -------------------------------------------------------- + +.PHONY: release +release: dist/$(NAME).elf sim/$(NAME).elf dist/$(NAME).hex dist/$(NAME).bin + ../create-release release $(word 1, $^) release/sim $(word 2, $^) + +# -------------------------------------------------------- + +.PHONY: clean +clean: + @rm -r dist + @rm -r build + @rm -r sim + @find . -type f -name ".depend" -exec rm {} \; + @echo "clean done" diff --git a/software/test-software/nano-644/release/v2024-10-31_172630/nano-x-base_test-software_nano-m644p_12mhz.bin b/software/test-software/nano-644/release/v2024-10-31_172630/nano-x-base_test-software_nano-m644p_12mhz.bin new file mode 100755 index 0000000..d9c1b37 Binary files /dev/null and b/software/test-software/nano-644/release/v2024-10-31_172630/nano-x-base_test-software_nano-m644p_12mhz.bin differ diff --git a/software/test-software/nano-644/release/v2024-10-31_172630/nano-x-base_test-software_nano-m644p_12mhz.elf b/software/test-software/nano-644/release/v2024-10-31_172630/nano-x-base_test-software_nano-m644p_12mhz.elf new file mode 100755 index 0000000..2d5103b Binary files /dev/null and b/software/test-software/nano-644/release/v2024-10-31_172630/nano-x-base_test-software_nano-m644p_12mhz.elf differ diff --git a/software/test-software/nano-644/release/v2024-10-31_172630/nano-x-base_test-software_nano-m644p_12mhz.hex b/software/test-software/nano-644/release/v2024-10-31_172630/nano-x-base_test-software_nano-m644p_12mhz.hex new file mode 100644 index 0000000..f3ab251 --- /dev/null +++ b/software/test-software/nano-644/release/v2024-10-31_172630/nano-x-base_test-software_nano-m644p_12mhz.hex @@ -0,0 +1,2294 @@ +:100000000C942B070C9453070C9453070C94530730 +:100010000C9453070C9453070C9453070C945307F8 +:100020000C9453070C94410B0C9453070C945307F6 +:100030000C9453070C9453070C9453070C945307D8 +:100040000C9453070C9453070C9453070C945307C8 +:100050000C94910A0C9453070C9453070C94530777 +:100060000C9453070C9453070C94050B0C945307F2 +:100070000C94C40A0C9453070C945307076342363C +:10008000B79BD8A71A39685618AEBAAB558C1D3C29 +:10009000B7CC5763BD6DEDFD753EF6177231BF00ED +:1000A0000000803F08000000BE922449123EABAA27 +:1000B000AA2ABECDCCCC4C3E00000080BEABAAAA82 +:1000C000AA3E00000000BF000000803F00000000CA +:1000D00000084178D3BB4387D1133D190E3CC3BD03 +:1000E0004282AD2B3E68EC8276BED98FE1A93E4CB0 +:1000F00080EFFFBE01C4FF7F3F000000000063648B +:10010000696E6F70737578585B000A2534643A2005 +:10011000005D3A20000A0A5B000A53656C6563744F +:1001200020756E69743A2000253378202E2E2E20FB +:10013000004552524F523A20496E76616C696420F4 +:1001400048617264776172652028256429004176D0 +:1001500061696C61626C6520756E6974733A0A0A34 +:100160000048617264776172653A20255300202F40 +:100170002000202F20000A0A4861726477617265AE +:1001800020255320646574656374656420284144A8 +:100190004337483D30782530325829000A496E7679 +:1001A000616C69642048617264776172652D56657F +:1001B0007273696F6E3A204144433748203D2025D1 +:1001C00064202841546D656761363434502C2033E7 +:1001D0002E3356290A00563F3F00563261005631F1 +:1001E0006100446F6E65004552524F52000A000A8A +:1001F0003D3D3D3D3D3D3D3D3D3D3D3D3D3D3D3D2F +:100200003D3D3D3D3D3D3D3D3D3D3D3D3D3D3D3D1E +:100210003D3D3D3D3D0A200041546D6567613634EA +:1002200034500031373A32363A3330004F6374205D +:1002300033312032303234000A505441424C452090 +:1002400025643A203078253032780020213D203056 +:100250007825303278000A00205B5741524E3A2010 +:1002600062756666657220746F20736D616C6C5D7B +:100270002000204F4B5B72656365697665202564BD +:100280002062797465735D2000204552524F525BA5 +:10029000726563656976652025642062797465738B +:1002A0002C206578706563742025642062797465FC +:1002B000735D20005D20002030782530325800200A +:1002C0005374617465735B004552525D005D00209C +:1002D000307825303278000A205B7265616452659F +:1002E00067697374657273283078253032782C20F2 +:1002F0002E2E2E2C202564295D202D3E20004552D7 +:10030000525D003078253032782C737461747573C7 +:100310003D3078253032785D000A205B726561647B +:100320005265676973746572283078253032782990 +:10033000202D3E20004552525D0073746174757328 +:100340003D3078253032785D00202D3E2000203071 +:100350007825303278000A205B77726974655265BF +:100360006769737465727328307825303278293A5A +:1003700020004552525D007374617475733D30788E +:10038000253032785D000A205B77726974655265AA +:10039000676973746572283078253032782C203084 +:1003A000782530327829202D3E20004F4B006661A1 +:1003B000696C73004F4B2C20696E69742050415456 +:1003C00041424C45202E2E2E20006661696C730040 +:1003D0004F4B2C20696E6974207265676973746570 +:1003E00072202E2E2E20006661696C7300207265CB +:1003F00073657420434331313031202E2E2E20007E +:1004000043432D313130312D3F0043432D313130C5 +:10041000312D546573740043432D313130312D52E9 +:100420006563656976650043432D313130312D5365 +:10043000656E6400646F6E65202873746174653D39 +:100440003078253032782900202E2E2E20002025CD +:1004500030325800256420646174612062797465CB +:10046000732028484558293A20004552524F522CB3 +:1004700020004F4B2C200020525353493D25642C23 +:10048000204C51493D25642C204352432000202D0F +:100490003E200045320063616E63656C6C656400EC +:1004A0004532004F4B2C2072656365697665202EBE +:1004B0002E2E20003F202849444C45290063616EC0 +:1004C00063656C6C6564004531000A205B2530343F +:1004D000785D203D3E207374617274202E2E2E2094 +:1004E000004F4B004531005D202D3E20002025307F +:1004F000325800202D2D3E2073656E642025642027 +:10050000627974657320284845583A20253032585E +:1005100000307825303278004531000A205B2530E4 +:1005200034785D3A2073746174653D006661696C6E +:1005300073002850415441424C45203D20307825DD +:10054000303258290064426D20000A2073776974A4 +:10055000636820706F77657220746F200020757358 +:1005600065202B20616E64202D20666F7220706FD5 +:10057000776572206368616E676520286F746865AF +:1005800072206B6579202D3E206261636B20746F51 +:100590002064656661756C742900292E06477A0E01 +:1005A00014040400000600216276CAF81622F840FE +:1005B000073018166C434991876BFB5610E92A00E7 +:1005C0001F4100597F3F813509C6392E3600C031A1 +:1005D000310000C531300000CD3700000086350005 +:1005E00000005030000000372D360000262D31303D +:1005F000001D2D313500172D323000032D33300012 +:1006000025356420283078253032782920000D20C7 +:10061000203D3E20456E636F6465722028707573BF +:100620006820746F20636C656172293A2000456E02 +:10063000636F64657200656E64000A20493243206E +:10064000534C4156453A2066726F6D206D6173744C +:1006500065723A20307825303278202D3E20746F34 +:10066000206D61737465723A2030782530327800DD +:10067000453100202D3E204552524F520030782502 +:10068000303278002C202066726F6D20736C61769A +:10069000653A2000202D3E204552524F52000A203C +:1006A0004932432D4D41535445523A20746F2073C3 +:1006B0006C6176653A20307825303278004531001B +:1006C000453300290062616400706F6F72006661DB +:1006D000697200676F6F6400657863656C6C656E46 +:1006E00074003F002C2065636F323D25642800298B +:1006F0002C2074766F633D2564707062003F007536 +:100700006E6865616C74687900706F6F72006D6FF0 +:1007100064657261746500676F6F64006578636516 +:100720006C6C656E7400206171693D25642800451C +:100730003200252E3166C2B0432F252E3166252585 +:10074000293A20004531290020207C20454E533194 +:1007500036302028002C20483D20252E32662525C5 +:10076000002C20543D20252E3266C2B043000A20C2 +:100770003D3E20424D3238303A20503D20252E3328 +:1007800066626172004F4B004534004533004532CC +:10079000004F4B2C20454E53313630202E2E2E202C +:1007A0000045310020424D323830202E2E2E2000C0 +:1007B0004932432D536C617665004932432D4D61BA +:1007C00073746572004932432D537061726B6675A4 +:1007D0006E20456E762D436F6D626F00656E64000E +:1007E0000A20203D3E207265636569766520427966 +:1007F00074653A20307825303278000A20203D3E5A +:100800002073656E6420427974652030782530321B +:1008100078004945454534383500656E64004552D9 +:10082000524F5228256429004F4B004C434420006E +:100830004552524F5220256429004F4B2900696EC2 +:100840006974204C43442028004C63640054657351 +:1008500074204C454420442564004C656400656E5A +:100860006400202D3E2025342E3866560A002030A4 +:100870007825303278002020003F000A20202020F8 +:10088000202020527844313A0020307825303278C8 +:10089000000A203D3E2053656E64696E673A004D44 +:1008A0006F646275733A206C657365205370616E76 +:1008B0006E756E6720766F6E2045617374726F6E11 +:1008C0002053444D2D323330202845696E706861C5 +:1008D00073656E7AC3A4686C65722900202E2E2E73 +:1008E000207072657373206B657920746F2070724D +:1008F0006F63656564006E6F206279746520726550 +:1009000063656976656400307825303278207265D9 +:10091000636569766564002044453D25752C206E2D +:1009200052453D25752073656E6420307825303240 +:10093000782E2E2E2000696E6974004D6F646275EA +:10094000730020206E6F20726F746174696F6E2067 +:1009500028543D253034782920200020206E3D2069 +:1009600025356420552F6D696E2028543D2530347F +:100970007829002053454E534F523D2564200020D6 +:100980006E4641554C543D25640020414443323D60 +:1009900025336400202050574D2F4F4330413D25D3 +:1009A0003364000D20203D3E20414443303D25333B +:1009B0006400454E3D3100454E3D30000D205357FB +:1009C000333D25642D3E000A004D6F746F72000A9E +:1009D000202042616E6B30202D204750422564203C +:1009E0003D2030000A202042616E6B30202D2047D0 +:1009F00050422564203D2031000A202042616E6B68 +:100A000030202D204750412564203D2030000A2011 +:100A10002042616E6B30202D204750412564203DDF +:100A20002031000A203D3E207374617274202E2E06 +:100A30002E002900204F4B00204A5033392E322FF0 +:100A400033206A756D706572656420286C65667404 +:100A5000293F00204552524F5200202872656164A0 +:100A600020307825303278202D3E203078253032E5 +:100A70007800506F727445787000253464202830F7 +:100A8000782530337829000D20203D3E204D6561CA +:100A90007375726520414443303A20000A00506F5C +:100AA0007469002025332E3166203D3E205357398E +:100AB0003A36203D202564202564252064202564C5 +:100AC0002020002534642028307825303378290010 +:100AD0000D20203D3E204D656173757265204144B7 +:100AE00043323A20000A0052325200416C6C0042FC +:100AF0006C756500477265656E00526564005267EB +:100B000062002025303278000A20257020257020D0 +:100B10002570202570202570202570202570202D1F +:100B20003E2077726974653A2000706F7765722095 +:100B30006F6666206661696C732C204920616D20A8 +:100B40007374696C6C20616C697665203A2D29207C +:100B50002E2E2E2070726F63656564000A20706F00 +:100B6000776572206F6666206E6F77202E2E2E00BE +:100B70000D2070726573732045534320746F20619C +:100B8000626F72742C20706F776572206F666620BA +:100B9000696E2025647320287072657373206B65FD +:100BA0007920746F20736B69702074696D65722988 +:100BB00020000A000A20706F776572206F6E202E69 +:100BC0002E2E006661696C73004F4B000A20546939 +:100BD0006D6572206F6666202E2E2E20000A20542E +:100BE000696D65722073657420746F2025647320AD +:100BF00028313A2530325829202E2E2E20000A2066 +:100C00007365743A20253034642D253032642D25E7 +:100C100030326420253032643A253032643A25304F +:100C2000326400202D2054696D65723D3078253086 +:100C30003278002C20256420253034642D25303274 +:100C4000642D2530326420253032643A25303264F8 +:100C50003A253032640020202D2D3E20003F3F00F9 +:100C600020253032580020000A203D3E2072656168 +:100C70006420726567697374657220302D31352088 +:100C800028686578293A000A202020732F53202EE7 +:100C90002E207365636F6E6420282B2F2D290A0088 +:100CA0000A2020206E2F4E202E2E206D696E757426 +:100CB0006520282B2F2D29000A202020682F48206E +:100CC0002E2E20686F757220282B2F2D29000A20C8 +:100CD0002020642F44202E2E2064617920282B2F81 +:100CE0002D29000A2020206D2F4D202E2E206D6FE3 +:100CF0006E746820282B2F2D29000A202020792FA0 +:100D000059202E2E207965617220282B2F2D290045 +:100D10000A202020772F57202E2E207765656B64C0 +:100D2000617920282B2F2D290A000A2020206320FA +:100D30002E2E2E2E20696E697420636C6F636B00FB +:100D40000A20202070202E2E2E2E20706F776572A4 +:100D5000206F6E2F6F666620285043372D3E51312D +:100D600029000A20202074202E2E2E2E2074696D3A +:100D70006572206F6E2F6F6666000A207072657351 +:100D8000733A000A203D3E20636F6E666967203823 +:100D9000353633202E2E2E20005254432D38353632 +:100DA0003300536F004D6F004469004D6900446F7C +:100DB0000046720053610000436861722025642080 +:100DC0002D202573202D3E2025303278004C312FE8 +:100DD0004C32204F4E004C312F4C32204F4E004FA2 +:100DE0004646004F4E00536567370052656C65619B +:100DF0007365205357256420005072657373205328 +:100E0000572564005377697463680048656C6C6F9C +:100E10002055415254312C204543484F2D4D6F648D +:100E20007573206163746976650A000A203D3E206F +:100E300073656E642074657874207669612055410D +:100E4000525431206E6F772E2E2E00556172743100 +:100E500000005739163A11241FBECFEFD0E1DEBF94 +:100E6000CDBF12E0A0E0B1E0E8EEFDE802C00590E1 +:100E70000D92A635B107D9F724E0A6E5B2E001C08E +:100E80001D92A63EB207E1F717E0CBE2D7E004C01F +:100E90002197FE010E94733CC932D107C9F70E9415 +:100EA000D2370C94F2460C940000FC01108211829F +:100EB0000895FC019181992311F091509183089537 +:100EC000FC01608384E68093B80084E08093BC00DA +:100ED00081E0089584E08093BC001092B8000895EA +:100EE0004150FB0194E824EC4F3FD1F0442319F02A +:100EF0002093BC0002C09093BC008091BC0087FF8F +:100F0000FCCF8091B900887F442319F0803519F017 +:100F100009C0883539F48091BB0081934150E4CFFA +:100F200081E0089580E00895DC01FB0184E835E06C +:100F3000442389F0222311F0949101C09081909371 +:100F4000BB008093BC0011963C9311979091BC001C +:100F500097FFFCCF02C081E008959091B900415005 +:100F60003196987F983221F380E00895FC0184EA5D +:100F70008093BC0085E081838091BC0087FFFCCF1B +:100F80009091B900987F983011F09031B1F4908130 +:100F9000990F962B9093BB0084E88093BC0085E06A +:100FA00081838091BC0087FFFCCF9091B900987F2E +:100FB000611105C081E0983129F080E0089581E059 +:100FC0009034D9F708950F931F93CF93DF93D62FC3 +:100FD0008A01C22F60E00E94B607811102C080E042 +:100FE00016C0F80124E8D093BB002093BC00909178 +:100FF000BC0097FFFCCF9091B900987F983279F7A9 +:10100000D1919FEF9C0FCC2311F0C92FECCFDF9132 +:10101000CF911F910F91089584E98093BC00809136 +:10102000BC0084FDFCCF81E00895FF920F931F93D5 +:10103000CF93DF93EC018B01F42E61E00E94B607A1 +:10104000882379F04F2DB801CE010E9470078823C4 +:1010500041F0CE01DF91CF911F910F91FF900C9441 +:101060000C0880E0DF91CF911F910F91FF900895C0 +:10107000FF920F931F93CF93DF93EC018B01F42E1C +:1010800060E00E94B607882381F020E04F2DB80170 +:10109000CE010E949407882341F0CE01DF91CF91C9 +:1010A0001F910F91FF900C940C0880E0DF91CF917D +:1010B0001F910F91FF900895FF920F931F93CF936D +:1010C000DF93EC018B01F42E60E00E94B6078823C9 +:1010D00081F021E04F2DB801CE010E9494078823B2 +:1010E00041F0CE01DF91CF911F910F91FF900C94B1 +:1010F0000C0880E0DF91CF911F910F91FF90089530 +:10110000CF92DF92EF92FF920F931F93CF93DF93D3 +:10111000EC016B01142F790160E00E94B60788236F +:1011200001F120E0412FB601CE010E9494078823EF +:10113000C1F061E0CE010E94B607882391F0402FF4 +:10114000B701CE010E947007882359F0CE01DF91CC +:10115000CF911F910F91FF90EF90DF90CF900C9463 +:101160000C0880E0DF91CF911F910F91FF90EF90DD +:10117000DF90CF900895FC011082118212821386B5 +:1011800014860895FC019081992311F09150908369 +:10119000089567FD0CC0660F642B6093BA0084E667 +:1011A0008093B80085E48093BC0081E0089580E0DE +:1011B000089584E08093BC001092B8000895FB016C +:1011C0002FB7F894918181E0890F8183DB01A90F0A +:1011D000B11D12964C93883008F011828181908164 +:1011E000891305C08F5F8083883008F010822FBF7D +:1011F0000895462FBC01655F7F4F0C94DF08FB010B +:101200009FB7F89480812181821304C09FBF8FEF24 +:101210009FEF089521E0280F2083DB01A80FB11D67 +:1012200012968C91283018F49FBF90E00895108298 +:10123000FBCFBC016F5F7F4F0C94FF082091B9007A +:10124000287F203819F0283A49F013C04091BB009C +:10125000BC016F5F7F4F0E94DF0809C0BC01655F62 +:101260007F4F0E94FF0897FD80E08093BB0085E8D8 +:1012700001C085EC8093BC000895CF93DF939091DB +:101280005D0480915C049817D1F3E0915D0481E0E6 +:101290008E0F80935D04F0E0E25AFB4FC081CD30A9 +:1012A00009F4CAE0D0E06091E2047091E304CE0159 +:1012B0000E940741CE01DF91CF9108950F931F93B4 +:1012C000CF93C82F8B018A3019F48DE00E945E09FC +:1012D0008091E2049091E3040817190731F480919A +:1012E000C00085FFFCCFC093C60080E090E0CF91A6 +:1012F0001F910F910895089580E090E0089508955A +:10130000089508950895089508952FB7F894409189 +:101310008E0450918F04452B59F4429A80383FEF48 +:10132000930710F480589F4F90938F0480938E04FE +:101330002FBF08952FB7F8944091900450919104D5 +:10134000452B59F4449A80383FEF930710F48058A6 +:101350009F4F90939104809390042FBF0895813004 +:1013600041F0823019F48AED91E0089586ED91E024 +:1013700008958EED91E00895CF9387E680937C00E9 +:1013800087E880937A0080917A00806480937A0065 +:1013900080917A0086FDFCCF1092860480917900BE +:1013A000843F10F081E005C080917900803E18F004 +:1013B00082E080938604809186049FEF980F92309C +:1013C00078F0809179001F928F938CE991E09F9340 +:1013D0008F930E9443410F900F900F900F9014C075 +:1013E000C09179000E94AF091F92CF939F938F9372 +:1013F00086E791E09F938F930E9443410F900F9057 +:101400000F900F900F900F9010927C0010927A0026 +:1014100080918604CF910895F89460938A04709324 +:101420008B0480938C0490938D04789408950E948B +:101430000C0AF89480918A0490918B04A0918C04FA +:10144000B0918D047894892B8A2B8B2B31F080916D +:10145000000190910101019661F38091000190914A +:1014600001010895CF93DF93CFEFDFEFD093010118 +:10147000C09300010E94170AD0930101C09300019C +:10148000DF91CF910895CF93DF93CDB7DEB7289743 +:101490000FB6F894DEBF0FBECDBF70917E04609191 +:1014A0007F04509180044091810430918204209106 +:1014B0008304909184048091850479836A835B839B +:1014C0004C833D832E839F8388878FB7F894E09168 +:1014D0007E0470917F04609180045091810440915A +:1014E0008204309183042091840490918504E983DF +:1014F0007A836B835C834D833E832F8398878FBF72 +:1015000029813A814B815C816D817E818F819885B3 +:1015100028960FB6F894DEBF0FBECDBFDF91CF91F6 +:1015200008951F920F920FB60F9211242F933F939D +:101530008F939F93EF93FF938091C600282F30E005 +:101540003093010120930001E0915C0491E09E0F33 +:1015500090935C04F0E0E25AFB4F808390915C042E +:1015600080915D04981305C080915D048F5F809326 +:101570005D04FF91EF919F918F913F912F910F907B +:101580000FBE0F901F9018951F920F920FB60F92DB +:1015900011242F933F934F935F936F937F938F9378 +:1015A0009F93AF93BF93CF93EF93FF93C091CE00E0 +:1015B00080912B04882329F06C2F89E294E00E940B +:1015C000712B80913F04882329F06C2F8DE394E0E8 +:1015D0000E94A43780912604882329F06C2F84E28E +:1015E00094E00E949926FF91EF91CF91BF91AF9126 +:1015F0009F918F917F916F915F914F913F912F912B +:101600000F900FBE0F901F9018951F920F920FB65C +:101610000F9211242F933F934F935F936F937F9378 +:101620008F939F93AF93BF93EF93FF938091920318 +:10163000882319F082E093E00DC080910103882394 +:1016400019F081E792E006C080912304882329F0F5 +:1016500083E993E00E94E22503C080E88093BC0008 +:10166000FF91EF91BF91AF919F918F917F916F917A +:101670005F914F913F912F910F900FBE0F901F9050 +:1016800018951F920F920FB60F9211242F933F932C +:101690004F935F936F937F938F939F93AF93BF937A +:1016A000EF93FF9380914F04882321F08DE494E021 +:1016B0000E945A2280914804882321F086E494E015 +:1016C0000E94C82C809189048F5F8A3018F480931F +:1016D000890490C01092890480918A0490918B04AF +:1016E000A0918C04B0918D04892B8A2B8B2B99F0BF +:1016F00080918A0490918B04A0918C04B0918D0408 +:101700000197A109B10980938A0490938B04A09357 +:101710008C04B0938D0420917E0430917F0440911D +:1017200080045091810460918204709183048091BF +:10173000840490918504A1E00E94303C20937E04B3 +:1017400030937F044093800450938104609382041B +:101750007093830480938404909385048BE793E0D3 +:101760000E9459078DE793E00E94C2088AEE92E03A +:101770000E9459078CEE92E00E94C2088CE094E02F +:101780000E9459078EE094E00E94C208809168028E +:10179000882319F081508093680280915E0288232B +:1017A00019F0815080935E0280918E0490918F0495 +:1017B000892B69F080918E0490918F04019790930A +:1017C0008F0480938E048038910508F442988091AC +:1017D000900490919104892B69F0809190049091EC +:1017E000910401979093910480939004803891051F +:1017F00008F444988091870490918804019690930E +:101800008804809387048838934140F098B188E039 +:10181000892788B91092880410928704FF91EF916C +:10182000BF91AF919F918F917F916F915F914F91F8 +:101830003F912F910F900FBE0F901F901895CF934F +:10184000DF93EC01198218828091D30481110EC0BC +:1018500083ED94E00E947C09892B41F081ED94E0B6 +:101860000E94550783ED94E00E947F09198A1A8A25 +:101870001B8A1C8A86E994E09B838A8384E994E02E +:101880009D838C8382E994E09F838E8381ED94E035 +:1018900099838883DF91CF910895CF93DF9300D010 +:1018A000CDB7DEB74A83FC0180819181009739F082 +:1018B000698342E0BE016F5F7F4F0E9438080F903E +:1018C0000F90DF91CF910895CF92EF920F93CF9326 +:1018D000DF93EC016295660F660F607C477027709E +:1018E000822F880F880F880F262F242B282B2FABB1 +:1018F0000295000F007E88AD8F71082B08AF8E2DEA +:101900008770880F880F880F9EA9292F207C9C2D17 +:101910009770E22EE82AE92AE894E7F8EEAA40E078 +:1019200064EFCE010E944D0C48AD4295469547703C +:1019300062EFCE010E944D0C9EA9492F477060E2D4 +:10194000469F90011124892F8695869586958770EC +:1019500064E0869FA0011124422B532B97FB99270B +:1019600090F9492B65EFCE010E944D0C9FA9492F9C +:10197000477080E2489F90011124892F86958695B3 +:101980008695877064E0869FA0011124422B532B1B +:101990009295969596959370492B64EFCE01DF91C1 +:1019A000CF910F91EF90CF900C944D0C0F93CF935C +:1019B000DF931F92CDB7DEB7FC0180819181009744 +:1019C00049F0698301E09E012F5F3F4F41E0B9017B +:1019D0000E94800889810F90DF91CF910F91089527 +:1019E0000F93CF93DF9300D0CDB7DEB7FC0180819A +:1019F0009181009749F0698302E09E012F5F3F4F7C +:101A000041E0B9010E94800889819A81982789273D +:101A100098270F900F90DF91CF910F9108950E941A +:101A2000F00C98278927982708950C94F00C0C94B3 +:101A30000F0D0F93CF93DF9300D01F92CDB7DEB77A +:101A4000FC0180819181009749F0698303E09E0148 +:101A50002F5F3F4F41E0B9010E94800829816A81D0 +:101A6000862F90E0A0E0B0E0BA2FA92F982F88270A +:101A7000A22B2B81BC01CD01622B0F900F900F90F8 +:101A8000DF91CF910F9108956F927F928F929F92E5 +:101A9000AF92BF92CF92DF92EF92FF920F931F937C +:101AA000CF93DF93EC019FA9892F807C803409F0CC +:101AB00043C0492F477060E2469F90011124892F4F +:101AC0008695869586958770E4E08E9FA001112407 +:101AD000422B532B9295969596959370492B64EFD4 +:101AE000CE010E944D0C0E94430A922E832E742E2A +:101AF000652E63EFCE010E94D60C83FF1FC00E94AB +:101B0000430AA92CB82CC72CD62CE12CF12C00E0D0 +:101B100010E00E943C3C203D3740410551056105E5 +:101B200071058105910509F038F487EB9BE0019779 +:101B3000F1F700C00000DDCF80E001C081E0DF915F +:101B4000CF911F910F91FF90EF90DF90CF90BF90BA +:101B5000AF909F908F907F906F9008951F93CF9339 +:101B6000DF93EC0168E80E940F0D9E8B8D8B6AE875 +:101B7000CE010E940F0D988F8F8B6CE8CE010E94D2 +:101B80000F0D9A8F898F6EE8CE010E940F0D9C8FEA +:101B90008B8F60E9CE010E940F0D9E8F8D8F62E9C1 +:101BA000CE010E940F0D98A38F8F64E9CE010E9491 +:101BB0000F0D9AA389A366E9CE010E940F0D9CA385 +:101BC0008BA368E9CE010E940F0D9EA38DA36AE945 +:101BD000CE010E940F0D98A78FA36CE9CE010E9441 +:101BE0000F0D9AA789A76EE9CE010E940F0D9CA741 +:101BF0008BA761EACE010E94D60C8DA761EECE01C3 +:101C00000E940F0D9FA78EA763EECE010E94D60CF7 +:101C100088AB64EECE010E94D60C182F65EECE0183 +:101C20000E94D60C90E11902900111248F70282B8C +:101C30003AAB29AB66EECE010E94D60C182F65EEAA +:101C4000CE010E94D60C90E119029001112490E07F +:101C500044E0959587954A95E1F7822B932B9CABB1 +:101C60008BAB67EECE010E94D60C8DABDF91CF918E +:101C70001F91089563EF0E94D60C81700895CF9252 +:101C8000DF92EF92FF920F931F93CF93DF93EC01BC +:101C900060ED0E94D60C90E0A0E0B0E089879A87C2 +:101CA000AB87BC8780369105A105B10569F546EB88 +:101CB00060EECE010E944D0C8FE295E70197F1F79F +:101CC00000C00000CE010E943A0E8111F5CFCE0176 +:101CD0000E94AE0DC12CD12CE12CF12C05E010E0BE +:101CE00025E030E045E050E063E070E0CE010E9486 +:101CF000640C9FE729EA83E0915020408040E1F79F +:101D000000C0000081E001C080E0DF91CF911F9111 +:101D10000F91FF90EF90DF90CF900895CF93DF93D6 +:101D2000EC01888199810E946007882329F0CE0107 +:101D3000DF91CF910C943F0E80E0DF91CF91089519 +:101D40004F925F926F927F928F929F92AF92BF92CB +:101D5000CF92DF92EF92FF92CF93DF93EC016AEF85 +:101D60000E94190D6115710520E88207910509F49B +:101D700085C06B017C0184E0F594E794D794C79407 +:101D80008A95D1F74D885E88C701B60128E030E01A +:101D900040E050E00E948E3A612C712CD301C201C8 +:101DA000880F991FAA1FBB1F281B390B4A0B5B0BFF +:101DB000AF89B88D0E94B83A4B015C01C701B601EA +:101DC00020E130E040E050E00E948E3ACA01B901C3 +:101DD00064197509860997099B01AC010E94503A64 +:101DE0009B01AC017CE055954795379527957A95F1 +:101DF000D1F7A98DBA8D0E94B83A2B013C01C501DB +:101E0000B40120E038E040E050E00E948E3A6901E1 +:101E10007A01C301B20120E030E440E050E00E94CA +:101E20008E3ABA01A9014C0D5D1D6E1D7F1D898979 +:101E30009A89AB89BC899A01AB01280F391F4A1FC7 +:101E40005B1F2D873E874F87588BA5E0B0E00E942F +:101E5000AD3A60587F4F8F4F9F4F20E031E040E018 +:101E600050E00E948E3ACA01B9010E94A53D20E0CF +:101E700030E048EC52E40E94F53C04C060E070E0C1 +:101E800080EC9FE7DF91CF91FF90EF90DF90CF90B4 +:101E9000BF90AF909F908F907F906F905F904F908A +:101EA00008952F923F924F925F926F927F928F92FE +:101EB0009F92AF92BF92CF92DF92EF92FF920F93D9 +:101EC0001F93CF93DF93CDB7DEB76D970FB6F8941E +:101ED000DEBF0FBECDBF1C010E94A00E67EFC10187 +:101EE0000E94190D6F87788B898B9A8B611571050C +:101EF0008048910509F49AC2F10185859685A785E8 +:101F0000B0896C017D01FF0CCC08DC2C76019C01B2 +:101F1000AD016C2D7C2D8C2D9C2D345F41405109E1 +:101F2000610971098109910929873A874B875C8783 +:101F30003B014C0159016A017B018C010E94C03AAE +:101F4000422E3D874E875B8B6C8B7D8B8E8B9B8F60 +:101F5000D1015E963C915E975D962C91932F990FDF +:101F6000990B492F592F692F792F892F0E94C03A39 +:101F70000CE00E94F03B2C8F3D8F49835F8B688F74 +:101F8000798F582E9A8FF10130A1278D932F990FB9 +:101F9000990BA42CBD84CE84DB88EC88FD880E8947 +:101FA0001B8D492F592F692F792F892F0E94C03AF5 +:101FB000F22E032F142FB52FF62FE72FD82EE92E50 +:101FC000A0E00E94453C84F421503F4F4F4F5F4FAB +:101FD0006F4F7F4F8F4F9F4FF22E032F142FB52F30 +:101FE000F62FE72FD82EE92E2F2D302F412F5B2FE4 +:101FF0006F2F7E2F8D2D9E2D08E00E94093CAC8C0A +:10200000BD8CC980DF88E88CF98C052D1A8D0E9463 +:10201000273C70588F4F9F4FD1015B96ED91FC91FB +:102020005C975F01C12CD12CE12CF12C8701E98355 +:10203000BA82CB82DC82ED82FE820F831887C12CAC +:10204000D12CE12CF12C00E010E00E94C03A122FBC +:102050003F8B4983B52FF62FE72FF82E092FA0E0ED +:102060000E94453C84F421503109410951096E4FC9 +:102070007F4F8F4F9F4F122F3F8B4983B52FF62FE6 +:10208000E72FF82E092F212F3F8949815B2F6F2FD2 +:102090007E2F8F2D902F01E20E94093C2D8F532E11 +:1020A00049835F8B688F798F8A8F9C8FA0E00E9415 +:1020B000453C09F4C0C1D10196963C9196979596FE +:1020C0002C91932F990F990BA42CBD84CE84DB887F +:1020D000EC88FD880E891B8D492F592F692F792F88 +:1020E000892F0E94C03A2D873E87442E5B8B6C8BD4 +:1020F0007D8B8E8B9B8FF10134A123A1932F990FA0 +:10210000990BA984BA84CB84DC8473018401492FA0 +:10211000592F692F792F892F0E94C03A01E10E941F +:10212000F03BAD84BE84C42CDB88EC88FD880E892E +:102130001B8D0E94273C59016A017B01482E192FF3 +:102140004F85588969897A8934E0759567955795DF +:1021500047953A95D1F780E090E0A0E1B0E0841B8C +:10216000950BA60BB70B3C014D01990C6608762C1C +:1021700043019C01AD01662D762D862D962D0FE134 +:102180000E94F03B722E832E942E652EB62FA72F21 +:102190008A879B87F10132A121A1932F990F990B77 +:1021A000492F592F692F792F892F03E20E94F03B85 +:1021B000042D0E94273C59016A017B018C01272DC7 +:1021C000382D492D562D6B2F7A2F8A859B850E949D +:1021D0003C3CE5E3AE2EFCE0BF2EC12CD12CE12C23 +:1021E000F12C00E010E00E94C03AAD8CB52CC98003 +:1021F000DF88E88CF98C0A8D1C8D0E941B3B2C8B90 +:102200003B8B2A013B014C01F22E032F142FB52DDD +:10221000F62FE72DD82EE92CA0E00E94453C84F44F +:102220002150304E4F4F5F4F6F4F7F4F8F4F9F4F1B +:10223000F22E032F142FB52FF62FE72FD82EE92ECD +:102240002F2D302F412F5B2F6F2F7E2F8D2D9E2D09 +:102250000DE00E94093C29873A874B875C876F878E +:1022600079838D879E87D1019C963C919C979B9604 +:102270002C91932F990F990BA984BA846A017B0141 +:10228000082F1E85492F592F692F792F892F0E94DA +:10229000C03A0E94C03AF22E032F142FB52FF62F0A +:1022A000E72FD82EE92EA0E00E94453C84F421506F +:1022B000310941095E4F6F4F7F4F8F4F9F4FF22E75 +:1022C000032F142FB52FF62FE72FD82EE92E2F2D01 +:1022D000302F412F5B2F6F2F7E2F8D2D9E2D09E1EB +:1022E0000E94093CAC88BB886201730184010E9492 +:1022F000273C29873A874B875C876F8779838D874F +:102300009E87F10132A521A5932F990F990B492F93 +:10231000592F692F792F892F0E94C03A122F3C8B99 +:102320004B8BB52FF62FE72FF82E092FA0E00E9438 +:10233000453C84F421503109484F5F4F6F4F7F4F28 +:102340008F4F9F4F122F3C8B4B8BB52FF62FE72FC4 +:10235000F82E092F212F3C894B895B2F6F2F7E2F61 +:102360008F2D902F03E10E94093C59016A017B01E6 +:102370008C0129853A854B855C856F8579818D85B2 +:102380009E850E94273C122F39874983B52FF62F4F +:10239000E72FF82E092FA0E00E94453C84F421503D +:1023A0003F4F4F4F5F4F6F4F7F4F8F4F9F4F122FBA +:1023B00039874983B52FF62FE72FF82E092F212FC4 +:1023C000398549815B2F6F2F7E2F8F2D902F08E04D +:1023D0000E94093C2983F32F6A017B01E82F192F02 +:1023E000D10197968D919C919897092E000CAA0B7C +:1023F000BB0B4C015D01BB0C8808982C54019C015F +:10240000AD01682D782D882D982D04E00E94F03BB9 +:10241000A980BF2E0E2F0E94273C0E949D3D20E0E8 +:1024200030E040E85BE30E947F3E08C060E070E07F +:1024300080EC9FE703C060E070E0CB016D960FB6C3 +:10244000F894DEBF0FBECDBFDF91CF911F910F91EA +:10245000FF90EF90DF90CF90BF90AF909F908F90C4 +:102460007F906F905F904F903F902F9008954F9284 +:102470005F926F927F928F929F92AF92BF92CF9214 +:10248000DF92EF92FF92CF93DF9300D000D000D085 +:10249000CDB7DEB79E838D830E94A00E6DEF8D8138 +:1024A0009E810E94F00CA0E0B0E0811520E8920728 +:1024B000A105B10509F4D3C0ED81FE818584968420 +:1024C000A784B088FCE29F1AF1E0AF0AB1083EE0B1 +:1024D000880F991FAA1FBB1F3A95D1F7ED81FE8186 +:1024E00041A952A9052E000C660B770B24E1440F7D +:1024F000551F661F771F2A95D1F76C017D01C41AFD +:10250000D50AE60AF70AA3A9B4A9A50194010E9475 +:10251000B83AA7019601261B370B480B590BCA0185 +:10252000B901705C8F4F9F4F412C30E8532E612CC6 +:10253000712CA30192010E948E3A29833A834B8326 +:102540005C83ED81FE81A0A9B0E0A50194010E9409 +:10255000AD3A20E038E040E050E00E948E3A690158 +:102560007A01F0E8DF0EE11CF11CED81FE81A5A9E6 +:102570000A2E000CBB0BA50194010E94B83A812CD5 +:1025800044E0942EA12CB12CA50194010E948E3A16 +:10259000CA01B901A70196010E94503AA501940110 +:1025A0000E948E3A405E5F4FED81FE81A6A5B7A5E1 +:1025B0000E94B83A705E8F4F9F4F20E030E440E0B9 +:1025C00050E00E948E3A69817A818B819C810E94C1 +:1025D000503A6B017C01A30192010E948E3ACA011C +:1025E000B9010E94503A9B01AC0167E055954795AF +:1025F000379527956A95D1F7ED81FE81A5A5B0E0C5 +:102600000E94AD3A20E130E040E050E00E948E3A76 +:10261000D701C601821B930BA40BB50BB7FF03C0F8 +:1026200080E090E0DC0181309105A105F9E1BF0770 +:1026300024F080E090E0A0E0B9E1BC01CD012CE005 +:1026400095958795779567952A95D1F70E94A33D33 +:1026500020E030E040E85AE30E947F3E04C060E0A2 +:1026600070E080EC9FE726960FB6F894DEBF0FBEB1 +:10267000CDBFDF91CF91FF90EF90DF90CF90BF90D3 +:10268000AF909F908F907F906F905F904F90089544 +:10269000CF92DF92EF92FF926A017B010E94510F6D +:1026A00020E030E048EC52E40E94F53CA70196019E +:1026B0000E94F53C21E03EED42E45EE30E94EC3EE8 +:1026C0009B01AC0160E070E080E89FE30E94883CE1 +:1026D00020E03AE24DE257E40E947F3EFF90EF9007 +:1026E000DF90CF900895CF92DF92EF92FF920F93F9 +:1026F0001F93CB01BA016801790120E03AE24DE273 +:1027000057E40E94F53C9B01AC0160E070E080E87A +:102710009FE30E94883C26EF38E248EA50E40E949A +:10272000EC3E9B01AC01C701B6010E94F53C1F9134 +:102730000F91FF90EF90DF90CF900895FC0161859D +:102740007285838594850895FC01218932894389A6 +:102750005489A5E0B0E00E94AD3A672F782F892F09 +:10276000992787FD9A950E94A53D20E030E048EC2E +:1027700052E40E94F53C0895CF93DF93EC01CB0126 +:10278000BA0120E030E048EC52E40E947F3E0E9413 +:10279000673D982F872F762F662725E030E040E0B1 +:1027A00050E00E948E3A298B3A8B4B8B5C8BDF91E9 +:1027B000CF9108950F931F93CF93DF938C01EB017B +:1027C00088E2FB0111928A95E9F74BE050E06BE754 +:1027D00071E0CE010E94B1401B8681E090E0A0E054 +:1027E000B0E08C879D87AE87BF87F801808191819B +:1027F000092E000CAA0BBB0B888B998BAA8BBB8B69 +:102800008DE090E0A0E0B0E08C8B9D8BAE8BBF8B19 +:102810001CA21DA21EA21FA280E090E0A0E2B2ECCA +:102820008C8F9D8FAE8FBF8F80E090E0AAEAB2E4DC +:10283000888F998FAA8FBB8F8AE097EDA3E2BCE3C4 +:1028400088A399A3AAA3BBA3DF91CF911F910F9156 +:102850000895CF93DF93EB0124E2FB0111922A95B7 +:10286000E9F744E250E060E070E0488359836A830E +:102870007B83FC0180819181092E000CAA0BBB0B8C +:102880008C839D83AE83BF838DE090E0A0E0B0E0B9 +:1028900088879987AA87BB870E94430A288B398B30 +:1028A0004A8B5B8B88E994E00E94A00E6C8B7D8B39 +:1028B0008E8B9F8B81E0DF91CF9108950F931F93B3 +:1028C000CF93DF938C01EB0188E2FB0111928A9593 +:1028D000E9F74BE050E06BE771E0CE010E94B140B8 +:1028E0001B8681E090E0A0E0B0E08C879D87AE87FA +:1028F000BF87F80180819181092E000CAA0BBB0BC8 +:10290000888B998BAA8BBB8B86E090E0A0E0B0E02F +:102910008C8B9D8BAE8BBF8B1CA21DA21EA21FA2F7 +:1029200080E090E0A6E9B3E48C8F9D8FAE8FBF8FDF +:1029300080E090E8A9E8B4E4888F998FAA8FBB8FD4 +:1029400086EA9BE9A4E4BCE388A399A3AAA3BBA35A +:10295000DF91CF911F910F910895CF93DF93EB01FA +:1029600024E2FB0111922A95E9F744E250E060E08D +:1029700070E0488359836A837B83FC018081918165 +:10298000092E000CAA0BBB0B8C839D83AE83BF83E7 +:1029900086E090E0A0E0B0E088879987AA87BB87AF +:1029A0000E94430A288B398B4A8B5B8B88E994E021 +:1029B0000E94510F20E030E048EC52E40E94F53CC8 +:1029C0006C8B7D8B8E8B9F8B81E0DF91CF910895F7 +:1029D0000F931F93CF93DF938C01EB0188E2FB01F0 +:1029E00011928A95E9F74BE050E06BE771E0CE0178 +:1029F0000E94B1401B8681E090E0A0E0B0E08C87AF +:102A00009D87AE87BF87F80180819181092E000CD8 +:102A1000AA0BBB0B888B998BAA8BBB8B8CE090E0AD +:102A2000A0E0B0E08C8B9D8BAE8BBF8B1CA21DA257 +:102A30001EA21FA21C8E1D8E1E8E1F8E80E090E097 +:102A4000A8ECB2E4888F998FAA8FBB8F80E090E0CA +:102A5000A0E4B0E488A399A3AAA3BBA3DF91CF917C +:102A60001F910F910895CF93DF93EB0124E2FB01B7 +:102A700011922A95E9F744E250E060E070E0488363 +:102A800059836A837B83FC0180819181092E000C2C +:102A9000AA0BBB0B8C839D83AE83BF838CE090E03D +:102AA000A0E0B0E088879987AA87BB870E94430A85 +:102AB000288B398B4A8B5B8B88E994E00E94371214 +:102AC0006C8B7D8B8E8B9F8B81E0DF91CF910895F6 +:102AD000CF93DF93EC010E9455071A828CE78CABF1 +:102AE0008AE08DAB8EE78EAB8FEA8FAB88AF82EA40 +:102AF00089AF1AAE80E88BAFDF91CF910895CF9365 +:102B0000DF9300D0CDB7DEB74A83698342E0BE01D0 +:102B10006F5F7F4F0E9438080F900F90DF91CF9129 +:102B200008950F93CF93DF931F92CDB7DEB79A012D +:102B3000698301E041E0BE016F5F7F4F0E94800822 +:102B40000F90DF91CF910F9108950F93CF93DF9363 +:102B50001F92CDB7DEB79A01698302E041E0BE0162 +:102B60006F5F7F4F0E9480080F90DF91CF910F9190 +:102B700008950F931F93CF93DF9300D0CDB7DEB7A7 +:102B80008A01AE014F5F5F4F0E94A515882341F077 +:102B900029813A81322723273227F8013183208384 +:102BA0000F900F90DF91CF911F910F9108950F9388 +:102BB000CF93DF931F92CDB7DEB76983022F9E01BB +:102BC0002F5F3F4F41E0B9010E9480080F90DF91D5 +:102BD000CF910F91089540EF60E10E947F15EFE2E1 +:102BE000F5E73197F1F700C0000008950F931F93A8 +:102BF000CF93DF9300D0CDB7DEB78C01AE014F5F2E +:102C00005F4F60E00E94A5158FE295E70197F1F70D +:102C100000C0000089819A818036E1E09E0721F49E +:102C2000F801128281E008C08136914021F481E0F0 +:102C3000F801828301C080E00F900F90DF91CF9167 +:102C40001F910F9108950F931F93CF93DF931F92BE +:102C5000CDB7DEB78C0140E062E10E947F158111A3 +:102C600008C08FE295E70197F1F700C0000080E00F +:102C700016C04CEC62E1C8010E947F15882389F3DD +:102C80008FE295E70197F1F700C00000AE014F5FBA +:102C90005F4F60E2C8010E949115882311F30F90E5 +:102CA000DF91CF911F910F9108950F931F93CF93B1 +:102CB000DF9300D01F92CDB7DEB78C010E942316A0 +:102CC000882359F18FE295E70197F1F700C00000E2 +:102CD0004EE062E1C8010E947F158823F1F023E0F5 +:102CE000AE014F5F5F4F6CE4C8010E94D715882387 +:102CF000A1F02981F80123839A8194839B81958394 +:102D000091E0273008F490E0F8019283EFE2F5E7D4 +:102D10003197F1F700C0000007C08FE295E70197F7 +:102D2000F1F700C0000080E00F900F900F90DF914E +:102D3000CF911F910F910895633021F4FC012281FE +:102D4000222359F0462F60E10E947F15EFE2F5E75C +:102D50003197F1F700C00000089580E00895CF9307 +:102D6000DF93EC0163E50E9460078FE295E701972E +:102D7000F1F700C00000CE010E94EB158823A9F0F6 +:102D8000CE010E94F615882381F061E0CE010E94F9 +:102D90009C16882351F0CE010E942316882329F027 +:102DA000CE01DF91CF910C94551680E0DF91CF9149 +:102DB0000895CF93DF9361157105D9F0EC017F83FE +:102DC0006E8361E00E949C16882399F0CE010E94D8 +:102DD0002316882371F042EC62E1CE010E947F1538 +:102DE000882339F0EFE2F5E73197F1F700C00000F2 +:102DF00007C08FE295E70197F1F700C0000080E07F +:102E0000DF91CF9108956F927F928F929F92AF92B0 +:102E1000BF92CF92DF92EF920F931F93CF93DF93E6 +:102E20001F92CDB7DEB73C01CB01342FE02FAFE2CC +:102E3000B5E71197F1F700C0000068E170E00E946B +:102E40007A3A8B014FEF460F4295440F440F407C76 +:102E50003111406221114061E1114860E11044608C +:102E600060E4C3010E947F15882309F471C0A801A2 +:102E700041505109569547955695479561E4C301D0 +:102E80000E947F15882309F463C0A60156954795D3 +:102E900062E4C3010E947F15882309F459C0A5018B +:102EA0005695479563E4C3010E947F15882309F472 +:102EB0004FC0A4015695479564E4C3010E947F1555 +:102EC000811146C049895A895695479565E4C301E1 +:102ED0000E947F1581113CC0F3014681415066E498 +:102EE000C3010E947F15811133C0D30116968D91C5 +:102EF0009C911797019711F440E801C040E067E406 +:102F0000C3010E947F15882319F1EFE2F5E731979D +:102F1000F1F700C00000AE014F5F5F4F6FE4C301E7 +:102F20000E9491158823A1F0AFE2B5E71197F1F760 +:102F300000C00000F30126813781B901606C49812E +:102F400050E06417750729F02F5F3F4F37832683C2 +:102F500080E00F90DF91CF911F910F91EF90DF9064 +:102F6000CF90BF90AF909F908F907F906F9008957B +:102F7000AB0160E20C9491150F93CF93DF931F92F6 +:102F8000CDB7DEB79B0141E2498305E041E0BE01D8 +:102F90006F5F7F4F0E9480080F90DF91CF910F915C +:102FA00008950F931F93CF93DF93CDB7DEB7299783 +:102FB0000FB6F894DEBF0FBECDBF8C016623F1F0D3 +:102FC000AE01475F5F4F60E2C8010E949115882300 +:102FD000E9F087EB9BE00197F1F700C000008985DD +:102FE00081FFEECF898581FF11C027E0AE014F5FE1 +:102FF0005F4F61E2C8010E94D71508C0AE01475F6C +:103000005F4F60E20E9491158111ECCF80E029961C +:103010000FB6F894DEBF0FBECDBFDF91CF911F91E9 +:103020000F9108950F931F93CF93DF93CDB7DEB722 +:1030300029970FB6F894DEBF0FBECDBF8C01662373 +:10304000C1F087EB9BE00197F1F700C00000AE01F3 +:10305000475F5F4F60E2C8010E949115811102C075 +:1030600080E00AC1898580FFECCF898580FFF8CF99 +:1030700009C0AE01475F5F4F60E20E949115811168 +:10308000F4CFEECF28E0AE014F5F5F4F68E4C80198 +:103090000E94D715882321F369817A8180E090E02E +:1030A0000E94A33D20E030E040E05AE30E947F3ED2 +:1030B0009B01AC0160E070E080E090E40E94EC3E97 +:1030C0000E946E3DF8016787708B818B928B6B81BC +:1030D0007C8180E090E00E94A33D20E030E040E071 +:1030E0005AE30E947F3E9B01AC0160E070E080E00B +:1030F00090E40E94EC3E0E946E3DF801678B708F59 +:10310000818F928F6D817E8180E090E00E94A33D4F +:1031100020E030E040E05AE30E947F3E9B01AC019A +:1031200060E070E080E090E40E94EC3E0E946E3D22 +:10313000F801678F70A381A392A36F81788580E0E7 +:1031400090E00E94A33D20E030E040E05AE30E947E +:103150007F3E9B01AC0160E070E080E090E40E9463 +:10316000EC3E0E946E3DF80167A370A781A792A76D +:1031700028E0AE014F5F5F4F68E2C8010E94D7159B +:10318000882309F46DCF69817A8180E090E00E9404 +:10319000A33D20E030E040E05AE30E947F3E9B01E7 +:1031A000AC0160E070E080E090E40E94EC3E0E94A0 +:1031B0006E3DF801638B748B858B968B6B817C8164 +:1031C00080E090E00E94A33D20E030E040E05AE340 +:1031D0000E947F3E9B01AC0160E070E080E090E4E3 +:1031E0000E94EC3E0E946E3DF801638F748F858FC4 +:1031F000968F6D817E8180E090E00E94A33D20E06B +:1032000030E040E05AE30E947F3E9B01AC0160E069 +:1032100070E080E090E40E94EC3E0E946E3DF80178 +:1032200063A374A385A396A36F81788580E090E063 +:103230000E94A33D20E030E040E05AE30E947F3E40 +:103240009B01AC0160E070E080E090E40E94EC3E05 +:103250000E946E3DF80163A774A785A796A7AE01EB +:103260004F5F5F4F68E3C8010E949115882309F4FE +:10327000F7CE9981F80193AB29960FB6F894DEBF8B +:103280000FBECDBFDF91CF911F910F910895CF93C6 +:10329000DF9300D000D0CDB7DEB769837A834B834C +:1032A0005C8324E0AE014F5F5F4F63E10E94E30760 +:1032B0000F900F900F900F90DF91CF9108958F9204 +:1032C0009F92AF92BF92CF92DF92EF92FF920F93B5 +:1032D0001F93CF93DF93EC014A015B01C901B80151 +:1032E00020E030E040E054E40E947F3E0E946E3DCA +:1032F0006B017C0123E333E948E853E4C501B401E1 +:103300000E94893C20E030E040E852E40E947F3E89 +:103310000E946E3DA601CE01DF91CF911F910F91CA +:10332000FF90EF90DF90CF90BF90AF909F908F90E5 +:103330000C944719FC01868197818330910540F4F4 +:10334000880F991FFC01EC59FE4F808191810895EF +:1033500080E094E00895289820981CBC2C9884B1B3 +:103360008F7084B981B18F7C81B982B18F7C82B931 +:10337000089560E070E0CB010E94170A0196C9F33E +:103380000895611102C00E94B9198FEF08956EBDB2 +:103390000DB407FEFDCF8EB50895289A089528989C +:1033A000089595B181E0892785B908951498089505 +:1033B000149A089583B186FB882780F9089580B117 +:1033C00085FB882780F908952AE0FC0120871E9953 +:1033D000FECF81E0089524E6FC012087059BFECF07 +:1033E00081E0089524E6FC0120870599FECF81E065 +:1033F00008950F931F93CF93DF93EC01162F0E9434 +:10340000D619CE010E94E419082F612F6F73CE01E7 +:103410000E94C719CE010E94D819802FDF91CF9149 +:103420001F910F910895FF920F931F93CF93DF93F6 +:10343000EC01062FF42E0E94D619CE010E94E41949 +:10344000182F602FCE010E94C7196F2DCE010E9448 +:10345000C7198A838D8181608D83CE010E94D8191E +:10346000898580FF2BC01F92FF921F920F9386E8E1 +:1034700093E09F938F930E9443410F900F900F9082 +:103480000F900F900F90112389F08D8182FF0EC055 +:103490008A811F928F9387E793E09F938F930E9477 +:1034A00043410F900F900F900F9008C082E793E078 +:1034B0009F938F930E9443410F900F90812FDF9134 +:1034C000CF911F910F91FF900895AF92BF92CF922D +:1034D000DF92EF92FF920F931F93CF93DF93EC0154 +:1034E000B42ED52E022F6F73162F10640E94D6199A +:1034F000CE010E94E419C82E612FCE010E94C71987 +:10350000EB2CFD2C5701D02EDD2041F0F50161910F +:103510005F01CE010E94C719DA94F6CFCE010E9456 +:10352000D819898581FF46C01F731F921F9386E5B6 +:1035300093E09F938F930E9443410F900F900F90C1 +:103540000F90102F8EE4A82E83E0B82E112379F06F +:10355000F70181917F011F928F93BF92AF920E94DA +:10356000434111500F900F900F900F90EFCF89E4CF +:1035700093E09F938F930E9443410F900F90CC2034 +:1035800089F08D8182FF0EC08A811F928F938AE31A +:1035900093E09F938F930E9443410F900F900F9061 +:1035A0000F9008C085E393E09F938F930E9443415F +:1035B0000F900F908C2DDF91CF911F910F91FF9065 +:1035C000EF90DF90CF90BF90AF900895EF92FF9271 +:1035D0000F931F93CF93DF93EC017A016F73162F34 +:1035E00010680E94D619CE010E94E419082F612F9D +:1035F000CE010E94C7198A838D8181608D8360E02E +:10360000CE010E94C719F7018083CE010E94D8190C +:10361000898582FF2EC01F731F921F9389E193E05B +:103620009F938F930E9443410F900F900F900F90A4 +:103630000023B9F08D8180FF14C08A811F928F937F +:10364000F70180811F928F9383E093E09F938F9384 +:103650000E9443410F900F900F900F900F900F908A +:1036600008C08EEF92E09F938F930E9443410F908A +:103670000F90802FDF91CF911F910F91FF90EF90CE +:103680000895AF92BF92CF92DF92EF92FF920F9385 +:103690001F93CF93DF938C01D62FB42ED52EC22F3C +:1036A0000E94D619C8010E94E419C82E6D2F606CC3 +:1036B000C8010E94C719EB2CFD2C5701DC2EDD2020 +:1036C00049F060E0C8010E94C719F50181935F01CC +:1036D000DA94F5CFC8010E94D819F801818583FFDB +:1036E00031C01F92CF93DF731F92DF9387ED92E07B +:1036F0009F938F930E9443410F900F900F900F90D4 +:103700000F900F90CC20B1F00FEC12E0CC2379F0A9 +:10371000F70181917F011F928F931F930F930E9456 +:103720004341C1500F900F900F900F90EFCF8DEC51 +:1037300092E002C088EC92E09F938F930E944341F5 +:103740000F900F908C2DDF91CF911F910F91FF90D3 +:10375000EF90DF90CF90BF90AF90089521E00C9450 +:10376000411B9B01205331092E30310510F40C947C +:10377000AE1B80E00895AF92BF92CF92DF92EF929E +:10378000FF920F931F93CF93DF93CDB7DEB762976E +:103790000FB6F894DEBF0FBECDBF8C01242F8AE098 +:1037A000F8018087AB016FE3C8010E94651AF82E0B +:1037B000AE014E5E5F4F6AE370E0C8010E94AE1B2F +:1037C0009A899431A1F58F2191F165E370E0C801E8 +:1037D0000E94F919F82E882351F1D12CE12CAE0169 +:1037E0004F5E5F4F65E370E0C8010E94AE1BF82298 +:1037F0008989D81659F0FFE0FE1540F0E1E0F0E0CD +:10380000EC0FFD1FEE0DF11D8083E394FF2049F0C6 +:10381000833129F0D82EF80190859111E0CFFF2453 +:10382000F39491E0833109F090E0F92261F46BE3C5 +:1038300070E0C8010E94F91960C0222389F0F801E4 +:103840008085882369F0AE014E5E5F4F6AE370E0C9 +:10385000C8010E94AE1B2A898111EFCF80E001C010 +:1038600081E091E0211190E0892309F3AE014F5EE0 +:103870005F4F65E370E0C8010E94AE1B2989882371 +:1038800039F0213039F0F80180858111EFCF02C085 +:1038900080E001C081E091E0213009F090E08923CF +:1038A00061F18FEB92E09F938F930E944341CE0191 +:1038B00001965C010F900F908C0187EBC82E82E07F +:1038C000D82E802F8A198E1570F4F80181918F01FE +:1038D0001F928F93DF92CF920E9443410F900F90DF +:1038E0000F900F90EECF84EB92E09F938F930E9406 +:1038F00043410F900F9081E001C080E062960FB6C7 +:10390000F894DEBF0FBECDBFDF91CF911F910F9115 +:10391000FF90EF90DF90CF90BF90AF9008953F92CF +:103920004F925F926F927F928F929F92AF92BF92CF +:10393000CF92DF92EF92FF920F931F93CF93DF937B +:10394000CDB7DEB767970FB6F894DEBF0FBECDBF19 +:103950006C01611105C046E062E00E94131A14C1B7 +:10396000623008F010C18DE595E09F938F930E941F +:1039700043410F900F9080E090E0EE24EA94FE2CFB +:10398000512C34E1432E4DEE642E44E0742E57EE5C +:10399000852E54E0952E2FEF30E03E8B2D8B5C0171 +:1039A0003FEFA31AB30A9F938F938BE195E09F9308 +:1039B0008F930E944341AE014B5E5F4F65E370E021 +:1039C000C6010E94AE1B0F900F900F900F908111B7 +:1039D00009C028E135E03F932F930E9443410F90A7 +:1039E0000F900EC08E898F938D898F93E1E1F5E062 +:1039F000FF93EF930E9443410F900F900F900F9011 +:103A00008F8989831F925F921F924F9283EF94E078 +:103A10009F938F930E9443418E010E5F1F4F0F9023 +:103A20000F900F900F900F900F90312C832D8A0DD7 +:103A3000F80181938F011F928F937F926F920E9462 +:103A4000434133940F900F900F900F90F3E13F128A +:103A5000EDCF9F928F920E94434144E1BE016F5F80 +:103A60007F4FC6010E94BB1B0F900F90811171C048 +:103A700084E690E00E94850984EE94E09F938F9302 +:103A80000E9443410F900F902FEFE216F20609F4C7 +:103A90005EC03BE2E316F10429F08DE2E816F10482 +:103AA00031F00CC091E0951558F45A940EC0552091 +:103AB00051F0E9E0E51548F0539407C0512C05C0DA +:103AC0005524539402C08AE0582EF5E05F9E800191 +:103AD000112407531A4F41E050E0B801CE01479638 +:103AE0000E949A408AE495E09F938F930E944341FD +:103AF0000F5F1F4F1F930F930E94434185E495E092 +:103B00009F938F930E9443414F896EE3C6010E94A9 +:103B1000131A0F900F900F900F900F900F90882313 +:103B200071F08F891F928F9382E395E09F938F931B +:103B30000E9443410F900F900F900F9008C08CE2AD +:103B400095E09F938F930E9443410F900F90C50182 +:103B500022CF84E690E00E949A0960ED77E080E051 +:103B600090E00E94320A7C0121EE34E03F932F93D3 +:103B70000E9443410F900F909BE1E916F10409F078 +:103B800083CF80E001C08FEF67960FB6F894DEBF59 +:103B90000FBECDBFDF91CF911F910F91FF90EF909E +:103BA000DF90CF90BF90AF909F908F907F906F905D +:103BB0005F904F903F9008958F929F92AF92BF92E7 +:103BC000CF92DF92EF92FF920F931F93CF93DF93E9 +:103BD00000D0CDB7DEB78C014B015A01C22EFA01DD +:103BE000108282E3F801808785818B7F8583AE0117 +:103BF0004E5F5F4F6BE370E0C8010E94AE1BF82E72 +:103C0000882309F446C08A818F7709F446C0D82EEC +:103C10008FEA94E00197F1F700C00000AE014E5F1B +:103C20005F4F6BE370E0C8010E94AE1B882321F058 +:103C30009A819F77E92E01C0ED2C91E0F801208553 +:103C4000211101C090E0F92EF82219F1DE1411F0D3 +:103C5000DE2CDECFF80185818270D82E90E044966C +:103C60002E2D30E08217930769F19F938F93F50112 +:103C700080811F928F9389E892E09F938F930E9497 +:103C80004341F50110820F900F900F900F900F900D +:103C90000F90F12C02C0E11056C06AE370E0C80139 +:103CA0000E94F9198F210F900F90DF91CF911F91F2 +:103CB0000F91FF90EF90DF90CF90BF90AF909F90CB +:103CC0008F9008959F938F9382E792E09F938F93B5 +:103CD0000E9443410F900F900F900F90F4E1FC155C +:103CE00018F42E2D2D1901C02C2DF5012083A401CF +:103CF0006FEFC8010E94411BF501811102C01082C3 +:103D0000C8CF8081E81ADE1430F688E592E09F93F0 +:103D10008F930E9443410F900F90AE014F5F5F4F12 +:103D20006FEFC8010E94E61AEA94DE14B0F3DD20BA +:103D300009F4AFCF22E0A8014D5F5F4F6FEFC801DC +:103D40000E94411BA6CF22E0A8014D5F5F4F6FEF9D +:103D5000C8010E94411BF82E882309F49ACFF8016C +:103D600085818460858399CF3F924F925F926F9255 +:103D70007F928F929F92AF92BF92CF92DF92EF92FB +:103D8000FF920F931F93CF93DF93CDB7DEB7679763 +:103D90000FB6F894DEBF0FBECDBF8C01611105C018 +:103DA00046E062E00E94131A61C1623008F05DC112 +:103DB00080E090E07C012FEFE21AF20A9F938F934C +:103DC0008AEC94E09F938F930E94434164E370E0F8 +:103DD000C8010E94F9190F900F900F900F908FEF6C +:103DE00090E09E8B8D8BAE014B5E5F4F65E370E084 +:103DF000C8010E94AE1B81110EC087EC94E09F9316 +:103E00008F930E9443419FE7EFE4F2E19150E0403D +:103E1000F040E1F714C060E070E0CB010E94170AA7 +:103E2000019691F08DEB94E09F938F930E94434114 +:103E30008FE79FE4E2E181509040E040E1F700C06D +:103E400000000F900F9019C08D899E8981309105D7 +:103E500071F484EB94E09F938F930E944341FFE7BA +:103E60002FE482E1F15020408040E1F7E8CF8D302F +:103E7000910519F0419709F0B2CF8D899E898D3057 +:103E8000910521F0419711F0C70194CF83EA94E0A6 +:103E90009F938F930E9443410F900F9084E5482E8B +:103EA00084E0582E98E4692E94E0792E2AE6C22EFA +:103EB00024E0D22E32E7A32E34E0B32E43E9842E41 +:103EC00044E0942EAE014B5E5F4F65E370E0C801A5 +:103ED0000E94AE1B81110EC0E0EAF4E0FF93EF9365 +:103EE0000E9443418FE79FE4E2E181509040E0402F +:103EF000E1F72EC060E070E0CB010E94170A019646 +:103F000091F086E994E09F938F930E9443412FE7BD +:103F10008FE492E1215080409040E1F700C0000022 +:103F20000F900F90A2C0AE01495E5F4F6BE370E04F +:103F3000C8010E94AE1B81110EC09F928F920E94F9 +:103F40004341EFE7FFE422E1E150F0402040E1F798 +:103F500000C0000071C08F89843108F46FC024E173 +:103F6000AE01495E5F4FBE016F5F7F4FC8010E9487 +:103F7000DC1D882309F462C08F89882309F45EC0A0 +:103F800084E690E00E949A098EE894E09F938F93D4 +:103F90000E944341F80185810F900F9082FF24C059 +:103FA00084818F771F928F938381282F082E000C96 +:103FB000330B3F938F9387E794E09F938F930E94F7 +:103FC0004341F80184810F900F900F900F900F9054 +:103FD0000F9087FF03C0BF92AF9202C0DF92CF92D3 +:103FE0000E9443410F900F908F891F928F935F9291 +:103FF0004F920E9443410F900F900F900F90312CE1 +:104000008F893816A8F4E1E0F0E0EC0FFD1FE30D16 +:10401000F11D80811F928F938EE494E09F938F9384 +:104020000E94434133940F900F900F900F90E8CF70 +:104030007F926F920E9443410F900F908D899E89CD +:104040008D30910509F43ECF8131910509F43ACFC5 +:104050009F938F9384E394E09F938F930E944341B7 +:104060000F900F900F900F900FCF8FEF67960FB6B6 +:10407000F894DEBF0FBECDBFDF91CF911F910F919E +:10408000FF90EF90DF90CF90BF90AF909F908F9078 +:104090007F906F905F904F903F900895FC01268134 +:1040A00037812130310531F038F02230310541F4CB +:1040B0000C94B41E0C948F1C611102C00E94B9199B +:1040C0008FEF0895AF92BF92CF92DF92EF92FF925F +:1040D0000F931F93CF93DF93CDB7DEB729970FB61A +:1040E000F894DEBF0FBECDBF7C0186E592E09F93C2 +:1040F0008F930E9443418AE9C82E85E0D82E0F9005 +:104100000F9010E09BE4A92E92E0B92E41E050E020 +:10411000B601CE0109960E949A40AE014F5F5F4FF3 +:10412000612FC7010E94E61A89859981981751F07D +:104130001F928F93BF92AF920E9443410F900F90B6 +:104140000F900F901F5F8FEFC81AD80A1F32F1F639 +:1041500000E310E0AE014F5F5F4FB801C7010E945E +:10416000B11B0F5F1F4F0E331105A1F728E0AE0101 +:104170004F5F5F4F6EE3C7010E94411B29960FB648 +:10418000F894DEBF0FBECDBFDF91CF911F910F918D +:10419000FF90EF90DF90CF90BF90AF9008951F9366 +:1041A000CF93DF93EC010E94D61988E28A95F1F74C +:1041B000CE010E94D81988EC8A95F1F7CE010E94B1 +:1041C000D619CE010E94E419182F60E370E0CE01E9 +:1041D0000E94F9191823CE010E94E4198123DF916E +:1041E000CF911F910895CF92DF92EF92FF921F938C +:1041F000CF93DF931F92CDB7DEB76C018AE9E82E2B +:1042000085E0F82E10E041E050E0B701CE010196C4 +:104210000E949A404981612FC6010E94131A1730EB +:1042200039F4998192FF04C0F601958192609583DB +:104230001F5F882331F08FEFE81AF80A1F3219F751 +:1042400081E00F90DF91CF911F91FF90EF90DF9071 +:10425000CF9008955F926F927F928F929F92AF92CC +:10426000BF92CF92DF92EF92FF920F931F93CF9363 +:10427000DF93CDB7DEB728970FB6F894DEBF0FBE39 +:10428000CDBF4C018E010F5F1F4FE12CF12C60E080 +:10429000702EC12E88E3A82E82E0B82EDD24D394A0 +:1042A000D60E6E2C5F2C85E0689FB00111246753F9 +:1042B0007A4F41E050E0C8010E949A40EAE0ED15D3 +:1042C00008F4D12CF401818584FF10C0F8018081AD +:1042D0001F928F935F926F92BF92AF920E94434161 +:1042E0000F900F900F900F900F900F90FFEFEF1A1D +:1042F000FF0A0F5F1F4F88E0E816F10411F06D2DE3 +:10430000CDCF28E0472D5C2D6EE3C4010E94651AD5 +:1043100028960FB6F894DEBF0FBECDBFDF91CF91C8 +:104320001F910F91FF90EF90DF90CF90BF90AF90D3 +:104330009F908F907F906F905F900895CF93DF93C1 +:10434000EC012898209A8091640084708093640026 +:10435000149A0C9A2C9A269884B1806B84B980E5C3 +:104360008CBD159A0D988DEE93E09F938F930E94CC +:104370004341CE010E94CF200F900F90811103C0C6 +:1043800087EE93E01FC080ED93E09F938F930E9490 +:104390004341CE010E94F3200F900F90811103C082 +:1043A0008AEC93E00FC084EB93E09F938F930E947D +:1043B0004341CE010E942A210F900F90811107C026 +:1043C0008EEA93E09F938F930E9443410CC08BEA47 +:1043D00093E09F938F930E9443418FEF8987CE0193 +:1043E0000E94622019860F900F90DF91CF9108955F +:1043F00024B1287F24B925B1276025B921E0FC012B +:1044000022830895FC01128284B1887F84B985B12A +:10441000887F85B90895EF92FF920F931F93CF93F2 +:10442000DF9361112CC0EC010EE016E080E0E82E75 +:1044300086E0F82E6AE070E080E090E00E94170AC3 +:104440000196F9F41F930F930E9443418B811F92B1 +:104450008F93282F082E000C330B3F938F93FF92DE +:10446000EF920E9443418DB79EB708960FB6F8941D +:104470009EBF0FBE8DBF1A99DDCF1B82DBCF8FEFA2 +:1044800001C080E0DF91CF911F910F91FF90EF90DD +:10449000089583B182FB882780F991E089270895E8 +:1044A00083B180958170089583B18695817091E084 +:1044B00089270895FC018281811102C01382089529 +:1044C00033B191E03927379533273795330F330BC5 +:1044D00023B1269521702927279522272795220F7A +:1044E000220B80E030FB80F920FB81F990911F01C5 +:1044F00098279370D1F490911E0190FD0EC09827DB +:1045000091FF0BC0938181FD04C09F3729F09F5F0D +:1045100003C0903809F09150938380911E0130FBC5 +:1045200080F920FB81F980931E0180911F0130FBEF +:1045300080F920FB81F980931F010895FC0182819D +:1045400093818330910540F4880F991FFC01E6594F +:10455000FE4F8081918108958AE991E00895E8EB0A +:10456000F0E02DE020832CE1208324E6208324E06A +:104570002093BC0020E620937C0027E820937A005B +:1045800080579F4F21E0FC012083089580579F4F63 +:10459000FC01108284E08093BC001092B80010925D +:1045A0007C0010927A0008952F923F924F925F9272 +:1045B0006F927F928F929F92AF92BF92CF92DF9233 +:1045C000EF92FF920F931F93CF93DF93CDB7DEB798 +:1045D00061970FB6F894DEBF0FBECDBF8C0161119D +:1045E000A5C2FC0182819381009709F0E8C184EAA9 +:1045F00097E09F938F930E94434198012C5F3F4F18 +:104600003D872C8767E7C9010E948E0E0F900F909F +:10461000811103C081EA97E08BC281E997E09F9303 +:104620008F930E94434158013DE3A30EB11CC50185 +:104630000E94AF160F900F90811103C08EE897E093 +:1046400077C262E0C5010E949C16811103C08BE80D +:1046500097E06EC200E010E022E832E440E050E073 +:1046600068EC71E4C5010E945F19811103C088E8FC +:1046700097E05EC285E897E09F938F930E94434145 +:104680000F900F908FEF8F83412C512C32014E866B +:104690005F86688A798A8C859D850E94510F20E00B +:1046A00030E543EC57E40E94F53C9F938F937F9352 +:1046B0006F93EEE6F7E0FF93EF930E9443418C8502 +:1046C0009D850E94A00E68877987382E292E9F939A +:1046D0008F9339853F9388858F93E1E6F7E0FF93C9 +:1046E000EF930E9443418C859D850E9437124B01B8 +:1046F0008A879B879F938F939F926F9385E597E01F +:104700009F938F930E9443410FB6F894DEBF0FBE74 +:10471000CDBF3F813F3F09F19A858B85282D392DEB +:10472000492F582FFC01682D792D8F2F9E2F0E9425 +:104730003C3F811112C078856985C101272F362F32 +:10474000492F582FDB01F1016B2F7A2F8F2F9E2FCE +:104750000E943C3F882309F4FBC165E0C62ED12CA2 +:10476000E12CF12C05E010E025E030E045E050E0E0 +:1047700063E070E08C859D850E94640C8F8180329F +:1047800008F413C1E8E4F7E0FF93EF930E9443417C +:104790000F900F903F8113162CF5632F330F770B7B +:1047A000880B990B0E94A53D6B017C019B01AC011C +:1047B000C301B2010E94F53C4B018A879B87A70188 +:1047C00096016E857F85888999890E94F53C688766 +:1047D0007987382E292E412C512C32014E865F8646 +:1047E000688A798A9A858B85082D192D292F382F6B +:1047F000F885E985C1014F2F5E2F692F722DC50104 +:104800000E945F19811105C084E497E09F938F9304 +:10481000C7C08B858F939A859F939F928F922F927B +:104820003F92E985EF93F885FF9322E337E03F93CA +:104830002F930E94434162E0C5010E949C160FB66F +:10484000F894DEBF0FBECDBF811103C08FE297E0A9 +:1048500093C014E687EC9FEA0197F1F700C00000CF +:10486000BE016A5F7F4FC5010E94B817882309F413 +:104870008AC08E8181FF87C0BE016F5F7F4FC501F7 +:104880000E94BC17882309F481C089811F928F93ED +:10489000E6E2F7E0FF93EF930E9443410F900F9001 +:1048A0000F900F908981833091F038F4813061F05E +:1048B000823099F487E197E012C0843059F0853056 +:1048C00061F48FEF96E00BC08CE197E008C08EE0BA +:1048D00097E005C089E097E002C08DEF96E09F93D6 +:1048E0008F930E9443410F900F908B818F938A8109 +:1048F0008F938FEE96E09F938F930E9443418D811B +:104900008F938C818F9324EE36E03F932F930E94F8 +:1049100043418C819D810FB6F894DEBF0FBECDBFA1 +:104920008039F1E09F0718F482EE96E01DC08835CB +:1049300022E0920718F488ED96E016C0803233E04A +:10494000930718F483ED96E00FC0883EE3E09E07DE +:1049500018F48EEC96E008C08C3D954018F489EC74 +:1049600096E002C085EC96E09F938F930E944341AE +:104970000F900F9083EC96E09F938F930E9443419A +:104980000F900F9003C0115009F064CF61E0C50192 +:104990000E949C16811108C020EC36E03F932F93B3 +:1049A0000E9443410F900F901F8268EE73E080E0F9 +:1049B00090E00E94170A019609F46DCEC1C08130C3 +:1049C000910509F071C007581F4F61E0C8010E94AE +:1049D0006007811103C08DEB96E0AAC09EE9692EA5 +:1049E00096E0792E24E9E22E26E0F22E34E8C32E5A +:1049F00036E0D32E43E7A42E46E0B42E5DE7852EA5 +:104A000056E0952E80917A00806480937A008091A0 +:104A10007A0086FDFCCF8091790089831F928F9365 +:104A20007F926F920E94434141E0BE016F5F7F4FD2 +:104A3000C8010E9438080F900F900F900F908111BD +:104A400006C0FF92EF920E9443410F900F90DF92B9 +:104A5000CF920E94434141E0BE016F5F7F4FC8018A +:104A60000E9415080F900F90882361F089811F9292 +:104A70008F939F928F920E9443410F900F900F90BF +:104A80000F9006C0BF92AF920E9443410F900F90CB +:104A900068EE73E080E090E00E94170A019609F446 +:104AA000B1CF0E946A074CC0029709F03FC0055879 +:104AB0001F4F40E061E0C8010E94C908811103C096 +:104AC00080E796E035C08AE3C82E86E0D82EC8017C +:104AD0000E9419097C010196F1F080917A008064AE +:104AE00080937A0080917A0086FDFCCF60917900F6 +:104AF000C8010E94F908809179001F928F93FF925C +:104B0000EF92DF92CF920E9443410F900F900F904F +:104B10000F900F900F9060E070E0CB010E94170A99 +:104B20000196A9F2C8010E94D9080AC086E396E05E +:104B30009F938F930E9443410F900F908FEF29C056 +:104B400064EF71E080E090E00E94170A80E021C0ED +:104B500078856985C101272F362F492F582F6E85FB +:104B60007F85888999890E94893C6E877F87888B99 +:104B7000998B9A858B85282D392D492F582FC30164 +:104B8000B2010E94893C2B013C018F818F5F8F8392 +:104B9000E4CD61960FB6F894DEBF0FBECDBFDF91B6 +:104BA000CF911F910F91FF90EF90DF90CF90BF902A +:104BB000AF909F908F907F906F905F904F903F90BD +:104BC0002F900895FC01228133812230310541F478 +:104BD000579A5F9A85589F4F0E941E095F980895C3 +:104BE0008091BC0080688093BC00089520E62093EB +:104BF0007C0027E820937A00289A299824B1236022 +:104C000024B95A9A22E02093C80028E92093C900C9 +:104C100026E02093CA001092CD002BE92093CC000F +:104C200021E0FC0122830895FC01128210927C0095 +:104C300010927A001092C8001092C9001092CA0017 +:104C40001092CD001092CC005A9884B18C7F84B918 +:104C500085B18C7F85B90895CF92DF92EF92FF9254 +:104C60000F931F93CF93DF938C0161114EC028984F +:104C700029988BEFE82E87E0F82ECC24CA94DC2C00 +:104C8000C0EED7E064EF71E080E090E00E94170A88 +:104C9000019609F044C080917A00806480937A0084 +:104CA00080917A0086FDFCCF8091C800806480935B +:104CB000C800289A299A809179008093CE0080912B +:104CC000C80086FFFCCF29982898809179001F9210 +:104CD0008F93FF92EF920E944341F894F8018381F1 +:104CE0009481D482C38278940F900F900F900F908C +:104CF00097FDC8CF9F938F93DF93CF930E9443413B +:104D00000F900F900F900F90BDCF8CED97E09F9379 +:104D10008F930E9443410F900F908FEF01C080E06E +:104D2000DF91CF911F910F91FF90EF90DF90CF9087 +:104D3000089570E0FC017483638308955F9A089579 +:104D40005F9808955E9A08955E980895139A08955D +:104D5000139808958FEF84B9089580918604813067 +:104D600019F48FEF84B9089514B8089580918604DA +:104D7000813041F487EB9BE00197F1F700C0000020 +:104D800080E0089583B1089565B90895109A089553 +:104D9000109808951F93CF93DF93EC01162F0E9474 +:104DA000A8268FEF84B98A81882389F0812F807F9C +:104DB00085B9CE010E94A6268CE38A95F1F7CE0133 +:104DC0000E94A82684E08A95F1F71295107F15B904 +:104DD000CE010E94A6268CE38A95F1F7CE010E94AF +:104DE000A82684E08A95F1F7DF91CF911F9108956D +:104DF0001F93CF93DF93EC01162F0E94A426CE01C0 +:104E00000E94A026612FCE01DF91CF911F910C94BB +:104E1000CA26EF92FF920F931F93CF93DF93EC017B +:104E20007B018B8187FD59C080918604813041F4DC +:104E300087EB9BE00197F1F700C0000081E04EC0D6 +:104E4000CE010E94AD268FEF85B9CE010E94A22629 +:104E5000CE010E94A02694E09A95F1F7CE010E941F +:104E6000A6268CE38A95F1F7CE010E94B626082F7C +:104E7000CE010E94A82694E09A95F1F7CE010E94F7 +:104E8000A6268CE38A95F1F7CE010E94B62682957C +:104E90008F70007F182F102BCE010E94A82694E05F +:104EA0009A95F1F7CE010E94A426912F90788BE07D +:104EB000E816F10430F08BE0E81AF10811F09111D6 +:104EC000C4CF8B81813021F4992311F08BEF8B8338 +:104ED00015B88FEF84B981E0911180E0DF91CF9117 +:104EE0001F910F91FF90EF900895CF93DF93EC0106 +:104EF00062E370E00E940927811102C08AEF8B8370 +:104F0000DF91CF9108951F93CF93DF93EC01162F7C +:104F10000E947527612F6068CE010E94F826CE019D +:104F2000DF91CF911F910C9475271F93CF93DF933F +:104F3000EC0115B88FEF84B98FE79BEB0197F1F780 +:104F400000C000001B8210E08A81882311F068E213 +:104F500001C068E0CE010E94F826111105C087E962 +:104F60009AE30197F1F704C08BE291E00197F1F722 +:104F700000C000001F5F143039F76CE0CE010E94C2 +:104F8000F82662E370E0CE010E940927811102C079 +:104F90008FEF1BC06CE0CE010E94F82662E370E048 +:104FA000CE010E940927811102C08DEF0EC061E081 +:104FB000CE010E94F82660EB74E0CE010E94092722 +:104FC000811102C08CEF01C081E08B83DF91CF9112 +:104FD0001F910895CF93DF93EC0181B1896081B96E +:104FE0008FEF84B98AB1806C8AB9CE010E9495276F +:104FF0008EE398E09F938F930E9443418B810F90A3 +:105000000F90813049F48AE398E09F938F930E9438 +:1050100043410F900F9010C0282F082E000C330B27 +:105020003F938F9380E398E09F938F930E94434137 +:105030000F900F900F900F90CE01DF91CF910C94B5 +:10504000C626CF93DF93FC012381213061F4EC016C +:105050000E9475276CE0CE010E94F826CE01DF91F8 +:10506000CF910C947527DF91CF910895CF93DF9363 +:10507000FC012381213061F4EC010E94752768E076 +:10508000CE010E94F826CE01DF91CF910C947527B6 +:10509000DF91CF910895CF93DF93FC0123812130DD +:1050A00061F4EC010E94752761E0CE010E94F826B0 +:1050B000CE01DF91CF910C947527DF91CF910895A8 +:1050C0000E944B2882B1867F82B981B1867F81B9E7 +:1050D00015B814B88BB18F738BB98AB18F738AB935 +:1050E0000895CF93DF93EC018B818130B9F4443183 +:1050F000A8F4613039F048F0623031F0633071F477 +:105100004C5A03C0405C01C04C5E642FCE010E942B +:105110008327CE01DF91CF910C947527DF91CF913A +:1051200008951F93CF93DF93FC0123812130A1F4D5 +:10513000162FEC010E94A426CE010E949E26612F0C +:10514000CE010E94CA26CE010E94A026CE01DF9188 +:10515000CF911F910C947527DF91CF911F910895E6 +:10516000FF920F931F93CF93DF938C0161114FC078 +:10517000C0E084E1F82ED0E2DC0F8C2F6F2D0E946E +:10518000603A911105C040E0682FC8010E94712863 +:105190006D2FC8010E949128C8010E947527CF5F1A +:1051A000C03549F78BE298E09F938F930E9443416B +:1051B000F80183810F900F90813049F488E298E0E4 +:1051C0009F938F930E9443410F900F9010C0282F00 +:1051D000082E000C330B3F938F938EE198E09F9342 +:1051E0008F930E9443410F900F900F900F9061E0BA +:1051F00070E080E090E00E94170A0196C1F364EF2E +:1052000071E080E090E00E94170A80E009C08AE126 +:1052100098E09F938F930E9443410F900F908FEFE0 +:10522000DF91CF911F910F91FF9008950F931F93DE +:10523000CF93DF93EC018B01F80161918F0166231D +:1052400039F08B81813021F4CE010E949128F4CF76 +:10525000DF91CF911F910F9108958BB18F708BB912 +:105260008AB1806F8AB908958AB18F708AB98BB17B +:105270008F708BB908958130910549F030F08230FC +:10528000910539F0039739F008955C9A08955D9A75 +:1052900008955E9A08955F9A0895CB0141110C9488 +:1052A0003B296130710551F038F06230710541F0F1 +:1052B0006330710539F008955C9808955D980895FC +:1052C0005E9808955F9808956130710559F038F03F +:1052D0006230710551F06330710559F008959BB14A +:1052E00080E105C09BB180E202C09BB180E48927C8 +:1052F00002C08BB180588BB90895CB010C943B2927 +:1053000040E00C944D29CF936031E8F5C62FC3706F +:10531000C23091F0C330B9F0C13039F063E070E0D1 +:105320000E94802980E090E014C060E070E00E945C +:10533000802981E090E00DC061E070E00E9480294A +:1053400082E090E006C062E070E00E94802983E085 +:1053500090E00E943B296C2F70E06F5F7F4F7F933E +:105360006F938DE498E09F938F930E94434164EF85 +:1053700071E080E090E00E94170A0F900F900F906C +:105380000F9080E001C08FEFCF9108950895FC0148 +:1053900012821092C8001092C9001092CA00109296 +:1053A000CD001092CC005A9884B18C7F84B985B11D +:1053B0008C7F85B908952F923F924F925F926F92A2 +:1053C0007F928F929F92AF92BF92CF92DF92EF9295 +:1053D000FF920F931F93CF93DF9300D000D0CDB7F0 +:1053E000DEB79C838B83611121C0289A299884B1F0 +:1053F000836084B95A9A82E08093C80088E98093D8 +:10540000C90086E08093CA001092CD008BE980939A +:10541000CC0081E0EB81FC81828386E399E09F935D +:105420008F930E9443410F900F903DC18FEF860FE5 +:10543000843008F06EC0633039F0643041F062307F +:1054400051F41EE801E009C015E500E002C01AEAC7 +:1054500001E0F12C04C011E000E0FF24F3941F925E +:105460001F931F92FF921F920F9387E199E09F93E2 +:105470008F930E9443410FB6F894DEBF0FBECDBF9D +:10548000FF2011F0289A01C02898002311F0299AD2 +:1054900001C02998EBE2F1E03197F1F700C000007C +:1054A000EB81FC8113821093CE0087EB9BE0019788 +:1054B000F1F700C000008381882389F084811F9266 +:1054C0008F9387E099E09F938F930E944341EB81F4 +:1054D000FC8113820F900F900F900F9008C086EF01 +:1054E00098E09F938F930E9443410F900F908CED13 +:1054F00098E09F938F930E9443410F900F906FEF1E +:105500007FEFCB010E94170A0196C9F32998289AC8 +:10551000CAC0653009F0BDC08FE998E09F938F93B2 +:105520000E944341299A28988BE291E00197F1F774 +:1055300000C000000F900F9081E9282E88E0382EDF +:1055400099E8492E98E0592E2BE7622E28E0722E1A +:1055500039E7832E38E0932E46E7E42E48E0F42E18 +:105560005EE6C52E58E0D52E62E6A62E68E0B62E81 +:10557000299AEB81FC81138200E711E0F801809108 +:10558000C80080648093C80081918093CE00809190 +:10559000C80085FFFCCF21E0E837F20781F7809152 +:1055A000C80086FFFCCF29983F922F920E9443416A +:1055B0000F900F90F80181918F011F928F935F924E +:1055C0004F920E9443410F900F900F900F90F1E087 +:1055D00008371F0779F764E670E080E090E00E94EA +:1055E000170A9A8389837F926F920E9443410F909A +:1055F0000F90EB81FC818381882311F010E01FC0A4 +:105600009F928F920E9443410F900F901DC01830BF +:1056100031F4FF92EF920E9443410F900F90EB8183 +:10562000FC81E10FF11D84811F928F93DF92CF9255 +:105630000E9443411F5F0F900F900F900F90EB81DE +:10564000FC818381181718F3EB81FC818381803101 +:1056500090F082899189208937853F932F939F937A +:105660008F93BF92AF920E9443410F900F900F9083 +:105670000F900F900F9089819A810196A1F468EEA6 +:1056800073E080E090E00E94170A019609F470CF61 +:105690000AC08EE598E09F938F930E9443410F903C +:1056A0000F908FEF07C064EF71E080E090E00E9400 +:1056B000170A80E00F900F900F900F90DF91CF911D +:1056C0001F910F91FF90EF90DF90CF90BF90AF9020 +:1056D0009F908F907F906F905F904F903F902F9012 +:1056E0000895FC012381203130F431E0320F3383FF +:1056F000E20FF11D64830895579810927C00109278 +:105700007A0014BC15BC24B1277E24B91398FC017F +:105710001282089580B183FB882780F991E0892760 +:1057200008952C9808952C9A0895CF93DF93EC0157 +:10573000579A80E680937C0087E880937A0083E81C +:1057400084BD84E085BD84B1886184B9139ACE019B +:105750000E94932B81E08A83DF91CF9108952F924D +:105760003F924F925F926F927F928F929F92AF92F1 +:10577000BF92CF92DF92EF92FF920F931F93CF933E +:10578000DF936111E1C0EC0187EC99E09F938F9367 +:105790000E9443410F900F9087EB482E89E0582ECE +:1057A00093EA692E99E0792E04E919E02AE8E22EBD +:1057B00029E0F22E3FE7C32E39E0D32E43E7A42E93 +:1057C00049E0B42E52E4252E59E0352E6BE5862EA5 +:1057D00069E0962E6AE070E080E090E00E94170A8F +:1057E000019609F0B3C080B183FB882780F91F922E +:1057F0008F938CEB99E09F938F930E9443410F907E +:105800000F900F900F90CE01039905C00E94912B2D +:105810005F924F9206C00E94932B82EB99E09F9378 +:105820008F930E9443410F900F9080917A00806483 +:1058300080937A0080917A0086FDFCCF8091790078 +:105840001F928F937F926F920E94434182EE8093CA +:105850007C008091790090E005970F900F900F9059 +:105860000F9097FF02C080E090E0809587BD1F9267 +:105870008F931F930F930E94434180917A0080641D +:1058800080937A000F900F900F900F9080917A0084 +:1058900086FDFCCF809179001F928F93FF92EF924B +:1058A0000E94434190E690937C0083B182FB88275D +:1058B00080F91F928F93DF92CF920E94434183B170 +:1058C00081701F928F93BF92AF920E944341F894D0 +:1058D0006B817C8178948DB79EB70C960FB6F89447 +:1058E0009EBF0FBE8DBF6115710519F17F936F9338 +:1058F00080E090E00E94A33D9B01AC0160E070E07D +:1059000080E792E40E94F53C27E137EB41ED58E354 +:105910000E94F53C0E94673D7F936F939F928F9208 +:105920000E9443410F900F900F900F900F900F9097 +:1059300051CF1F921F923F922F920E9443410F908E +:105940000F900F900F9046CF8FEF01C080E0DF9156 +:10595000CF911F910F91FF90EF90DF90CF90BF906C +:10596000AF909F908F907F906F905F904F903F90FF +:105970002F90089583B182FB882780F991E08927D1 +:10598000089583B1817008958BB180588BB90895C3 +:105990001F93CF93DF93EC0123B18091DB049091AF +:1059A000DC04122F117020FD1BC02091DF04222384 +:1059B00009F12091DD043091DE0423303105D0F06F +:1059C000820F931F9C838B831092DE041092DD0460 +:1059D0001092DC041092DB04CE010E94C42C0AC099 +:1059E000811520E4920748F501969093DC0480939A +:1059F000DB040DC08091DD049091DE04811520E46C +:105A00009207F0F401969093DE048093DD04809178 +:105A1000DB049091DC048115904438F48091DD041E +:105A20009091DE048115904410F01C821B8210932B +:105A3000DF04DF91CF911F91089580E090E4D5CFEE +:105A400080E090E4E0CFE4E6F0E080818470808341 +:105A5000179A0F9A2C9A84B1806B84B926988CB5CA +:105A600083658CBD0895269884B18F7584B90F988D +:105A700017981CBC089517980895179A08950F93C6 +:105A80001F93CF93DF93EC01062F142F0E943B2D21 +:105A900080E48EBD0DB407FEFDCF0EBD0DB407FE34 +:105AA000FDCF1EBD0DB407FEFDCFCE010E943D2DE2 +:105AB00084E18A95F1F780E0DF91CF911F910F91FA +:105AC00008951F93CF93DF93EC01162F0E943B2D77 +:105AD00081E48EBD0DB407FEFDCF1EBD0DB407FEE3 +:105AE000FDCF1EBC0DB407FEFDCFCE010E943D2DA3 +:105AF0008EB5DF91CF911F910895CF93DF93C42F7F +:105B0000D22F1F924F931F926F938AE59AE09F9333 +:105B10008F930E9443410F900F900F900F900F9022 +:105B20000F90CD1769F083E59AE09F938F930E94C1 +:105B300043410F900F90CF3F59F488E39AE002C0A1 +:105B400084E39AE09F938F930E9443410F900F90BC +:105B500082E39AE09F938F930E9443410F900F90AE +:105B6000DF91CF9108952F923F924F925F926F9263 +:105B70007F928F929F92AF92BF92CF92DF92EF92DD +:105B8000FF920F931F93CF93DF936111D8C0EC0165 +:105B900083E2282E8AE0382ECC24C394D12C2EE028 +:105BA000422E2AE0522E39EF632E39E0732E44EE56 +:105BB000A42E49E0B42E5FEC852E59E0952E64EFBB +:105BC00071E080E090E00E94170A019609F0B9C0E8 +:105BD0003F922F920E9443410F900F90E12CF12CA5 +:105BE00086010E2C01C0000F0A94EAF7402F409561 +:105BF00060E0CE010E943F2D402F62E1CE010E9465 +:105C00003F2DFF92EF925F924F920E94434162E1DB +:105C1000CE010E94612D202F482F62E1CE010E940B +:105C20007D2D68EC70E080E090E00E94170A40E073 +:105C300062E1CE010E943F2DFF92EF927F926F9220 +:105C40000E94434162E1CE010E94612D20E0482F75 +:105C500062E1CE010E947D2D4FEF60E0CE010E94F7 +:105C60003F2D68EC70E080E090E00E94170A8FEF13 +:105C7000E81AF80A8DB79EB708960FB6F8949EBF3B +:105C80000FBE8DBF98E0E916F10409F0A9CF00E03E +:105C900010E07601002E01C0EE0C0A94EAF74E2DBA +:105CA000409561E0CE010E943F2D4E2D63E1CE0173 +:105CB0000E943F2D1F930F93BF92AF920E944341CA +:105CC00063E1CE010E94612D2E2D482F63E1CE01AC +:105CD0000E947D2D68EC70E080E090E00E94170A41 +:105CE00040E063E1CE010E943F2D1F930F939F92EE +:105CF0008F920E94434163E1CE010E94612D20E01A +:105D0000482F63E1CE010E947D2D4FEF61E0CE016F +:105D10000E943F2D68EC70E080E090E00E94170A3E +:105D20000F5F1F4F8DB79EB708960FB6F8949EBFB2 +:105D30000FBE8DBF0830110509F0ABCF40CF8FEFFC +:105D400001C080E0DF91CF911F910F91FF90EF9004 +:105D5000DF90CF90BF90AF909F908F907F906F908B +:105D60005F904F903F902F90089580E480937C0047 +:105D700087E880937A00089510927C0010927A0050 +:105D800008950F931F93CF93DF9361113AC08CE96D +:105D90009AE09F938F930E9443410F900F9007E8E2 +:105DA0001AE0CAE7DAE06AE070E080E090E00E9482 +:105DB000170A019641F51F930F930E94434180916A +:105DC0007A00806480937A000F900F9080917A001F +:105DD00086FDFCCF20917800309179008091780089 +:105DE000909179003F932F939F938F93DF93CF935D +:105DF0000E9443410F900F900F900F900F900F90C3 +:105E0000D2CF8FEF01C080E0DF91CF911F910F9132 +:105E1000089582E480937C0087E880937A00089557 +:105E200010927C0010927A000895AF92BF92CF92A8 +:105E3000DF92EF92FF920F931F93CF93DF93611145 +:105E40007FC085EE9AE09F938F930E9443410F900D +:105E50000F9030EDE32E3AE0F32E03EC1AE0C3EAA4 +:105E6000DAE06AE070E080E090E00E94170A0196B4 +:105E700009F068C0FF92EF920E94434180917A003E +:105E8000806480937A000F900F9080917A0086FD55 +:105E9000FCCF20917800309179008091780090912A +:105EA00079003F932F939F938F931F930F930E949B +:105EB0004341609178007091790080E090E00E9409 +:105EC000A33D2AE939E941E852E40E94F53C2DEC72 +:105ED0003CEC4CE05FE30E94893CD62EC72EB82EE6 +:105EE000A92EA6019501652F742F832F922F0E9452 +:105EF0006E3D862F90E061701F926F9381FB222789 +:105F000020F91F922F9382FB222720F91F922F93B3 +:105F100023E0959587952A95E1F79F938F93AF920C +:105F2000BF92CF92DF92DF93CF930E9443418DB710 +:105F30009EB744960FB6F8949EBF0FBE8DBF91CF0B +:105F40008FEF01C080E0DF91CF911F910F91FF9003 +:105F5000EF90DF90CF90BF90AF900895442371F001 +:105F60006130710539F020F06230710529F0089533 +:105F700028980895299808952A9808956130710500 +:105F800039F020F06230710529F00895289A0895BB +:105F9000299A08952A9A08956130710541F020F0F8 +:105FA0006230710539F0089595B181E005C095B171 +:105FB00082E002C095B184E0892785B9089541E067 +:105FC0000C94AE2F40E00C94AE2FCF93DF93EC01F6 +:105FD00060E070E00E94E22F61E070E0CE010E947C +:105FE000E22F62E070E0CE010E94E22F84B1876070 +:105FF00084B9DF91CF910895CF93DF93EC0160E0F6 +:1060000070E00E94E22F61E070E0CE010E94E22F7A +:1060100062E070E0CE010E94E22F84B1887F84B9F3 +:10602000DF91CF910895CF93DF93EC01613009F4B4 +:106030003FC058F1623009F44EC0633009F064C0CB +:1060400060E070E00E94DF2F61E070E0CE010E940E +:10605000DF2F62E070E0CE010E94DF2F8BEE9AE02E +:106060009F938F930E94434168EB7BE080E090E038 +:106070000E94170A60E070E0CE010E94E22F61E00A +:1060800070E0CE010E94E22F36C060E070E00E9416 +:10609000DF2F8AEF9AE09F938F930E94434168EB32 +:1060A0007BE080E090E00E94170A60E070E025C08D +:1060B00061E070E00E94DF2F84EF9AE09F938F935E +:1060C0000E94434168EB7BE080E090E00E94170A69 +:1060D00061E070E012C062E070E00E94DF2F8FEE9E +:1060E0009AE09F938F930E94434168EB7BE080E0AE +:1060F00090E00E94170A62E070E0CE010E94E22F59 +:106100000F900F9080E001C08FEFDF91CF91089545 +:1061100047983F9AE8EBF0E02DE020832CE12083C4 +:1061200024E6208324E02093BC0021E0FC012483AA +:106130000895FC01148284E08093BC001092B800A2 +:10614000089589E99DE00895ECEBF0E08081806896 +:1061500080830895862F8695869586958E71982FD3 +:10616000990F990F890F6F70860F08950F931F93E2 +:10617000CF93DF938C01EA019E859C7F92609E877E +:1061800081E0611101C080E09E8580FB97F99E87C8 +:106190006F87998180FB90F99B7F98609983662334 +:1061A00089F01F929F931F926F938DED9BE09F93B9 +:1061B0008F930E9443410F900F900F900F900F907C +:1061C0000F9008C08CEC9BE09F938F930E944341FB +:1061D0000F900F900E5F1F4F21E0AE014F5F5F4F9A +:1061E00061E0C8010E94E3078823A1F0AE01425F8D +:1061F0005F4F22E06EE0C8010E94E307C82F8823AA +:1062000049F089EC9BE09F938F930E9443410F904C +:106210000F9009C083EC9BE09F938F930E944341B2 +:106220000F900F90C0E08C2FDF91CF911F910F91B5 +:106230000895CF92DF92EF92FF920F931F93CF9327 +:10624000DF937C01EA01479B10C084EB9BE09F93A6 +:106250008F930E9443413F9A4798AE0160E0C70187 +:106260000E94B6300F900F905CC082EB9BE09F9332 +:106270008F930E9443410F900F9009E010E080E758 +:10628000C82E8BE0D82E1F930F93DF92CF920E94DF +:10629000434168EE73E080E090E00E94320A0F9084 +:1062A0000F900F900F900130110531F0015011093E +:1062B0008F3F2FEF920739F34B9799F1AE016AE0C8 +:1062C000C7010E94B630898188608B7F8160898395 +:1062D000AE014F5F5F4F21E061E0C70102960E946F +:1062E000E3078CE59BE09F938F930E9443413F9A85 +:1062F000479A87E99AE30197F1F700C000003F98B9 +:10630000479868E873E180E090E00E94320A8AE2F0 +:106310009BE09F938F930E9443410F900F900F90AB +:106320000F9081E0DF91CF911F910F91FF90EF903F +:10633000DF90CF9008958F929F92AF92BF92CF92AD +:10634000DF92EF92FF920F931F93CF93DF93CDB71E +:10635000DEB727970FB6F894DEBF0FBECDBF4C0156 +:10636000362FCA011E2DFC2DEA2DBA01605D774043 +:1063700051E06536710508F450E04E8150FB47F955 +:106380004E8364E670E00E947A3A6AE00E94603AC6 +:106390008295807F982B9F8337FF02C0395FFCCFA7 +:1063A000373014F03750FCCF37708D81887F382B11 +:1063B0003D83121614F0245FFCCF2D3014F02C50C6 +:1063C000FCCF822F6AE00E946C3A9F702E81207F62 +:1063D000922B80FB94F99E83101614F0015EFCCF83 +:1063E000003214F00F51FCCF802F6AE00E946C3A0B +:1063F0009F703C81307C8370282F2295207F832FD3 +:10640000892B822B8C8317FF02C0185EFCCF1831BA +:1064100014F01851FCCF812F6AE00E946C3A9F70F3 +:106420003B81307C8370282F2295207F832F892BFE +:10643000822B8B83F7FF02C0F45CFCCFFC3314F09B +:10644000FC53FCCF8F2F6AE00E946C3A9F703A8118 +:1064500030788770282F2295207F832F892B822BDD +:106460008A83E7FF02C0E45CFCCFEC3314F0EC530A +:10647000FCCF8E2F6AE00E946C3A9F703981307891 +:106480008770282F2295207F832F892B822B898349 +:10649000CE0107969F938F9301979F938F930197B8 +:1064A0009F938F9301979F938F9301979F938F93C0 +:1064B00001979F938F938E010F5F1F4F1F930F9331 +:1064C00088E09BE09F938F930E94434178015E0197 +:1064D00088E0A80EB11C0FB6F894DEBF0FBECDBF8A +:1064E00082E0C82E8BE0D82EF70181917F011F92A8 +:1064F0008F93DF92CF920E9443410F900F900F90A5 +:106500000F90AE14BF0481F727E0A80162E0C40138 +:1065100002960E94E30727960FB6F894DEBF0FBEDF +:10652000CDBFDF91CF911F910F91FF90EF90DF9042 +:10653000CF90BF90AF909F908F9008952F923F92F1 +:106540004F925F926F927F928F929F92AF92BF9283 +:10655000CF92DF92EF92FF920F931F93CF93DF932F +:10656000CDB7DEB76E970FB6F894DEBF0FBECDBFC6 +:10657000611166C22C019C012E5F3F4F3D8F2C8F15 +:1065800061E5C9010E946007CE0101969A8F898F4B +:1065900080E1E98DFA8D11928A95E9F783E89DE013 +:1065A0009F938F930E9443418A8181608A8342E056 +:1065B000BE016F5F7F4F8C8D9D8D0E9438080F90BC +:1065C0000F90811103C087EE91E002C082EE91E04E +:1065D0009F938F930E9443410F900F908AE79DE015 +:1065E0009F938F930E94434182E69DE09F938F93F8 +:1065F0000E94434180E49DE09F938F930E9443411A +:106600008AE29DE09F938F930E94434180E19DE049 +:106610009F938F930E9443418AEF9CE09F938F93B7 +:106620000E94434183EE9CE09F938F930E944341DD +:106630008EEC9CE09F938F930E94434188EB9CE0FB +:106640009F938F930E94434180EA9CE09F938F9396 +:106650000E94434187E89CE09F938F930E944341AF +:106660000FB6F894DEBF0FBECDBF188E88E69CE053 +:106670009F938F930E94434100E19E012F5F3F4F04 +:1066800041E0BE01685E7F4F8C8D9D8D0E94800829 +:106690000F900F90811110C087EE91E09F938F9320 +:1066A0000E94434168EE73E080E090E00E94320A6D +:1066B0004C010F900F90BDC127E030E047E050E063 +:1066C000BE016D5F7F4FCE0141960E94A3409E01A7 +:1066D0002F5F3F4F790110E0812F837041F486E6F0 +:1066E0009CE09F938F930E9443410F900F90F7017E +:1066F00081917F011F928F9320E63CE03F932F937F +:106700000E9443411F5F0F900F900F900F90103128 +:1067100019F78E8987FD03C040ED57E002C044E3BE +:1067200058E08F89982F9695969596959E71292F6A +:10673000220F220F920F8F70890F1A01280E311C21 +:106740008E89982F9695969596959E71792E770CB1 +:10675000770C790E8F70780E672C8C89982F969510 +:10676000969596959E71B92EBB0CBB0CB90E8F7089 +:10677000B80EBB8E8B89982F9695969596959E719F +:10678000D92EDD0CDD0CD90E8F70D80EED2C8A8938 +:10679000982F9695969596959E71F92EFF0CFF0C65 +:1067A000F90E8F70F80ECF2C8989182F1695169533 +:1067B00016951E71912F990F990F190F8F70180F41 +:1067C000A12E0D890E8F073048F4E3E00E02C001C0 +:1067D00011249C012E55324F490104C03DE5832E02 +:1067E0003CE0932E86E59CE09F938F930E9443416B +:1067F0009F928F920E944341812F012E000C990B92 +:106800009F931F938F2D0F2C000C990B9F93FF923A +:106810008D2D0D2C000C990B9F93DF928B2D0B2C43 +:10682000000C990B9F93BF92872D072C000C990B9E +:106830009F937F923F922F92802F002E000C990BF6 +:106840009F930F9323E33CE03F932F930E94434198 +:1068500088891F928F93E3E2FCE0FF93EF930E94FD +:10686000434168EE73E080E090E00E94320A4C0100 +:106870000FB6F894DEBF0FBECDBF94E68916910423 +:1068800009F490C0F4F5FEE48F16910409F494C065 +:106890008CF438E48316910409F487C08DE48816DB +:1068A000910409F47BC094E48916910409F0C1C0F5 +:1068B000BA9479C0E7E58E16910409F485C044F4D2 +:1068C00023E58216910409F0B4C0AA24AA9478C0E2 +:1068D00039E58316910409F45AC083E688169104B9 +:1068E00009F0A7C08AE0A82E9CE0C92E21E1E22E83 +:1068F00000E128E048EE57E065E0C2010E949B31CC +:1069000098C090E789169104D1F194F4FDE68F16B2 +:10691000910409F440C02EE68216910409F449C09E +:1069200038E68316910409F084C0EE24E3943FC056 +:1069300084E788169104B1F044F4E3E78E169104DD +:1069400009F077C0AA24A3943BC0F7E78F169104FF +:10695000C9F129E78216910409F06BC03FEF231AB1 +:10696000330A34C08F8587FD02C06AE001C060E051 +:10697000AE014F5F5F4FC2010E94B6305AC0AE01F8 +:106980004F5F5F4F6AE0C2010E94193152C081E03F +:10699000281A31081BC06624639402C066246A94D6 +:1069A000670C14C0B394BB8E11C0EE24EA94ED0CB6 +:1069B0000DC0CC24C39402C0CC24CA94CF0C06C012 +:1069C000A10E04C00F5F01C001500E8F8A2D0A2C4A +:1069D000000C990B9F93AF928C2D0C2C000C990BF3 +:1069E0009F93CF928E2D0E2C000C990B9F93EF92BC +:1069F000EB8D8E2F0E2E000C990B9F93EF93862D0F +:106A0000062C000C990B9F936F923F922F922EEFC2 +:106A10003BE03F932F930E9443410B8D262DA10114 +:106A20006E8DC2010E949B310FB6F894DEBF0FBE7F +:106A3000CDBF9BE18916910409F017CE80E001C01B +:106A40008FEF6E960FB6F894DEBF0FBECDBFDF910D +:106A5000CF911F910F91FF90EF90DF90CF90BF905B +:106A6000AF909F908F907F906F905F904F903F90EE +:106A70002F90089560FF02C0289A01C0289861FFF6 +:106A800002C0299A01C0299862FF02C02A9A01C057 +:106A90002A9863FF02C02B9A01C02B9864FF02C0A2 +:106AA0002C9A01C02C9865FF02C02D9A01C02D9828 +:106AB00066FF02C02E9A01C02E9867FF02C02F9A6F +:106AC00001C02F9880918604813019F0823061F0E6 +:106AD000089570FF02C05E9A01C05E9871FF02C007 +:106AE0005F9A08955F98089570FF02C0129A01C0DE +:106AF000129871FF02C0139A089513980895809117 +:106B00008604813019F08230B1F0089560FF02C030 +:106B1000109A01C0109861FF02C0119A01C011982B +:106B200062FF02C0129A01C0129863FF02C0139A5A +:106B300008951398089560FF02C05C9A01C05C98A4 +:106B400061FF02C05D9A01C05D9862FF02C05E9A5B +:106B500001C05E9863FF02C05F9A08955F98089530 +:106B6000CF93DF93EC0160E070E00E943A3560E083 +:106B7000CE010E947F358FEF84B9809186048130E9 +:106B800041F0823061F481B18E6081B98AB1806F49 +:106B900005C081B18F6081B98AB1806E8AB9DF91F9 +:106BA000CF910895CF93DF93EC0160E070E00E94F5 +:106BB0003A3560E0CE010E947F3514B8809186049A +:106BC000813041F0823061F481B1817F81B98AB135 +:106BD0008F7005C081B1807F81B98AB18F718AB908 +:106BE000DF91CF91089580918604813019F0823031 +:106BF00039F00895662311F05D9808955D9A08951F +:106C0000662311F011980895119A0895CF92DF929A +:106C1000EF92FF920F931F93CF93DF937C0161114B +:106C200017C06FE00E947F356FEF73E0C7010E94CD +:106C30003A3561E0C7010E94F33583EE9DE09F93F2 +:106C40008F930E94434160ED77E080E090E028C0A0 +:106C5000613069F48FED9DE09F938F930E944341D3 +:106C600068EE73E080E090E00E94170A20C0623076 +:106C700039F460E071E00E943A3586ED9DE008C08D +:106C80006330C1F460E072E00E943A358DEC9DE023 +:106C90009F938F930E94434168EE73E080E090E001 +:106CA0000E94170A60E070E0C7010E943A350F9019 +:106CB0000F9044C0643208F043C0C62FD0E0249740 +:106CC0008E0183E0159507958A95E1F7C770DD275A +:106CD000CC24C394D12CB601002E01C0660F0A94B7 +:106CE000EAF7C7010E947F350C2E02C0CC0CDD1CD8 +:106CF0000A94E2F7B601C7010E943A35DF92CF92BB +:106D0000CC0FDD1FC05EDE4F89818F9388818F930A +:106D10001F930F9388EB9DE09F938F930E944341B5 +:106D200060E971E080E090E00E94170A8DB79EB79D +:106D300008960FB6F8949EBF0FBE8DBF80E001C0CD +:106D40008FEFDF91CF911F910F91FF90EF90DF9028 +:106D5000CF90089581B1807F81B982B18F6082B96F +:106D6000089582B1807F82B981B1807F81B9089511 +:106D70006130710581F058F06230710581F0633047 +:106D80007105A1F480B183FB882780F90CC080B124 +:106D900080958170089580B18695817004C080B11E +:106DA00082FB882780F991E08927089580E0089583 +:106DB0000F931F93CF93DF93603108F04EC08C0187 +:106DC000C62FC695C695D0E06370613021F0633060 +:106DD00009F44BC021C0BE010E94B836811145C0E4 +:106DE000CE0101969F938F9389EF9DE09F938F93A0 +:106DF0000E9443410F900F900F900F90BE01C80169 +:106E00000E94B83681112BC060E070E0CB010E9477 +:106E1000170A019621F5F2CFBE010E94B8368823E9 +:106E200021F1CE0101969F938F938BEE9DE09F936E +:106E30008F930E9443410F900F900F900F90BE01CF +:106E4000C8010E94B836882351F060E070E0CB01A1 +:106E50000E94170A019619F4F2CF8FEF07C06AE07B +:106E600070E080E090E00E94170A80E0DF91CF910F +:106E70001F910F910895CF93C82F8A3019F48DE098 +:106E80000E943B378091C80085FFFCCFC093CE00A5 +:106E900080E090E0CF9108955A9A22E02093C800B4 +:106EA00028E92093C90026E02093CA001092CD0063 +:106EB0002CE02093CC0020E331E03093E5042093D4 +:106EC000E40421E0FC0122830895FC011282109267 +:106ED000C8001092C9001092CA001092CD00109202 +:106EE000CC001092E5041092E40408950F931F93D0 +:106EF000CF93DF93611122C00BE21EE0CBE0DEE016 +:106F00001F930F930E944341DF93CF938091E50439 +:106F10008F938091E4048F930E94EC4068E873E1C2 +:106F200080E090E00E94170A0F900F900F900F9052 +:106F30000F900F90019621F380E001C08FEFDF9159 +:106F4000CF911F910F910895862F6091E404709165 +:106F5000E5040C943B370F931F93CF93DF93EC0121 +:106F60008B0180EA91E099838883CE0104960E9488 +:106F70001F0CCE01CD960E946815CE0187589F4FF9 +:106F80000E945507CE0185589F4F0E94BB08FE0105 +:106F9000E057FF4F10821B830A83DF91CF911F912F +:106FA0000F910895CF93DF93CDB7DEB7AC970FB6AF +:106FB000F894DEBF0FBECDBF87B18C6987B988B1A9 +:106FC000837688B93D98459A82E08093C00098E91D +:106FD0009093C10096E09093C2001092C5009CE08F +:106FE0009093C4008093B0008093B10096E9909391 +:106FF000B3008093700080E191E09093E30480936C +:10700000E20482E091E09093E1048093E0047894BC +:1070100086E2EEE3F1E0DE01119601900D928A9591 +:10702000E1F70E94BC090DEE11E0FFEEEF2EF1E05A +:10703000FF2E6E0127E2C20ED11C1E013BE2230E81 +:10704000311C6EE6462E61E0562E73E2672E72E02A +:10705000772EE1E6AE2EE1E0BE2E1F930F930E9445 +:107060004341FF92EF920E94434188E192E09F9357 +:107070008F930E94434122E731E03F932F930E9478 +:107080004341ACE2B2E0BF93AF930E9443415F92B1 +:107090004F920E9443417F926F920E944341FF9220 +:1070A000EF920E944341809186049FEF980F0FB6A4 +:1070B000F894DEBF0FBECDBF9230C8F40E94AF0976 +:1070C0009F938F93BF92AF920E944341FF92EF92A2 +:1070D0000E9443411F930F930E9443418EE491E02D +:1070E0009F938F930E9443411CA61BA60DC01F9225 +:1070F0008F9381E391E09F938F930E9443410F9080 +:107100000F900F900F90FFCF0FB6F894DEBF0FBE19 +:10711000CDBF8BA59CA58331910548F5FC01EE0FF1 +:10712000FF1FA1E0B0E0AC0FBD1FEA0FFB1F808086 +:1071300091809F938F9328E231E03F932F930E9499 +:107140004341D401ED91FC910680F781E02DC4010B +:1071500009959F938F930E9443411F930F930E9421 +:1071600043418BA59CA501969CA78BA7CDCF89E118 +:1071700091E09F938F930E94434110925D0410927F +:107180005C044091E0045091E10464E070E0C601C9 +:107190000E94C0403F922F9288E791E09F938F9387 +:1071A000DF92CF920E9469410FB6F894DEBF0FBE06 +:1071B000CDBF019709F051CF8BA59CA583319105D7 +:1071C00008F04BCF880F991FE1E0F0E0EC0FFD1FB6 +:1071D000E80FF91FA080B18085E191E09F938F9324 +:1071E0000E944341D501ED91FC910680F781E02D8D +:1071F000C50109959F938F930E94434181E191E0DE +:107200009F938F930E9443418FEF9FEF90930101D3 +:1072100080930001D501ED91FC910280F381E02D76 +:10722000C50109950F900F900F900F900F900F9040 +:10723000812C912C3AE0632E31E0732E44244A9441 +:10724000542C9F928F927F926F920E944341D5015E +:10725000ED91FC910190F081E02D682DC50109951B +:107260000F900F900F900F9087FD18C08091000134 +:10727000909101014B9739F48FEF9FEF90930101AB +:10728000809300010BC05092010140920001BFEFBA +:107290008B1A9B0A2FEF8216910499F6D501ED9176 +:1072A000FC910480F581E02DC5010995CACE84ECDE +:1072B00091E090935B0480935A0481E492E0909370 +:1072C0005904809358048CE092E090935704809383 +:1072D000560484E292E090935404809353041092F5 +:1072E000550484EF91E0909352048093510482E915 +:1072F00091E090934E0480934D04109250041092AC +:107300004F0480E092E090934C0480934B048CED0A +:1073100091E09093470480934604109248041092A1 +:107320004A041092490488EE91E0909345048093BA +:10733000440488EB91E0909341048093400481E001 +:1073400090918604913009F480E080934204109279 +:1073500043048DE492E090933E0480933D041092A8 +:107360003F0480ED91E090932A04809329041092C9 +:107370002B0410922C048CEA91E0909325048093C6 +:107380002404109226048FEF9FEF9093280480939B +:10739000270460E070E083E993E00E94AB3761E08E +:1073A00070E082E093E00E94AB3762E070E081E73A +:1073B00092E00E94AB3788E192E090936B02809359 +:1073C0006A028CE692E00E94550710926E021092BB +:1073D000700210926F0286E891E0909361028093B0 +:1073E00060021092680221E030E03093670220933F +:1073F000660210926202109263021092640210926E +:107400006502909357028093560210925E0282E0CA +:1074100090E090935D0280935C021092580210926B +:10742000590210925A0210925B02089588E994E082 +:107430000E941F0C88E191E090939704809396043A +:107440009093950480939404909393048093920472 +:1074500008958EE296E0089582E198E0089589E427 +:1074600098E008958AE598E008958BE399E00895FF +:1074700089EC99E0089582E79AE008958EE99AE010 +:10748000089587EE9AE008958EEF9AE0089586EECB +:107490009DE0089584E09EE008958BE49EE00895C9 +:1074A000DB018F939F930E94AD3ABF91AF91A29F52 +:1074B000800D911DA39F900DB29F900D11240895F2 +:1074C000991B79E004C0991F961708F0961B881F36 +:1074D0007A95C9F78095089587FB082E062687FDC3 +:1074E000819567FD61950E94603A0EF4919507FCC5 +:1074F00081950895AA1BBB1B51E107C0AA1FBB1FA2 +:10750000A617B70710F0A61BB70B881F991F5A952F +:10751000A9F780959095BC01CD010895052E97FBA4 +:107520001EF400940E94A53A57FD07D00E94513CDA +:1075300007FC03D04EF40C94A53A50954095309535 +:1075400021953F4F4F4F5F4F0895909580957095CF +:1075500061957F4F8F4F9F4F08950E94793CA59F63 +:10756000900DB49F900DA49F800D911D112408953E +:10757000B7FF0C94AD3A0E94AD3A821B930B08956D +:10758000DF93CF931F930F939A9DF02D219FF00DC2 +:107590008B9DF00D8A9DE02DF10D039FF00D029F54 +:1075A000E00DF11D4E9DE00DF11D5E9DF00D4F9D16 +:1075B000F00D7F936F93BF92AF925F934F93D5017E +:1075C0000E94793C8B01AC01D7010E94793CEB0110 +:1075D000E80FF91FD6010E94103B2F913F91D60171 +:1075E0000E94793CC60FD71FE81FF91FAF91BF91CA +:1075F0000E94103B2F913F910E94793CC60FD71FEC +:10760000E81FF91FD6010E94793CE60FF71F980189 +:10761000BE01CF0111240F911F91CF91DF910895E9 +:107620000E94793C460F571FC81FD91F08F4319696 +:107630000895689401C0E894F92FF12B12F00C948E +:107640004D3BA0E0B0E0E7E2FBE30C94BF3B092E2A +:10765000059422F40E94A93B112392F4F0E80F262E +:10766000FFEFE094F09400951095B094C094D094FE +:10767000A194BF0ACF0ADF0AEF0AFF0A0F0B1F0B04 +:107680000E94583B07FC0E94A93BCDB7DEB7ECE057 +:107690000C94DB3B689401C0E8948F929F92CF9347 +:1076A000DF930E94583BDF91CF919F908F90089578 +:1076B00088249924F401E401B0E49F93AA279A1541 +:1076C0008B049C04ED05FE05CF05D007A10798F4B7 +:1076D000AD2FDC2FCF2FFE2FE92D982C892E982F40 +:1076E000872F762F652F542F432F322F2227B85004 +:1076F00031F7BF9127C01B2EBF91BB27220F331F2D +:10770000441F551F661F771F881F991F881C991CCF +:10771000EE1FFF1FCC1FDD1FAA1FBB1F8A149B0477 +:10772000EC05FD05CE05DF05A007B10748F08A1876 +:107730009B08EC09FD09CE09DF09A00BB10B216004 +:107740001A94E1F62EF49401AF01BE01CD01000CB4 +:1077500008956095709580959095309540955095D9 +:1077600021953F4F4F4F5F4F6F4F7F4F8F4F9F4F31 +:1077700008952F923F924F925F926F927F928F92D5 +:107780009F92AF92BF92CF92DF92EF92FF920F93B0 +:107790001F93CF93DF93CDB7DEB7CA1BDB0B0FB6BA +:1077A000F894DEBF0FBECDBF09942A883988488877 +:1077B0005F846E847D848C849B84AA84B984C8840D +:1077C000DF80EE80FD800C811B81AA81B981CE0F04 +:1077D000D11D0FB6F894DEBF0FBECDBFED010895E9 +:1077E0000F93083090F0982F872F762F652F542F06 +:1077F000432F322F22270850F4CF220F331F441F6C +:10780000551F661F771F881F991F0A95B2F70F91A2 +:10781000089597FB10F8169400080F93083098F01D +:107820000850232F342F452F562F672F782F892F5D +:10783000902DF4CF059497958795779567955795F3 +:107840004795379527950A95AAF70F9108952A0D20 +:107850003B1D4C1D5D1D6E1D7F1D801F911F0895DA +:107860000024A7FD00942A0F301D401D501D601DEF +:10787000701D801D901D08952A193B094C095D0952 +:107880006E097F09800B910B08950024A7FD0094D9 +:107890002A173005400550056005700580059005E4 +:1078A0000895A1E21A2EAA1BBB1BFD010DC0AA1F41 +:1078B000BB1FEE1FFF1FA217B307E407F50720F059 +:1078C000A21BB30BE40BF50B661F771F881F991FD4 +:1078D0001A9469F760957095809590959B01AC011D +:1078E000BD01CF010895EE0FFF1F0590F491E02D2B +:1078F0000994A29FB001B39FC001A39F700D811D89 +:107900001124911DB29F700D811D1124911D0895A8 +:107910005058BB27AA270E94A03C0C94453E0E94C9 +:10792000373E38F00E943E3E20F039F49F3F19F474 +:1079300026F40C94243E0EF4E095E7FB0C941E3ED6 +:10794000E92F0E94563E58F3BA176207730784075F +:10795000950720F079F4A6F50C94783E0EF4E095A6 +:107960000B2EBA2FA02D0B01B90190010C01CA01F9 +:10797000A0011124FF27591B99F0593F50F4503EA4 +:1079800068F11A16F040A22F232F342F4427585F96 +:10799000F3CF469537952795A795F0405395C9F7AE +:1079A0007EF41F16BA0B620B730B840BBAF0915066 +:1079B000A1F0FF0FBB1F661F771F881FC2F70EC005 +:1079C000BA0F621F731F841F48F4879577956795D8 +:1079D000B795F7959E3F08F0B0CF9395880F08F0C4 +:1079E0009927EE0F9795879508950E94093D0C946D +:1079F000453E0E943E3E58F00E94373E40F029F43A +:107A00005F3F29F00C941E3E51110C94793E0C946A +:107A1000243E0E94563E68F39923B1F3552391F317 +:107A2000951B550BBB27AA2762177307840738F0ED +:107A30009F5F5F4F220F331F441FAA1FA9F335D04A +:107A40000E2E3AF0E0E832D091505040E695001CFE +:107A5000CAF72BD0FE2F29D0660F771F881FBB1FB8 +:107A6000261737074807AB07B0E809F0BB0B802D96 +:107A7000BF01FF2793585F4F3AF09E3F510578F0C2 +:107A80000C941E3E0C94793E5F3FE4F3983ED4F391 +:107A9000869577956795B795F7959F5FC9F7880F96 +:107AA000911D9695879597F90895E1E0660F771FE8 +:107AB000881FBB1F621773078407BA0720F0621B79 +:107AC000730B840BBA0BEE1F88F7E09508950E94A4 +:107AD0006E3D6894B1110C94793E08950E945E3E0B +:107AE00088F09F5798F0B92F9927B751B0F0E1F07F +:107AF000660F771F881F991F1AF0BA95C9F714C02F +:107B0000B13091F00E94783EB1E008950C94783E37 +:107B1000672F782F8827B85F39F0B93FCCF3869567 +:107B200077956795B395D9F73EF4909580957095C4 +:107B300061957F4F8F4F9F4F089597FB16F40E94DA +:107B4000273E0C94E13DE89409C097FB3EF49095E4 +:107B50008095709561957F4F8F4F9F4F9923A9F026 +:107B6000F92F96E9BB279395F695879577956795B5 +:107B7000B795F111F8CFFAF4BB0F11F460FF1BC0F9 +:107B80006F5F7F4F8F4F9F4F16C0882311F096E98C +:107B900011C0772321F09EE8872F762F05C066233A +:107BA00071F096E8862F70E060E02AF09A95660FF3 +:107BB000771F881FDAF7880F9695879597F90895AC +:107BC000E894F92F96EBFF2381F0121613061406A2 +:107BD000440B9395F6958795779567955795404013 +:107BE000FF23B9F71BC099270895882351F49850B3 +:107BF000D2F7872B762F652F542F432F322F20E07B +:107C0000B1F3121613061406440B88233AF09A9522 +:107C1000440F551F661F771F881FCAF755234AF464 +:107C2000440F551F11F460FF04C06F5F7F4F8F4FEB +:107C30009F4F880F9695879597F9089597F99F67B5 +:107C400080E870E060E008959FEF80EC08959095E3 +:107C500080957095609550954095309521953F4F52 +:107C60004F4F5F4F6F4F7F4F8F4F9F4F08950024AF +:107C70000A941616170618060906089500240A9491 +:107C800012161306140605060895092E0394000C17 +:107C900011F4882352F0BB0F40F4BF2B11F460FFA6 +:107CA00004C06F5F7F4F8F4F9F4F089557FD9058CF +:107CB000440F551F59F05F3F71F04795880F97FBB0 +:107CC000991F61F09F3F79F087950895121613066A +:107CD0001406551FF2CF4695F1DF08C01616170699 +:107CE0001806991FF1CF86957105610508940895CE +:107CF000E894BB2766277727CB0197F908950E9460 +:107D0000923E0C94453E0E94373E38F00E943E3E23 +:107D100020F0952311F00C941E3E0C94243E112467 +:107D20000C94793E0E94563E70F3959FC1F3950FD7 +:107D300050E0551F629FF001729FBB27F00DB11DEF +:107D4000639FAA27F00DB11DAA1F649F6627B00D7F +:107D5000A11D661F829F2227B00DA11D621F739F68 +:107D6000B00DA11D621F839FA00D611D221F749F76 +:107D70003327A00D611D231F849F600D211D822FBD +:107D8000762F6A2F11249F5750409AF0F1F08823E4 +:107D90004AF0EE0FFF1FBB1F661F771F881F915011 +:107DA0005040A9F79E3F510580F00C941E3E0C9464 +:107DB000793E5F3FE4F3983ED4F3869577956795D7 +:107DC000B795F795E7959F5FC1F7FE2B880F911D3B +:107DD0009695879597F90895FA01EE0FFF1F309653 +:107DE00021053105A1F16115710561F48038BFE30A +:107DF0009B0749F168949038810561F08038BFEFA6 +:107E00009B0741F099234AF5FF3FE1053105210524 +:107E100019F1E8940894E795D901AA2329F4AB2F26 +:107E2000BE2FF85FD0F310C0FF5F70F4A695E0F7A7 +:107E3000F73950F019F0FF3A38F49F779F930DD03F +:107E40000F9007FC9058089546F00C94243E60E093 +:107E500070E080E89FE308954FE79F775F934F932B +:107E60003F932F930E9410402F913F914F915F912C +:107E70000E947F3E0C94493F0E947B3F880B990BE8 +:107E8000089529F416F00C941E3E0C94783E0C9440 +:107E9000243E0E945E3EA8F39638A0F707F80F92A2 +:107EA000E8942BE33AEA48EB5FE70E94953E0F9295 +:107EB0000F920F924DB75EB70F920E945840ECE7B9 +:107EC000F0E00E949F3F4F915F91EF91FF91E59508 +:107ED000EE1FFF1F49F0FE57E0684427EE0F441FD6 +:107EE000FA95E1F74195550B0E94D23F0F9007FE9E +:107EF0000C94C63F0895990F0008550FAA0BE0E8AF +:107F0000FEEF16161706E807F907C0F0121613065B +:107F1000E407F50798F0621B730B840B950B39F49B +:107F20000A2661F0232B242B252B21F408950A2601 +:107F300009F4A140A6958FEF811D811D0895DF935F +:107F4000CF931F930F93FF92EF92DF927B018C01EF +:107F5000689406C0DA2EEF010E94923EFE01E8947A +:107F6000A5912591359145915591A6F3EF010E9478 +:107F7000A03CFE019701A801DA9469F7DF90EF9029 +:107F8000FF900F911F91CF91DF9108959B01AC015C +:107F900060E070E080E89FE30C94F53C0C941E3E9A +:107FA0000C948C400E945E3ED8F39923C9F3940F41 +:107FB000511DA3F39150504094F059F0882332F0B2 +:107FC000660F771F881F91505040C1F79E3F5105A3 +:107FD0002CF7880F911D9695879597F908955F3F27 +:107FE000ACF0983E9CF0BB27869577956795B79542 +:107FF00008F4B1609395C1F7BB0F58F711F460FF17 +:10800000E8CF6F5F7F4F8F4F9F4FE3CF0C94793E48 +:1080100016F00C948C400C94243E68940C941E3EF4 +:108020000E945E3EA8F39923C1F3AEF3DF93CF9392 +:108030001F930F93FF92C92FDD2788232AF02197E2 +:10804000660F771F881FDAF720E030E040E85FEB2B +:108050009FE3883920F0803E38F021968F770E9488 +:10806000893CE4EAF0E004C00E94893CE1EDF0E0E4 +:108070000E949F3F8B01BE01EC01FB2E6F577109DF +:108080007595771F880B990B0E94A53D28E132E773 +:1080900041E35FE30E94923EAF2D9801AE01FF9055 +:1080A0000F911F91CF91DF910E94A03C0C94453E0F +:1080B000FA01DC01AA0FBB1F9B01AC01BF5728F4DA +:1080C000222733274427507820C0B75190F4AB2F94 +:1080D0000024469537952795011CA395D2F30020DF +:1080E00071F0220F331F441FB395DAF30ED00C94B6 +:1080F000883C61307105A0E88A07B94630F49B01DD +:10810000AC016627772788279078309621F0208366 +:1081100031834283538308959F3F31F0915020F47F +:10812000879577956795B795880F911D9695879553 +:1081300097F90895FB01DC0102C005900D924150B2 +:108140005040D8F70895FB01DC012150304030F059 +:1081500001900D920416C9F7CD010895882799273B +:108160000895FB01DC014150504048F001900D9210 +:108170000020C9F701C01D9241505040E0F708951A +:10818000A0E0B0E0E6ECF0E40C94C33BFA012381FC +:1081900020FD03C080E090E01AC016161706D4F741 +:1081A0007A018C01EB016C01C130D10569F0C70186 +:1081B0000E943A468F3FFFEF9F0761F3F6018193DC +:1081C0006F0121970A9781F7F6011082C801CDB798 +:1081D000DEB7E8E00C94DF3BA0E0B0E0E2EFF0E4D3 +:1081E0000C94C73B0F811885F801838188608383D5 +:1081F000AE01455F5F4F69857A85C8010E94824163 +:10820000F8012381277F2383E4E00C94E33B0F9361 +:108210001F93CF93DF93FB01238121FD03C08FEFD9 +:108220009FEF2CC022FF16C04681578124813581E3 +:108230004217530744F4A081B1819D012F5F3F4F46 +:10824000318320838C93268137812F5F3F4F378383 +:10825000268314C08B01EC01FB010084F185E02D25 +:108260000995892BE1F6D80116968D919C91179767 +:10827000019617969C938E931697CE01DF91CF911E +:108280001F910F910895A0E0B0E0E9E4F1E40C94AF +:10829000C73BAE01495F5F4FDA016D917D91AD0142 +:1082A00000EE14E0F80182819381DC0113962C9199 +:1082B0001397286013962C930E948241D80112963E +:1082C000ED91FC9113972381277F2383E4E00C94A5 +:1082D000E33BAEE0B0E0EFE6F1E40C94C93B85E0AF +:1082E0008C838B899C899A838983AE01495E5F4F19 +:1082F0006D897E89CE0101960E94FF442E96E2E0B0 +:108300000C94E53BABE0B0E0E8E8F1E40C94B93B59 +:108310006C017B018A01FC0117821682838181FF37 +:10832000CCC1CE0101963C01F6019381F70193FD8A +:10833000859193FF81917F01882309F4BAC1853229 +:1083400039F493FD859193FF81917F01853229F462 +:10835000B60190E00E940741E7CF912C212C312CEF +:10836000FFE1F315D8F08B3279F038F4803279F0F0 +:108370008332A1F4232D20611DC08D3261F0803342 +:1083800069F4232D216016C0832D8260382EE32DE1 +:10839000E4603E2E2AC0F32DF8601DC037FC2DC0CE +:1083A00020ED280F2A3040F08E32B9F436FC81C11E +:1083B000232D2064322E19C036FE06C08AE0989E16 +:1083C000200D1124922E11C0EAE02E9E200D1124C2 +:1083D000222EF32DF0623F2E08C08C3621F4832D1F +:1083E0008068382E02C0883641F4F70193FD8591EC +:1083F00093FF81917F018111B3CF982F9F7D955479 +:10840000933028F40C5F1F4F9FE399830DC0833690 +:1084100031F0833771F0833509F059C021C0F8017C +:10842000808189830E5F1F4F88248394912C530190 +:1084300013C02801F2E04F0E511CF801A080B1805A +:1084400036FE03C0692D70E002C06FEF7FEFC501FB +:108450000E942F464C018201F32DFF773F2E16C05C +:10846000280122E0420E511CF801A080B18036FEA6 +:1084700003C0692D70E002C06FEF7FEFC5010E945D +:1084800024464C01F32DF0683F2E820133FC1BC0C3 +:10849000822D90E088169906B0F4B60180E290E053 +:1084A0000E9407412A94F4CFF50137FC859137FEED +:1084B00081915F01B60190E00E94074121102A944A +:1084C00021E0821A91088114910471F7E8C0843682 +:1084D00011F0893641F5F80137FE07C060817181DE +:1084E000828193810C5F1F4F08C060817181072ECC +:1084F000000C880B990B0E5F1F4FF32DFF763F2E5C +:1085000097FF09C090958095709561957F4F8F4F2B +:108510009F4FF0683F2E2AE030E0A3010E94914671 +:10852000882E861845C0853731F4232D2F7EB22E34 +:108530002AE030E025C0932D997FB92E8F36C1F007 +:1085400018F4883579F0B5C0803719F0883721F0F4 +:10855000B0C0E92FE061BE2EB4FE0DC0FB2DF4606B +:10856000BF2E09C034FE0AC0292F2660B22E06C0D5 +:1085700028E030E005C020E130E002C020E132E038 +:10858000F801B7FE07C060817181828193810C5F21 +:108590001F4F06C06081718180E090E00E5F1F4F29 +:1085A000A3010E949146882E8618FB2DFF773F2E4F +:1085B00036FE0DC0232D2E7FA22E891458F434FED2 +:1085C0000BC032FC09C0832D8E7EA82E05C0B82CAE +:1085D000A32C03C0B82C01C0B92CA4FE0FC0FE010F +:1085E000E80DF11D8081803321F49A2D997EA92E0A +:1085F00009C0A2FE06C0B394B39404C08A2D867845 +:1086000009F0B394A3FC11C0A0FE06C0B21488F414 +:10861000280C922C9B180EC0B21460F4B60180E2B4 +:1086200090E00E940741B394F7CFB21418F42B18CE +:1086300002C0982C212CA4FE10C0B60180E390E06B +:108640000E940741A2FE17C0A1FC03C088E790E08A +:1086500002C088E590E0B6010CC08A2D867859F0FA +:10866000A1FE02C08BE201C080E2A7FC8DE2B60150 +:1086700090E00E940741891438F4B60180E390E04D +:108680000E9407419A94F7CF8A94F301E80DF11DF7 +:108690008081B60190E00E9407418110F5CF222031 +:1086A00009F442CEB60180E290E00E9407412A948C +:1086B000F6CFF6018681978102C08FEF9FEF2B9650 +:1086C000E2E10C94D53B20FD09C0FC0123FD05C06F +:1086D00022FF02C07383628351834083089544FD67 +:1086E00017C046FD17C0AB01BC01DA01FB01AA0FA0 +:1086F000BB1FEE1FFF1F1094D1F74A0F5B1F6E1FA9 +:108700007F1FCB01BA01660F771F881F991F09C011 +:1087100033E001C034E0660F771F881F991F315086 +:10872000D1F7620F711D811D911D08950F931F9345 +:10873000CF93DF938C01C8010E943A46EC0197FD6C +:1087400008C00E941046892BB1F7B801CE010E94E3 +:108750007846CE01DF91CF911F910F9108958F92AE +:108760009F92AF92BF92EF92FF920F931F93CF937E +:10877000DF938C01D62F7A01B22E0E943A469C01DB +:1087800033272B32310531F02D32310561F48B2D39 +:108790008068B82ED15011F480E068C0C8010E94F2 +:1087A0003A4697FDF9CFCB2DCD7F2B2D207309F5C0 +:1087B0008033F9F4AA24AA94AD0E09F443C0C80189 +:1087C0000E943A4697FD3EC09C012F7D33272835F5 +:1087D000310549F4C264D250A9F1C8010E943A4659 +:1087E00097FF07C02FC0B6FE02C0C26001C0C261C1 +:1087F000DA2D812C912C540120ED280F283080F0A7 +:10880000C4FF04C0B8010E94784619C02A3040F065 +:10881000C6FFF8CF2F7D3FEE320F363098F7275046 +:108820004C2FC501B4010E946F434B015C01C26033 +:10883000D15059F0C8010E943A4697FFDDCFC1FDE3 +:1088400004C0AACF812C912C5401C7FF08C0B0945A +:10885000A09490948094811C911CA11CB11C2C2F7D +:10886000B501A401C7010E94634381E0DF91CF916C +:108870001F910F91FF90EF90BF90AF909F908F90BE +:108880000895A0E2B0E0E7E4F4E40C94BC3B5C01A2 +:10889000962E7A01F9018E010F5F1F4F680180E269 +:1088A000D8011D928A95E9F7D50113968C9080E046 +:1088B00090E0612C712C30E061E070E083FC259148 +:1088C00083FE21918F01522E211103C080E090E0A0 +:1088D00092C02E3511F4009751F1432F50E0481704 +:1088E00059073CF42D3559F12D3219F4772009F14F +:1088F00003C0772009F46AC0452D469546954695F4 +:10890000D601A40FB11D452D47708B0102C0000F89 +:10891000111F4A95E2F7A8015C91452B4C93651411 +:1089200059F0561410F45394E7CF5A94E5CF31E040 +:1089300004C07724739401C0712C0196BFCF7720B7 +:1089400019F08E8180628E83311103C08824839454 +:1089500017C0F6019E012F5D3F4F80818095819366 +:108960002E173F07D1F7F2CFE114F10429F0D70118 +:108970008C93F70131967F019A94812C9920F9F01C +:10898000C5010E943A4697FD18C0FC01FF2723E06D +:10899000F595E7952A95E1F7EC0DFD1D208130E076 +:1089A000AC014770552702C0359527954A95E2F7E7 +:1089B00020FDDACFB5010E947846811087CFE114FF +:1089C000F10411F0D7011C92C80115C0422F469541 +:1089D00046954695D601A40FB11D422F47708B01D5 +:1089E00002C0000F111F4A95E2F7A8015C91452BC8 +:1089F0004C93622EA2CFA096EFE00C94D83BA0E05F +:108A0000B0E0E5E0F5E40C94BC3B6C01EB015A01ED +:108A1000FC0117821682512CF601E380FE01E3FC73 +:108A20008591E3FE8191182FEF01882309F4EEC0B0 +:108A300090E00E941046892B21F0C6010E949643C7 +:108A4000EBCF153241F4FE01E3FC1591E3FE1191E9 +:108A5000EF01153281F4C6010E943A4697FDD4C059 +:108A6000412F50E09C01332724173507A9F2B601A6 +:108A70000E947846CBC01A3239F4E3FC1591E3FE2C +:108A80001191EF0101E001C000E0F12C20ED210F78 +:108A90002A3080F402606F2D70E080E090E040E2C8 +:108AA0000E946F43F62EFE01E3FC1591E3FE119147 +:108AB000EF01ECCF01FF03C0F11003C0A7C0FF24FA +:108AC000FA94183619F01C3651F010C0FE01E3FC80 +:108AD0001591E3FE1191EF01183641F4086004602E +:108AE000FE01E3FC1591E3FE1191EF01112309F45E +:108AF0008DC0612F70E08EEF90E00E941946892BA7 +:108B000009F484C000FD07C0F50180809180C50193 +:108B100002965C0102C0812C912C1E3651F4F601A4 +:108B20004681578160E070E0202FC4010E946343BA +:108B300073CF1336A9F401FD02C0FF24F394C601DC +:108B40000E943A4697FD60C08114910429F0F40117 +:108B50008083C40101964C01FA94F110F0CF50C00B +:108B60001B3559F49E01A4016F2DC6010E9441449A +:108B7000EC01892B09F044C03EC0C6010E94964317 +:108B800097FD42C01F3661F128F4143639F11936C9 +:108B900051F128C0133771F0153701F123C081144A +:108BA000910429F0F4016082C40101964C01FA9409 +:108BB000FF2071F0C6010E943A463C0197FD08C0B3 +:108BC0000E941046892B59F3B601C3010E947846D2 +:108BD00081149104A9F0F401108212C0006203C054 +:108BE000006101C00064202FA4016F2DC6010E9406 +:108BF000AF43811105C0F6018381807329F406C05B +:108C000000FD0ACF539408CF552019F0852D90E030 +:108C100002C08FEF9FEFCDB7DEB7EFE00C94D83BEB +:108C200091110C94EF46803219F089508550C8F7A5 +:108C30000895FC010590061621F00020D9F7C00127 +:108C400008953197CF010895FC010590615070405F +:108C50000110D8F7809590958E0F9F1F0895FC0105 +:108C60006150704001900110D8F7809590958E0F5B +:108C70009F1F0895CF93DF93EC012B8120FF33C01A +:108C800026FF0AC02F7B2B838E819F8101969F83B5 +:108C90008E838A8190E029C022FF0FC0E881F9818C +:108CA0008081082E000C990B009719F420622B8309 +:108CB0001AC03196F983E8830EC0EA85FB850995D1 +:108CC00097FF09C02B81019611F080E201C080E17D +:108CD000822B8B8308C02E813F812F5F3F4F3F83C4 +:108CE0002E83992702C08FEF9FEFDF91CF910895D8 +:108CF000FB01238120FF12C026FD10C08F3F3FEFF4 +:108D0000930761F082832F7D20642383268137813E +:108D10002150310937832683992708958FEF9FEFDC +:108D20000895FA01AA27283051F1203181F1E89401 +:108D30006F936E7F6E5F7F4F8F4F9F4FAF4FB1E04E +:108D40003ED0B4E03CD0670F781F891F9A1FA11D49 +:108D5000680F791F8A1F911DA11D6A0F711D811D4A +:108D6000911DA11D20D009F468943F912AE0269F0F +:108D700011243019305D3193DEF6CF010895462F6E +:108D80004770405D4193B3E00FD0C9F7F6CF462F4F +:108D90004F70405D4A3318F0495D31FD40524193B8 +:108DA00002D0A9F7EACFB4E0A69597958795779575 +:108DB0006795BA95C9F700976105710508959B01FC +:108DC000AC010A2E06945795479537952795BA9585 +:108DD000C9F7620F731F841F951FA01D089599275F +:088DE00088270895F894FFCFE5 +:108DE800FFFF000000010000000000003D09000036 +:108DF80000000002000000005E09000000000303FC +:108E08002C022E02300232023402360238023A02B2 +:108E180000000002000000003B37000000005A0478 +:108E280058045604530451044D044B0446044404A6 +:108E380040043D04290424040203710293036A02D6 +:108E4800600256020A0427041704C507BA07B007C8 +:108E580001040000000271CB257800424D453238EC +:108E68003000000000004E209E21AB199A19000026 +:108E780000000B22F8210222293A3F0000000000DE +:108E8800D422AF22C6229E22000000002C26F625FE +:108E980014262C3A00000000B028EA2760282F3A50 +:108EA8000000000083292D293429323A00000000EF +:108EB800DB29C629C729353A00000000AF2B952BBE +:108EC8007C2B383A00000000B32D232D332D3B3A7C +:108ED80000000000C12EB52EBC2E3E3A0000000056 +:108EE800152F092F102F413A000000001330E52FED +:108EF800FC2F443A000000009E3288309930A1309F +:108F0800000000000636B035D235473A410042002D +:108F1800430044004500460047004450000000005C +:108F280000D836AA36B1364A3A0000000076374CE7 +:068F38003765374D3A00D9 +:00000001FF diff --git a/software/test-software/nano-644/src b/software/test-software/nano-644/src new file mode 120000 index 0000000..5cd551c --- /dev/null +++ b/software/test-software/nano-644/src @@ -0,0 +1 @@ +../src \ No newline at end of file diff --git a/software/test-software/src/adafruit/bme280.cpp b/software/test-software/src/adafruit/bme280.cpp new file mode 100644 index 0000000..1836c56 --- /dev/null +++ b/software/test-software/src/adafruit/bme280.cpp @@ -0,0 +1,512 @@ +#include "bme280.h" +#include +#include + +Adafruit_BME280 theBME280; +Adafruit_BME280_Temp bm280TempSensor; +Adafruit_BME280_Pressure bm280PressureSensor; +Adafruit_BME280_Humidity bm280HumiditySensor; + +Adafruit_BME280::Adafruit_BME280() { + static I2cMaster i2cDevice; + t_fine_adjust = 0; + temp_sensor = &bm280TempSensor; + pressure_sensor = &bm280PressureSensor; + humidity_sensor = &bm280HumiditySensor; + i2c_dev = &i2cDevice; +} + +bool Adafruit_BME280::begin (uint8_t addr) { + if (!i2c_dev->begin(addr)) { + return false; + } + return init(); +} + +bool Adafruit_BME280::init() { + _sensorID = read8(BME280_REGISTER_CHIPID); + if (_sensorID != 0x60) { + return false; + } + write8(BME280_REGISTER_SOFTRESET, 0xB6); + _delay_ms(10); // wait for chip to wake up. + + // if chip is still reading calibration, delay + while (isReadingCalibration()) { + _delay_ms(10); + } + + readCoefficients(); // read trimming parameters, see DS 4.2.2 + setSampling(); // use defaults + _delay_ms(100); + + return true; +} + +/*! + * @brief setup sensor with given parameters / settings + * + * This is simply a overload to the normal begin()-function, so SPI users + * don't get confused about the library requiring an address. + * @param mode the power mode to use for the sensor + * @param tempSampling the temp samping rate to use + * @param pressSampling the pressure sampling rate to use + * @param humSampling the humidity sampling rate to use + * @param filter the filter mode to use + * @param duration the standby duration to use + */ +void Adafruit_BME280::setSampling(sensor_mode mode, + sensor_sampling tempSampling, + sensor_sampling pressSampling, + sensor_sampling humSampling, + sensor_filter filter, + standby_duration duration) { + _measReg.mode = mode; + _measReg.osrs_t = tempSampling; + _measReg.osrs_p = pressSampling; + + _humReg.osrs_h = humSampling; + _configReg.filter = filter; + _configReg.t_sb = duration; + _configReg.spi3w_en = 0; + + // making sure sensor is in sleep mode before setting configuration + // as it otherwise may be ignored + write8(BME280_REGISTER_CONTROL, MODE_SLEEP); + + // you must make sure to also set REGISTER_CONTROL after setting the + // CONTROLHUMID register, otherwise the values won't be applied (see + // DS 5.4.3) + write8(BME280_REGISTER_CONTROLHUMID, _humReg.get()); + write8(BME280_REGISTER_CONFIG, _configReg.get()); + write8(BME280_REGISTER_CONTROL, _measReg.get()); +} + +/*! + * @brief Writes an 8 bit value over I2C or SPI + * @param reg the register address to write to + * @param value the value to write to the register + */ +void Adafruit_BME280::write8(uint8_t reg, uint8_t value) { + uint8_t buffer[2]; + buffer[1] = value; + if (i2c_dev) { + buffer[0] = reg; + i2c_dev->write(buffer, 2); + } +} + +/*! + * @brief Reads an 8 bit value over I2C or SPI + * @param reg the register address to read from + * @returns the data byte read from the device + */ +uint8_t Adafruit_BME280::read8(uint8_t reg) { + uint8_t buffer[1]; + if (i2c_dev) { + buffer[0] = uint8_t(reg); + i2c_dev->write_then_read(buffer, 1, buffer, 1); + } + return buffer[0]; +} + +/*! + * @brief Reads a 16 bit value over I2C or SPI + * @param reg the register address to read from + * @returns the 16 bit data value read from the device + */ +uint16_t Adafruit_BME280::read16(uint8_t reg) { + uint8_t buffer[2]; + + if (i2c_dev) { + buffer[0] = uint8_t(reg); + i2c_dev->write_then_read(buffer, 1, buffer, 2); + } + return uint16_t(buffer[0]) << 8 | uint16_t(buffer[1]); +} + +/*! + * @brief Reads a signed 16 bit little endian value over I2C or SPI + * @param reg the register address to read from + * @returns the 16 bit data value read from the device + */ +uint16_t Adafruit_BME280::read16_LE(uint8_t reg) { + uint16_t temp = read16(reg); + return (temp >> 8) | (temp << 8); +} + +/*! + * @brief Reads a signed 16 bit value over I2C or SPI + * @param reg the register address to read from + * @returns the 16 bit data value read from the device + */ +int16_t Adafruit_BME280::readS16(uint8_t reg) { return (int16_t)read16(reg); } + +/*! + * @brief Reads a signed little endian 16 bit value over I2C or SPI + * @param reg the register address to read from + * @returns the 16 bit data value read from the device + */ +int16_t Adafruit_BME280::readS16_LE(uint8_t reg) { + return (int16_t)read16_LE(reg); +} + +/*! + * @brief Reads a 24 bit value over I2C + * @param reg the register address to read from + * @returns the 24 bit data value read from the device + */ +uint32_t Adafruit_BME280::read24(uint8_t reg) { + uint8_t buffer[3]; + + if (i2c_dev) { + buffer[0] = uint8_t(reg); + i2c_dev->write_then_read(buffer, 1, buffer, 3); + } + return uint32_t(buffer[0]) << 16 | uint32_t(buffer[1]) << 8 | + uint32_t(buffer[2]); +} + +/*! + * @brief Take a new measurement (only possible in forced mode) + @returns true in case of success else false + */ +bool Adafruit_BME280::takeForcedMeasurement(void) { + bool return_value = false; + // If we are in forced mode, the BME sensor goes back to sleep after each + // measurement and we need to set it to forced mode once at this point, so + // it will take the next measurement and then return to sleep again. + // In normal mode simply does new measurements periodically. + if (_measReg.mode == MODE_FORCED) { + return_value = true; + // set to forced mode, i.e. "take next measurement" + write8(BME280_REGISTER_CONTROL, _measReg.get()); + // Store current time to measure the timeout + uint32_t timeout_start = millis(); + // wait until measurement has been completed, otherwise we would read the + // the values from the last measurement or the timeout occurred after 2 sec. + while (read8(BME280_REGISTER_STATUS) & 0x08) { + // In case of a timeout, stop the while loop + if ((millis() - timeout_start) > 2000) { + return_value = false; + break; + } + _delay_ms(1); + } + } + return return_value; +} + +/*! + * @brief Reads the factory-set coefficients + */ +void Adafruit_BME280::readCoefficients(void) { + _bme280_calib.dig_T1 = read16_LE(BME280_REGISTER_DIG_T1); + _bme280_calib.dig_T2 = readS16_LE(BME280_REGISTER_DIG_T2); + _bme280_calib.dig_T3 = readS16_LE(BME280_REGISTER_DIG_T3); + + _bme280_calib.dig_P1 = read16_LE(BME280_REGISTER_DIG_P1); + _bme280_calib.dig_P2 = readS16_LE(BME280_REGISTER_DIG_P2); + _bme280_calib.dig_P3 = readS16_LE(BME280_REGISTER_DIG_P3); + _bme280_calib.dig_P4 = readS16_LE(BME280_REGISTER_DIG_P4); + _bme280_calib.dig_P5 = readS16_LE(BME280_REGISTER_DIG_P5); + _bme280_calib.dig_P6 = readS16_LE(BME280_REGISTER_DIG_P6); + _bme280_calib.dig_P7 = readS16_LE(BME280_REGISTER_DIG_P7); + _bme280_calib.dig_P8 = readS16_LE(BME280_REGISTER_DIG_P8); + _bme280_calib.dig_P9 = readS16_LE(BME280_REGISTER_DIG_P9); + + _bme280_calib.dig_H1 = read8(BME280_REGISTER_DIG_H1); + _bme280_calib.dig_H2 = readS16_LE(BME280_REGISTER_DIG_H2); + _bme280_calib.dig_H3 = read8(BME280_REGISTER_DIG_H3); + _bme280_calib.dig_H4 = ((int8_t)read8(BME280_REGISTER_DIG_H4) << 4) | + (read8(BME280_REGISTER_DIG_H4 + 1) & 0xF); + _bme280_calib.dig_H5 = ((int8_t)read8(BME280_REGISTER_DIG_H5 + 1) << 4) | + (read8(BME280_REGISTER_DIG_H5) >> 4); + _bme280_calib.dig_H6 = (int8_t)read8(BME280_REGISTER_DIG_H6); +} + +/*! + * @brief return true if chip is busy reading cal data + * @returns true if reading calibration, false otherwise + */ +bool Adafruit_BME280::isReadingCalibration(void) { + uint8_t const rStatus = read8(BME280_REGISTER_STATUS); + + return (rStatus & (1 << 0)) != 0; +} + +/*! + * @brief Returns the temperature from the sensor + * @returns the temperature read from the device + */ +float Adafruit_BME280::readTemperature(void) { + int32_t var1, var2; + + int32_t adc_T = read24(BME280_REGISTER_TEMPDATA); + if (adc_T == 0x800000) // value in case temp measurement was disabled + return NAN; + adc_T >>= 4; + + var1 = (int32_t)((adc_T / 8) - ((int32_t)_bme280_calib.dig_T1 * 2)); + var1 = (var1 * ((int32_t)_bme280_calib.dig_T2)) / 2048; + var2 = (int32_t)((adc_T / 16) - ((int32_t)_bme280_calib.dig_T1)); + var2 = (((var2 * var2) / 4096) * ((int32_t)_bme280_calib.dig_T3)) / 16384; + + t_fine = var1 + var2 + t_fine_adjust; + + int32_t T = (t_fine * 5 + 128) / 256; + + return (float)T / 100; +} + +/*! + * @brief Returns the pressure from the sensor + * @returns the pressure value (in Pascal) read from the device + */ +float Adafruit_BME280::readPressure(void) { + int64_t var1, var2, var3, var4; + + readTemperature(); // must be done first to get t_fine + + int32_t adc_P = read24(BME280_REGISTER_PRESSUREDATA); + if (adc_P == 0x800000) // value in case pressure measurement was disabled + return NAN; + adc_P >>= 4; + + var1 = ((int64_t)t_fine) - 128000; + var2 = var1 * var1 * (int64_t)_bme280_calib.dig_P6; + var2 = var2 + ((var1 * (int64_t)_bme280_calib.dig_P5) * 131072); + var2 = var2 + (((int64_t)_bme280_calib.dig_P4) * 34359738368); + var1 = ((var1 * var1 * (int64_t)_bme280_calib.dig_P3) / 256) + + ((var1 * ((int64_t)_bme280_calib.dig_P2) * 4096)); + var3 = ((int64_t)1) * 140737488355328; + var1 = (var3 + var1) * ((int64_t)_bme280_calib.dig_P1) / 8589934592; + + if (var1 == 0) { + return 0; // avoid exception caused by division by zero + } + + var4 = 1048576 - adc_P; + var4 = (((var4 * 2147483648UL) - var2) * 3125) / var1; + var1 = (((int64_t)_bme280_calib.dig_P9) * (var4 / 8192) * (var4 / 8192)) / + 33554432; + var2 = (((int64_t)_bme280_calib.dig_P8) * var4) / 524288; + var4 = ((var4 + var1 + var2) / 256) + (((int64_t)_bme280_calib.dig_P7) * 16); + + float P = var4 / 256.0; + + return P; +} + +/*! + * @brief Returns the humidity from the sensor + * @returns the humidity value read from the device + */ +float Adafruit_BME280::readHumidity(void) { + int32_t var1, var2, var3, var4, var5; + + readTemperature(); // must be done first to get t_fine + + int32_t adc_H = read16(BME280_REGISTER_HUMIDDATA); + if (adc_H == 0x8000) // value in case humidity measurement was disabled + return NAN; + + var1 = t_fine - ((int32_t)76800); + var2 = (int32_t)(adc_H * 16384); + var3 = (int32_t)(((int32_t)_bme280_calib.dig_H4) * 1048576); + var4 = ((int32_t)_bme280_calib.dig_H5) * var1; + var5 = (((var2 - var3) - var4) + (int32_t)16384) / 32768; + var2 = (var1 * ((int32_t)_bme280_calib.dig_H6)) / 1024; + var3 = (var1 * ((int32_t)_bme280_calib.dig_H3)) / 2048; + var4 = ((var2 * (var3 + (int32_t)32768)) / 1024) + (int32_t)2097152; + var2 = ((var4 * ((int32_t)_bme280_calib.dig_H2)) + 8192) / 16384; + var3 = var5 * var2; + var4 = ((var3 / 32768) * (var3 / 32768)) / 128; + var5 = var3 - ((var4 * ((int32_t)_bme280_calib.dig_H1)) / 16); + var5 = (var5 < 0 ? 0 : var5); + var5 = (var5 > 419430400 ? 419430400 : var5); + uint32_t H = (uint32_t)(var5 / 4096); + + return (float)H / 1024.0; +} + +/*! + * Calculates the altitude (in meters) from the specified atmospheric + * pressure (in hPa), and sea-level pressure (in hPa). + * @param seaLevel Sea-level pressure in hPa + * @returns the altitude value read from the device + */ +float Adafruit_BME280::readAltitude(float seaLevel) { + // Equation taken from BMP180 datasheet (page 16): + // http://www.adafruit.com/datasheets/BST-BMP180-DS000-09.pdf + + // Note that using the equation from wikipedia can give bad results + // at high altitude. See this thread for more information: + // http://forums.adafruit.com/viewtopic.php?f=22&t=58064 + + float atmospheric = readPressure() / 100.0F; + return 44330.0 * (1.0 - pow(atmospheric / seaLevel, 0.1903)); +} + +/*! + * Calculates the pressure at sea level (in hPa) from the specified + * altitude (in meters), and atmospheric pressure (in hPa). + * @param altitude Altitude in meters + * @param atmospheric Atmospheric pressure in hPa + * @returns the pressure at sea level (in hPa) from the specified altitude + */ +float Adafruit_BME280::seaLevelForAltitude(float altitude, float atmospheric) { + // Equation taken from BMP180 datasheet (page 17): + // http://www.adafruit.com/datasheets/BST-BMP180-DS000-09.pdf + + // Note that using the equation from wikipedia can give bad results + // at high altitude. See this thread for more information: + // http://forums.adafruit.com/viewtopic.php?f=22&t=58064 + + return atmospheric / pow(1.0 - (altitude / 44330.0), 5.255); +} + +/*! + * Returns Sensor ID found by init() for diagnostics + * @returns Sensor ID 0x60 for BME280, 0x56, 0x57, 0x58 BMP280 + */ +uint32_t Adafruit_BME280::sensorID(void) { return _sensorID; } + +/*! + * Returns the current temperature compensation value in degrees Celsius + * @returns the current temperature compensation value in degrees Celsius + */ +float Adafruit_BME280::getTemperatureCompensation(void) { + return float((t_fine_adjust * 5) >> 8) / 100.0; +}; + +/*! + * Sets a value to be added to each temperature reading. This adjusted + * temperature is used in pressure and humidity readings. + * @param adjustment Value to be added to each temperature reading in Celsius + */ +void Adafruit_BME280::setTemperatureCompensation(float adjustment) { + // convert the value in C into and adjustment to t_fine + t_fine_adjust = ((int32_t(adjustment * 100) << 8)) / 5; +}; + + +/**************************************************************************/ +/*! + @brief Gets the sensor_t data for the BME280's temperature sensor +*/ +/**************************************************************************/ +void Adafruit_BME280_Temp::getSensor(sensor_t *sensor) { + /* Clear the sensor_t object */ + memset(sensor, 0, sizeof(sensor_t)); + + /* Insert the sensor name in the fixed length char array */ + strncpy(sensor->name, "BME280", sizeof(sensor->name) - 1); + sensor->name[sizeof(sensor->name) - 1] = 0; + sensor->version = 1; + sensor->sensor_id = _sensorID; + sensor->type = SENSOR_TYPE_AMBIENT_TEMPERATURE; + sensor->min_delay = 0; + sensor->min_value = -40.0; /* Temperature range -40 ~ +85 C */ + sensor->max_value = +85.0; + sensor->resolution = 0.01; /* 0.01 C */ +} + +/**************************************************************************/ +/*! + @brief Gets the temperature as a standard sensor event + @param event Sensor event object that will be populated + @returns True +*/ +/**************************************************************************/ +bool Adafruit_BME280_Temp::getEvent(sensors_event_t *event) { + /* Clear the event */ + memset(event, 0, sizeof(sensors_event_t)); + + event->version = sizeof(sensors_event_t); + event->sensor_id = _sensorID; + event->type = SENSOR_TYPE_AMBIENT_TEMPERATURE; + event->timestamp = millis(); + event->temperature = theBME280.readTemperature(); + return true; +} + +/**************************************************************************/ +/*! + @brief Gets the sensor_t data for the BME280's pressure sensor +*/ +/**************************************************************************/ +void Adafruit_BME280_Pressure::getSensor(sensor_t *sensor) { + /* Clear the sensor_t object */ + memset(sensor, 0, sizeof(sensor_t)); + + /* Insert the sensor name in the fixed length char array */ + strncpy(sensor->name, "BME280", sizeof(sensor->name) - 1); + sensor->name[sizeof(sensor->name) - 1] = 0; + sensor->version = 1; + sensor->sensor_id = _sensorID; + sensor->type = SENSOR_TYPE_PRESSURE; + sensor->min_delay = 0; + sensor->min_value = 300.0; /* 300 ~ 1100 hPa */ + sensor->max_value = 1100.0; + sensor->resolution = 0.012; /* 0.12 hPa relative */ +} + +/**************************************************************************/ +/*! + @brief Gets the pressure as a standard sensor event + @param event Sensor event object that will be populated + @returns True +*/ +/**************************************************************************/ +bool Adafruit_BME280_Pressure::getEvent(sensors_event_t *event) { + /* Clear the event */ + memset(event, 0, sizeof(sensors_event_t)); + + event->version = sizeof(sensors_event_t); + event->sensor_id = _sensorID; + event->type = SENSOR_TYPE_PRESSURE; + event->timestamp = millis(); + event->pressure = theBME280.readPressure() / 100; // convert Pa to hPa + return true; +} + +/**************************************************************************/ +/*! + @brief Gets the sensor_t data for the BME280's humidity sensor +*/ +/**************************************************************************/ +void Adafruit_BME280_Humidity::getSensor(sensor_t *sensor) { + /* Clear the sensor_t object */ + memset(sensor, 0, sizeof(sensor_t)); + + /* Insert the sensor name in the fixed length char array */ + strncpy(sensor->name, "BME280", sizeof(sensor->name) - 1); + sensor->name[sizeof(sensor->name) - 1] = 0; + sensor->version = 1; + sensor->sensor_id = _sensorID; + sensor->type = SENSOR_TYPE_RELATIVE_HUMIDITY; + sensor->min_delay = 0; + sensor->min_value = 0; + sensor->max_value = 100; /* 0 - 100 % */ + sensor->resolution = 3; /* 3% accuracy */ +} + +/**************************************************************************/ +/*! + @brief Gets the humidity as a standard sensor event + @param event Sensor event object that will be populated + @returns True +*/ +/**************************************************************************/ +bool Adafruit_BME280_Humidity::getEvent(sensors_event_t *event) { + /* Clear the event */ + memset(event, 0, sizeof(sensors_event_t)); + + event->version = sizeof(sensors_event_t); + event->sensor_id = _sensorID; + event->type = SENSOR_TYPE_RELATIVE_HUMIDITY; + event->timestamp = millis(); + event->relative_humidity = theBME280.readHumidity(); + return true; +} diff --git a/software/test-software/src/adafruit/bme280.h b/software/test-software/src/adafruit/bme280.h new file mode 100644 index 0000000..aa5aa72 --- /dev/null +++ b/software/test-software/src/adafruit/bme280.h @@ -0,0 +1,373 @@ +// https://github.com/adafruit/Adafruit_BME280_Library + +/*! + * @file Adafruit_BME280.h + * + * Designed specifically to work with the Adafruit BME280 Breakout + * ----> http://www.adafruit.com/products/2650 + * + * These sensors use I2C or SPI to communicate, 2 or 4 pins are required + * to interface. + * + * Adafruit invests time and resources providing this open source code, + * please support Adafruit and open-source hardware by purchasing + * products from Adafruit! + * + * Written by Kevin "KTOWN" Townsend for Adafruit Industries. + * + * BSD license, all text here must be included in any redistribution. + * See the LICENSE file for details. + * + */ + +#ifndef __BME280_H__ +#define __BME280_H__ + +// #include "Arduino.h" + +// #include +// #include +// #include + + +#include "../i2cmaster.hpp" +#include "../main.hpp" +// #define byte uint8_t + + + +#include +#include +#include "sensor.h" + +/*! + * @brief default I2C address + */ +#define BME280_ADDRESS (0x77) // Primary I2C Address + /*! + * @brief alternate I2C address + */ +#define BME280_ADDRESS_ALTERNATE (0x76) // Alternate Address + +/*! + * @brief Register addresses + */ +enum { + BME280_REGISTER_DIG_T1 = 0x88, + BME280_REGISTER_DIG_T2 = 0x8A, + BME280_REGISTER_DIG_T3 = 0x8C, + + BME280_REGISTER_DIG_P1 = 0x8E, + BME280_REGISTER_DIG_P2 = 0x90, + BME280_REGISTER_DIG_P3 = 0x92, + BME280_REGISTER_DIG_P4 = 0x94, + BME280_REGISTER_DIG_P5 = 0x96, + BME280_REGISTER_DIG_P6 = 0x98, + BME280_REGISTER_DIG_P7 = 0x9A, + BME280_REGISTER_DIG_P8 = 0x9C, + BME280_REGISTER_DIG_P9 = 0x9E, + + BME280_REGISTER_DIG_H1 = 0xA1, + BME280_REGISTER_DIG_H2 = 0xE1, + BME280_REGISTER_DIG_H3 = 0xE3, + BME280_REGISTER_DIG_H4 = 0xE4, + BME280_REGISTER_DIG_H5 = 0xE5, + BME280_REGISTER_DIG_H6 = 0xE7, + + BME280_REGISTER_CHIPID = 0xD0, + BME280_REGISTER_VERSION = 0xD1, + BME280_REGISTER_SOFTRESET = 0xE0, + + BME280_REGISTER_CAL26 = 0xE1, // R calibration stored in 0xE1-0xF0 + + BME280_REGISTER_CONTROLHUMID = 0xF2, + BME280_REGISTER_STATUS = 0XF3, + BME280_REGISTER_CONTROL = 0xF4, + BME280_REGISTER_CONFIG = 0xF5, + BME280_REGISTER_PRESSUREDATA = 0xF7, + BME280_REGISTER_TEMPDATA = 0xFA, + BME280_REGISTER_HUMIDDATA = 0xFD +}; + +/**************************************************************************/ +/*! + @brief calibration data +*/ +/**************************************************************************/ +typedef struct { + uint16_t dig_T1; ///< temperature compensation value + int16_t dig_T2; ///< temperature compensation value + int16_t dig_T3; ///< temperature compensation value + + uint16_t dig_P1; ///< pressure compensation value + int16_t dig_P2; ///< pressure compensation value + int16_t dig_P3; ///< pressure compensation value + int16_t dig_P4; ///< pressure compensation value + int16_t dig_P5; ///< pressure compensation value + int16_t dig_P6; ///< pressure compensation value + int16_t dig_P7; ///< pressure compensation value + int16_t dig_P8; ///< pressure compensation value + int16_t dig_P9; ///< pressure compensation value + + uint8_t dig_H1; ///< humidity compensation value + int16_t dig_H2; ///< humidity compensation value + uint8_t dig_H3; ///< humidity compensation value + int16_t dig_H4; ///< humidity compensation value + int16_t dig_H5; ///< humidity compensation value + int8_t dig_H6; ///< humidity compensation value +} bme280_calib_data; +/*=========================================================================*/ + +class Adafruit_BME280; + +/** Adafruit Unified Sensor interface for temperature component of BME280 */ +class Adafruit_BME280_Temp : public Adafruit_Sensor { +public: + /** @brief Create an Adafruit_Sensor compatible object for the temp sensor + @param parent A pointer to the BME280 class */ + Adafruit_BME280_Temp() { _sensorID = 280; } + bool getEvent(sensors_event_t *); + void getSensor(sensor_t *); + +private: + int _sensorID; +}; + +/** Adafruit Unified Sensor interface for pressure component of BME280 */ +class Adafruit_BME280_Pressure : public Adafruit_Sensor { +public: + /** @brief Create an Adafruit_Sensor compatible object for the pressure sensor + @param parent A pointer to the BME280 class */ + Adafruit_BME280_Pressure() { _sensorID = 280; } + bool getEvent(sensors_event_t *); + void getSensor(sensor_t *); + +private: + int _sensorID; +}; + +/** Adafruit Unified Sensor interface for humidity component of BME280 */ +class Adafruit_BME280_Humidity : public Adafruit_Sensor { +public: + /** @brief Create an Adafruit_Sensor compatible object for the humidity sensor + @param parent A pointer to the BME280 class */ + Adafruit_BME280_Humidity() { _sensorID = 280;} + bool getEvent(sensors_event_t *); + void getSensor(sensor_t *); + +private: + int _sensorID; +}; + +/**************************************************************************/ +/*! + @brief Class that stores state and functions for interacting with BME280 IC +*/ +/**************************************************************************/ +class Adafruit_BME280 { +public: + /**************************************************************************/ + /*! + @brief sampling rates + */ + /**************************************************************************/ + enum sensor_sampling { + SAMPLING_NONE = 0b000, + SAMPLING_X1 = 0b001, + SAMPLING_X2 = 0b010, + SAMPLING_X4 = 0b011, + SAMPLING_X8 = 0b100, + SAMPLING_X16 = 0b101 + }; + + /**************************************************************************/ + /*! + @brief power modes + */ + /**************************************************************************/ + enum sensor_mode { + MODE_SLEEP = 0b00, + MODE_FORCED = 0b01, + MODE_NORMAL = 0b11 + }; + + /**************************************************************************/ + /*! + @brief filter values + */ + /**************************************************************************/ + enum sensor_filter { + FILTER_OFF = 0b000, + FILTER_X2 = 0b001, + FILTER_X4 = 0b010, + FILTER_X8 = 0b011, + FILTER_X16 = 0b100 + }; + + /**************************************************************************/ + /*! + @brief standby duration in ms + */ + /**************************************************************************/ + enum standby_duration { + STANDBY_MS_0_5 = 0b000, + STANDBY_MS_10 = 0b110, + STANDBY_MS_20 = 0b111, + STANDBY_MS_62_5 = 0b001, + STANDBY_MS_125 = 0b010, + STANDBY_MS_250 = 0b011, + STANDBY_MS_500 = 0b100, + STANDBY_MS_1000 = 0b101 + }; + + // constructors + Adafruit_BME280(); + + bool begin(uint8_t addr = BME280_ADDRESS); + bool init(); + + void setSampling(sensor_mode mode = MODE_NORMAL, + sensor_sampling tempSampling = SAMPLING_X16, + sensor_sampling pressSampling = SAMPLING_X16, + sensor_sampling humSampling = SAMPLING_X16, + sensor_filter filter = FILTER_OFF, + standby_duration duration = STANDBY_MS_0_5); + + bool takeForcedMeasurement(void); + float readTemperature(void); + float readPressure(void); + float readHumidity(void); + + float readAltitude(float seaLevel); + float seaLevelForAltitude(float altitude, float pressure); + uint32_t sensorID(void); + + float getTemperatureCompensation(void); + void setTemperatureCompensation(float); + +protected: + I2cMaster *i2c_dev = NULL; ///< Pointer to I2C bus interface + // Adafruit_SPIDevice *spi_dev = NULL; ///< Pointer to SPI bus interface + + Adafruit_BME280_Temp *temp_sensor; + Adafruit_BME280_Pressure *pressure_sensor; + Adafruit_BME280_Humidity *humidity_sensor; + + void readCoefficients(void); + bool isReadingCalibration(void); + + void write8(uint8_t reg, uint8_t value); + uint8_t read8(uint8_t reg); + uint16_t read16(uint8_t reg); + uint32_t read24(uint8_t reg); + int16_t readS16(uint8_t reg); + uint16_t read16_LE(uint8_t reg); // little endian + int16_t readS16_LE(uint8_t reg); // little endian + + uint8_t _i2caddr; //!< I2C addr for the TwoWire interface + int32_t _sensorID; //!< ID of the BME Sensor + int32_t t_fine; //!< temperature with high resolution, stored as an attribute + //!< as this is used for temperature compensation reading + //!< humidity and pressure + + int32_t t_fine_adjust; //!< add to compensate temp readings and in turn + //!< to pressure and humidity readings + + bme280_calib_data _bme280_calib; //!< here calibration data is stored + + /**************************************************************************/ + /*! + @brief config register + */ + /**************************************************************************/ + struct config { + // inactive duration (standby time) in normal mode + // 000 = 0.5 ms + // 001 = 62.5 ms + // 010 = 125 ms + // 011 = 250 ms + // 100 = 500 ms + // 101 = 1000 ms + // 110 = 10 ms + // 111 = 20 ms + unsigned int t_sb : 3; ///< inactive duration (standby time) in normal mode + + // filter settings + // 000 = filter off + // 001 = 2x filter + // 010 = 4x filter + // 011 = 8x filter + // 100 and above = 16x filter + unsigned int filter : 3; ///< filter settings + + // unused - don't set + unsigned int none : 1; ///< unused - don't set + unsigned int spi3w_en : 1; ///< unused - don't set + + /// @return combined config register + unsigned int get() { return (t_sb << 5) | (filter << 2) | spi3w_en; } + }; + config _configReg; //!< config register object + + /**************************************************************************/ + /*! + @brief ctrl_meas register + */ + /**************************************************************************/ + struct ctrl_meas { + // temperature oversampling + // 000 = skipped + // 001 = x1 + // 010 = x2 + // 011 = x4 + // 100 = x8 + // 101 and above = x16 + unsigned int osrs_t : 3; ///< temperature oversampling + + // pressure oversampling + // 000 = skipped + // 001 = x1 + // 010 = x2 + // 011 = x4 + // 100 = x8 + // 101 and above = x16 + unsigned int osrs_p : 3; ///< pressure oversampling + + // device mode + // 00 = sleep + // 01 or 10 = forced + // 11 = normal + unsigned int mode : 2; ///< device mode + + /// @return combined ctrl register + unsigned int get() { return (osrs_t << 5) | (osrs_p << 2) | mode; } + }; + ctrl_meas _measReg; //!< measurement register object + + /**************************************************************************/ + /*! + @brief ctrl_hum register + */ + /**************************************************************************/ + struct ctrl_hum { + /// unused - don't set + unsigned int none : 5; + + // pressure oversampling + // 000 = skipped + // 001 = x1 + // 010 = x2 + // 011 = x4 + // 100 = x8 + // 101 and above = x16 + unsigned int osrs_h : 3; ///< pressure oversampling + + /// @return combined ctrl hum register + unsigned int get() { return (osrs_h); } + }; + ctrl_hum _humReg; //!< hum register object +}; + +extern Adafruit_BME280 theBME280; + +#endif diff --git a/software/test-software/src/adafruit/ens160.cpp b/software/test-software/src/adafruit/ens160.cpp new file mode 100644 index 0000000..29e3704 --- /dev/null +++ b/software/test-software/src/adafruit/ens160.cpp @@ -0,0 +1,374 @@ +/* + ScioSense_ENS160.h - Library for the ENS160 sensor with I2C interface from ScioSense + 2023 Mar 23 v6 Christoph Friese Bugfix measurement routine, prepare next release + 2021 Nov 25 v5 Martin Herold Custom mode timing fixed + 2021 Feb 04 v4 Giuseppe de Pinto Custom mode fixed + 2020 Apr 06 v3 Christoph Friese Changed nomenclature to ScioSense as product shifted from ams + 2020 Feb 15 v2 Giuseppe Pasetti Corrected firmware flash option + 2019 May 05 v1 Christoph Friese Created + based on application note "ENS160 Software Integration.pdf" rev 0.01 +*/ + +#include "ens160.h" +#include "math.h" +#include +#include +#include + +ScioSense_ENS160::ScioSense_ENS160 () { + _revENS16x = 0; + + //Isotherm, HP0 252°C / HP1 350°C / HP2 250°C / HP3 324°C / measure every 1008ms + _seq_steps[0][0] = 0x7c; + _seq_steps[0][1] = 0x0a; + _seq_steps[0][2] = 0x7e; + _seq_steps[0][3] = 0xaf; + _seq_steps[0][4] = 0xaf; + _seq_steps[0][5] = 0xa2; + _seq_steps[0][6] = 0x00; + _seq_steps[0][7] = 0x80; +} + +bool ScioSense_ENS160::begin () { + i2cDevice.begin(ENS160_I2CADDR_1); + _delay_ms(ENS160_BOOTING); + if (reset()) { + if (checkPartID()) { + if (setMode(ENS160_OPMODE_IDLE)) { + if (clearCommand()) { + if (getFirmware()) { + return true; + } + } + } + } + } + return false; + +} + +bool ScioSense_ENS160::write8 (uint8_t reg, uint8_t value) { + uint8_t buffer[2]; + buffer[1] = value; + buffer[0] = reg; + return i2cDevice.write(buffer, 2); +} + +bool ScioSense_ENS160::read8 (uint8_t reg, uint8_t *value) { + uint8_t buffer[1]; + buffer[0] = uint8_t(reg); + return i2cDevice.write_then_read(buffer, 1, value, 1); +} + +bool ScioSense_ENS160::read16 (uint8_t reg, uint16_t *value) { + uint8_t buffer[1]; + buffer[0] = uint8_t(reg); + return i2cDevice.write_then_read(buffer, 1, (uint8_t *)value, 2); +} + +bool ScioSense_ENS160::read16LE (uint8_t reg, uint16_t *value) { + uint16_t tmp; + if (read16(reg, &tmp)) { + *value = ((tmp & 0xff) << 8) | (tmp >> 8); + return true; + } + return false; +} + +bool ScioSense_ENS160::readBytes (uint8_t reg, uint8_t *bytes, uint8_t len) { + uint8_t buffer[1]; + buffer[0] = uint8_t(reg); + return i2cDevice.write_then_read(buffer, 1, buffer, len); +} + + +// Sends a reset to the ENS160. Returns false on I2C problems. +bool ScioSense_ENS160::reset () { + if (write8(ENS160_REG_OPMODE, ENS160_OPMODE_RESET)) { + _delay_ms(ENS160_BOOTING); + return true; + } + _delay_ms(ENS160_BOOTING); + return false; +} + +// Reads the part ID and confirms valid sensor +bool ScioSense_ENS160::checkPartID () { + uint16_t part_id; + + read16(ENS160_REG_PART_ID, &part_id); + _delay_ms(ENS160_BOOTING); + + if (part_id == ENS160_PARTID) { + _revENS16x = 0; + return true; + + } else if (part_id == ENS161_PARTID) { + _revENS16x = 1; + return true; + } + + return false; +} + +// Initialize idle mode and confirms +bool ScioSense_ENS160::clearCommand () { + uint8_t status; + + if (write8(ENS160_REG_COMMAND, ENS160_COMMAND_NOP)) { + if (write8(ENS160_REG_COMMAND, ENS160_COMMAND_CLRGPR)) { + _delay_ms(ENS160_BOOTING); + if (read8(ENS160_REG_DATA_STATUS, &status)) { + return true; + } + } + } + _delay_ms(ENS160_BOOTING); + return false; +} + +// Read firmware revisions +bool ScioSense_ENS160::getFirmware () { + uint8_t i2cbuf[3]; + + if (clearCommand()) { + _delay_ms(ENS160_BOOTING); + if (write8(ENS160_REG_COMMAND, ENS160_COMMAND_GET_APPVER)) { + if (readBytes(ENS160_REG_GPR_READ_4, i2cbuf, 3)) { + _fw_ver_major = i2cbuf[0]; + _fw_ver_minor = i2cbuf[1]; + _fw_ver_build = i2cbuf[2]; + _revENS16x = this->_fw_ver_major > 6 ? 1 : 0; + _delay_ms(ENS160_BOOTING); + return true; + } + } + } + _delay_ms(ENS160_BOOTING); + return false; +} + +// Set operation mode of sensor +bool ScioSense_ENS160::setMode (uint8_t mode) { + //LP only valid for rev>0 + if ((mode == ENS160_OPMODE_LP) and (_revENS16x == 0)) { + return false; + } + if (write8(ENS160_REG_OPMODE, mode)) { + _delay_ms(ENS160_BOOTING); + return true; + } + _delay_ms(ENS160_BOOTING); + return false; +} + +// Initialize definition of custom mode with steps +bool ScioSense_ENS160::initCustomMode (uint16_t stepNum) { + if (stepNum > 0) { + _stepCount = stepNum; + if (setMode(ENS160_OPMODE_IDLE)) { + if (clearCommand()) { + if (write8(ENS160_REG_COMMAND, ENS160_COMMAND_SETSEQ)) { + _delay_ms(ENS160_BOOTING); + return true; + } + } + } + } + _delay_ms(ENS160_BOOTING); + return false; +} + +// Add a step to custom measurement profile with definition of duration, enabled data acquisition and temperature for each hotplate +bool ScioSense_ENS160::addCustomStep (uint16_t time, bool measureHP0, bool measureHP1, bool measureHP2, bool measureHP3, uint16_t tempHP0, uint16_t tempHP1, uint16_t tempHP2, uint16_t tempHP3) { + uint8_t seq_ack; + uint8_t temp; + + _delay_ms(ENS160_BOOTING); + + temp = (uint8_t)(((time / 24) - 1) << 6); + if (measureHP0) { + temp = temp | 0x20; + } + if (measureHP1) { + temp = temp | 0x10; + } + if (measureHP2) { + temp = temp | 0x08; + } + if (measureHP3) { + temp = temp | 0x04; + } + if (!write8(ENS160_REG_GPR_WRITE_0, temp)) { + return false; + } + temp = (uint8_t)(((time / 24) - 1) >> 2); + if (!write8(ENS160_REG_GPR_WRITE_1, temp)) { + return false; + } + if (!write8(ENS160_REG_GPR_WRITE_2, (uint8_t)(tempHP0 / 2))) { + return false; + } + if (!write8(ENS160_REG_GPR_WRITE_3, (uint8_t)(tempHP1 / 2))) { + return false; + } + if (write8(ENS160_REG_GPR_WRITE_4, (uint8_t)(tempHP2 / 2))) { + return false; + } + if (write8(ENS160_REG_GPR_WRITE_5, (uint8_t)(tempHP3 / 2))) { + return false; + } + + if (write8(ENS160_REG_GPR_WRITE_6, (uint8_t)(_stepCount - 1))) { + return false; + } + + if (_stepCount == 1) { + if (!write8(ENS160_REG_GPR_WRITE_7, 128)) { + return false; + } + } else { + if (!write8(ENS160_REG_GPR_WRITE_7, 0)) { + return false; + } + } + _delay_ms(ENS160_BOOTING); + + if (!read8(ENS160_REG_GPR_READ_7, &seq_ack)) { + return false; + } + _delay_ms(ENS160_BOOTING); + + if ((ENS160_SEQ_ACK_COMPLETE | _stepCount) != seq_ack) { + _stepCount++; + return false; + } + + return true; +} + +bool ScioSense_ENS160::readStatus (uint8_t *status) { + return read8(ENS160_REG_DATA_STATUS, status); +} + +bool ScioSense_ENS160::readData (ENS160_DATA *data) { + uint8_t buffer[1] = { 0x21 }; + return i2cDevice.write_then_read(buffer, 1, (uint8_t *)data, sizeof(ENS160_DATA)); +} + +// Perform prediction measurement and stores result in internal variables +bool ScioSense_ENS160::measure (bool waitForNew) { + uint8_t i2cbuf[8]; + uint8_t status; + + // Set default status for early bail out + if (waitForNew) { + do { + if (!read8(ENS160_REG_DATA_STATUS, &status)) { + return false; + } + _delay_ms(1); + } while (!IS_NEWDAT(status)); + } else { + if (!read8(ENS160_REG_DATA_STATUS, &status)) { + return false; + } + } + + + // Read predictions + if (IS_NEWDAT(status)) { + if (!readBytes(ENS160_REG_DATA_AQI, i2cbuf, 7)) { + return false; + } + return false; + _data_aqi = i2cbuf[0]; + _data_tvoc = i2cbuf[1] | ((uint16_t)i2cbuf[2] << 8); + _data_eco2 = i2cbuf[3] | ((uint16_t)i2cbuf[4] << 8); + if (_revENS16x > 0) { + _data_aqi500 = ((uint16_t)i2cbuf[5]) | ((uint16_t)i2cbuf[6] << 8); + } else { + _data_aqi500 = 0; + } + return true; + } + + return false; +} + +// Perfrom raw measurement and stores result in internal variables +bool ScioSense_ENS160::measureRaw (bool waitForNew) { + uint8_t i2cbuf[8]; + uint8_t status; + + // Set default status for early bail out + if (waitForNew) { + do { + _delay_ms(1); + if (!read8(ENS160_REG_DATA_STATUS, &status)) { + return false; + } + } while (!IS_NEWGPR(status)); + } else { + if (!read8(ENS160_REG_DATA_STATUS, &status)) { + return false; + } + } + + if (IS_NEWGPR(status)) { + + // Read raw resistance values + if (!readBytes(ENS160_REG_GPR_READ_0, i2cbuf, 8)) { + return false; + } + _hp0_rs = CONVERT_RS_RAW2OHMS_F((uint32_t)(i2cbuf[0] | ((uint16_t)i2cbuf[1] << 8))); + _hp1_rs = CONVERT_RS_RAW2OHMS_F((uint32_t)(i2cbuf[2] | ((uint16_t)i2cbuf[3] << 8))); + _hp2_rs = CONVERT_RS_RAW2OHMS_F((uint32_t)(i2cbuf[4] | ((uint16_t)i2cbuf[5] << 8))); + _hp3_rs = CONVERT_RS_RAW2OHMS_F((uint32_t)(i2cbuf[6] | ((uint16_t)i2cbuf[7] << 8))); + + // Read baselines + if (!readBytes(ENS160_REG_DATA_BL, i2cbuf, 8)) { + return false; + } + _hp0_bl = CONVERT_RS_RAW2OHMS_F((uint32_t)(i2cbuf[0] | ((uint16_t)i2cbuf[1] << 8))); + _hp1_bl = CONVERT_RS_RAW2OHMS_F((uint32_t)(i2cbuf[2] | ((uint16_t)i2cbuf[3] << 8))); + _hp2_bl = CONVERT_RS_RAW2OHMS_F((uint32_t)(i2cbuf[4] | ((uint16_t)i2cbuf[5] << 8))); + _hp3_bl = CONVERT_RS_RAW2OHMS_F((uint32_t)(i2cbuf[6] | ((uint16_t)i2cbuf[7] << 8))); + + if (!read8(ENS160_REG_DATA_MISR, i2cbuf)) { + return false; + } + _misr = i2cbuf[0]; + return true; + } + + return false; +} + + +// Writes t (degC) and h (%rh) to ENV_DATA. Returns false on I2C problems. +bool ScioSense_ENS160::set_envdata (float t, float h) { + uint16_t t_data = (uint16_t)((t + 273.15f) * 64.0f); + uint16_t rh_data = (uint16_t)(h * 512.0f); + return this->set_envdata210(t_data, rh_data); +} + +// Writes t and h (in ENS210 format) to ENV_DATA. Returns false on I2C problems. +bool ScioSense_ENS160::set_envdata210 (uint16_t t, uint16_t h) { + //uint16_t temp; + uint8_t trh_in[4]; + + //temp = (uint16_t)((t + 273.15f) * 64.0f); + trh_in[0] = t & 0xff; + trh_in[1] = (t >> 8) & 0xff; + + //temp = (uint16_t)(h * 512.0f); + trh_in[2] = h & 0xff; + trh_in[3] = (h >> 8) & 0xff; + + if (!i2cDevice.writeByteAndBuffer(ENS160_REG_TEMP_IN, trh_in, 4)) { + return false; + } + + return true; +} diff --git a/software/test-software/src/adafruit/ens160.h b/software/test-software/src/adafruit/ens160.h new file mode 100644 index 0000000..7f26ba1 --- /dev/null +++ b/software/test-software/src/adafruit/ens160.h @@ -0,0 +1,188 @@ +/* + ScioSense_ENS160.h - Library for the ENS160 sensor with I2C interface from ScioSense + 2023 Mar 23 v6 Christoph Friese Bugfix measurement routine, prepare next release + 2021 July 29 v4 Christoph Friese Changed nomenclature to ScioSense as product shifted from ams + 2020 Apr 06 v3 Christoph Friese Changed nomenclature to ScioSense as product shifted from ams + 2020 Feb 15 v2 Giuseppe Pasetti Corrected firmware flash option + 2019 May 05 v1 Christoph Friese Created + based on application note "ENS160 Software Integration.pdf" rev 0.01 +*/ + +#ifndef __SCIOSENSE_ENS160_H_ +#define __SCIOSENSE_ENS160_H_ + +#include "../i2cmaster.hpp" +#include +// #define byte uint8_t + +// #if (ARDUINO >= 100) +// #include "Arduino.h" +// #else +// #include "WProgram.h" +// #endif + +// #include + +// Chip constants +#define ENS160_PARTID 0x0160 +#define ENS161_PARTID 0x0161 +#define ENS160_BOOTING 10 + +// 7-bit I2C slave address of the ENS160 +#define ENS160_I2CADDR_0 0x52 //ADDR low +#define ENS160_I2CADDR_1 0x53 //ADDR high + +// ENS160 registers for version V0 +#define ENS160_REG_PART_ID 0x00 // 2 byte register +#define ENS160_REG_OPMODE 0x10 +#define ENS160_REG_CONFIG 0x11 +#define ENS160_REG_COMMAND 0x12 +#define ENS160_REG_TEMP_IN 0x13 +#define ENS160_REG_RH_IN 0x15 +#define ENS160_REG_DATA_STATUS 0x20 +#define ENS160_REG_DATA_AQI 0x21 +#define ENS160_REG_DATA_TVOC 0x22 +#define ENS160_REG_DATA_ECO2 0x24 +#define ENS160_REG_DATA_BL 0x28 +#define ENS160_REG_DATA_T 0x30 +#define ENS160_REG_DATA_RH 0x32 +#define ENS160_REG_DATA_MISR 0x38 +#define ENS160_REG_GPR_WRITE_0 0x40 +#define ENS160_REG_GPR_WRITE_1 ENS160_REG_GPR_WRITE_0 + 1 +#define ENS160_REG_GPR_WRITE_2 ENS160_REG_GPR_WRITE_0 + 2 +#define ENS160_REG_GPR_WRITE_3 ENS160_REG_GPR_WRITE_0 + 3 +#define ENS160_REG_GPR_WRITE_4 ENS160_REG_GPR_WRITE_0 + 4 +#define ENS160_REG_GPR_WRITE_5 ENS160_REG_GPR_WRITE_0 + 5 +#define ENS160_REG_GPR_WRITE_6 ENS160_REG_GPR_WRITE_0 + 6 +#define ENS160_REG_GPR_WRITE_7 ENS160_REG_GPR_WRITE_0 + 7 +#define ENS160_REG_GPR_READ_0 0x48 +#define ENS160_REG_GPR_READ_4 ENS160_REG_GPR_READ_0 + 4 +#define ENS160_REG_GPR_READ_6 ENS160_REG_GPR_READ_0 + 6 +#define ENS160_REG_GPR_READ_7 ENS160_REG_GPR_READ_0 + 7 + +//ENS160 data register fields +#define ENS160_COMMAND_NOP 0x00 +#define ENS160_COMMAND_CLRGPR 0xCC +#define ENS160_COMMAND_GET_APPVER 0x0E +#define ENS160_COMMAND_SETTH 0x02 +#define ENS160_COMMAND_SETSEQ 0xC2 + +#define ENS160_OPMODE_RESET 0xF0 +#define ENS160_OPMODE_DEP_SLEEP 0x00 +#define ENS160_OPMODE_IDLE 0x01 +#define ENS160_OPMODE_STD 0x02 +#define ENS160_OPMODE_LP 0x03 +#define ENS160_OPMODE_CUSTOM 0xC0 + +#define ENS160_BL_CMD_START 0x02 +#define ENS160_BL_CMD_ERASE_APP 0x04 +#define ENS160_BL_CMD_ERASE_BLINE 0x06 +#define ENS160_BL_CMD_WRITE 0x08 +#define ENS160_BL_CMD_VERIFY 0x0A +#define ENS160_BL_CMD_GET_BLVER 0x0C +#define ENS160_BL_CMD_GET_APPVER 0x0E +#define ENS160_BL_CMD_EXITBL 0x12 + +#define ENS160_SEQ_ACK_NOTCOMPLETE 0x80 +#define ENS160_SEQ_ACK_COMPLETE 0xC0 + +#define IS_ENS160_SEQ_ACK_NOT_COMPLETE(x) (ENS160_SEQ_ACK_NOTCOMPLETE == (ENS160_SEQ_ACK_NOTCOMPLETE & (x))) +#define IS_ENS160_SEQ_ACK_COMPLETE(x) (ENS160_SEQ_ACK_COMPLETE == (ENS160_SEQ_ACK_COMPLETE & (x))) + +#define ENS160_DATA_STATUS_NEWDAT 0x02 +#define ENS160_DATA_STATUS_NEWGPR 0x01 + +#define IS_NEWDAT(x) (ENS160_DATA_STATUS_NEWDAT == (ENS160_DATA_STATUS_NEWDAT & (x))) +#define IS_NEWGPR(x) (ENS160_DATA_STATUS_NEWGPR == (ENS160_DATA_STATUS_NEWGPR & (x))) +#define IS_NEW_DATA_AVAILABLE(x) (0 != ((ENS160_DATA_STATUS_NEWDAT | ENS160_DATA_STATUS_NEWGPR ) & (x))) + +#define CONVERT_RS_RAW2OHMS_I(x) (1 << ((x) >> 11)) +#define CONVERT_RS_RAW2OHMS_F(x) (pow (2, (float)(x) / 2048)) + +typedef struct { + uint8_t aqi; + uint16_t tvoc; + uint16_t eco2; +} ENS160_DATA; + +class ScioSense_ENS160 { + + public: + ScioSense_ENS160(); + + void setI2C(uint8_t sda, uint8_t scl); // Function to redefine I2C pins + + bool begin(); // Init I2C communication, resets ENS160 and checks its PART_ID. Returns false on I2C problems or wrong PART_ID. + uint8_t revENS16x() { return this->_revENS16x; } // Report version of sensor (0: ENS160, 1: ENS161) + bool setMode(uint8_t mode); // Set operation mode of sensor + + bool initCustomMode(uint16_t stepNum); // Initialize definition of custom mode with steps + bool addCustomStep(uint16_t time, bool measureHP0, bool measureHP1, bool measureHP2, bool measureHP3, uint16_t tempHP0, uint16_t tempHP1, uint16_t tempHP2, uint16_t tempHP3); + // Add a step to custom measurement profile with definition of duration, enabled data acquisition and temperature for each hotplate + + bool readData (ENS160_DATA *data); + bool readStatus(uint8_t *status); + bool measure(bool waitForNew); // Perform measurement and stores result in internal variables + bool measureRaw(bool waitForNew); // Perform raw measurement and stores result in internal variables + bool set_envdata(float t, float h); // Writes t (degC) and h (%rh) to ENV_DATA. Returns "0" if I2C transmission is successful + bool set_envdata210(uint16_t t, uint16_t h); // Writes t and h (in ENS210 format) to ENV_DATA. Returns "0" if I2C transmission is successful + uint8_t getMajorRev() { return this->_fw_ver_major; } // Get major revision number of used firmware + uint8_t getMinorRev() { return this->_fw_ver_minor; } // Get minor revision number of used firmware + uint8_t getBuild() { return this->_fw_ver_build; } // Get build revision number of used firmware + + uint8_t getAQI() { return this->_data_aqi; } // Get AQI value of last measurement + uint16_t getTVOC() { return this->_data_tvoc; } // Get TVOC value of last measurement + uint16_t geteCO2() { return this->_data_eco2; } // Get eCO2 value of last measurement + uint16_t getAQI500() { return this->_data_aqi500; } // Get AQI500 value of last measurement + uint32_t getHP0() { return this->_hp0_rs; } // Get resistance of HP0 of last measurement + uint32_t getHP1() { return this->_hp1_rs; } // Get resistance of HP1 of last measurement + uint32_t getHP2() { return this->_hp2_rs; } // Get resistance of HP2 of last measurement + uint32_t getHP3() { return this->_hp3_rs; } // Get resistance of HP3 of last measurement + uint32_t getHP0BL() { return this->_hp0_bl; } // Get baseline resistance of HP0 of last measurement + uint32_t getHP1BL() { return this->_hp1_bl; } // Get baseline resistance of HP1 of last measurement + uint32_t getHP2BL() { return this->_hp2_bl; } // Get baseline resistance of HP2 of last measurement + uint32_t getHP3BL() { return this->_hp3_bl; } // Get baseline resistance of HP3 of last measurement + uint8_t getMISR() { return this->_misr; } // Return status code of sensor + + private: + I2cMaster i2cDevice; + bool reset(); // Sends a reset to the ENS160. Returns false on I2C problems. + bool checkPartID(); // Reads the part ID and confirms valid sensor + bool clearCommand(); // Initialize idle mode and confirms + bool getFirmware(); // Read firmware revisions + + uint8_t _revENS16x; // ENS160 or ENS161 connected? (FW >7) + + uint8_t _fw_ver_major; + uint8_t _fw_ver_minor; + uint8_t _fw_ver_build; + + uint16_t _stepCount; // Counter for custom sequence + + uint8_t _data_aqi; + uint16_t _data_tvoc; + uint16_t _data_eco2; + uint16_t _data_aqi500; + uint32_t _hp0_rs; + uint32_t _hp0_bl; + uint32_t _hp1_rs; + uint32_t _hp1_bl; + uint32_t _hp2_rs; + uint32_t _hp2_bl; + uint32_t _hp3_rs; + uint32_t _hp3_bl; + uint16_t _temp; + int _slaveaddr; // Slave address of the ENS160 + uint8_t _misr; + + uint8_t _seq_steps[1][8]; + + bool write8(uint8_t reg, uint8_t value); + bool read8 (uint8_t reg, uint8_t *value); + bool read16 (uint8_t reg, uint16_t *value); + bool read16LE (uint8_t reg, uint16_t *value); + bool readBytes (uint8_t reg, uint8_t *bytes, uint8_t len); +}; + + +#endif diff --git a/software/test-software/src/adafruit/sensor.h b/software/test-software/src/adafruit/sensor.h new file mode 100644 index 0000000..ac7e454 --- /dev/null +++ b/software/test-software/src/adafruit/sensor.h @@ -0,0 +1,224 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software< /span> + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* Update by K. Townsend (Adafruit Industries) for lighter typedefs, and + * extended sensor support to include color, voltage and current */ + +#ifndef _ADAFRUIT_SENSOR_H +#define _ADAFRUIT_SENSOR_H + +#ifndef ARDUINO +#include +#elif ARDUINO >= 100 +#include "Arduino.h" +#include "Print.h" +#else +#include "WProgram.h" +#endif + +/* Constants */ +#define SENSORS_GRAVITY_EARTH (9.80665F) /**< Earth's gravity in m/s^2 */ +#define SENSORS_GRAVITY_MOON (1.6F) /**< The moon's gravity in m/s^2 */ +#define SENSORS_GRAVITY_SUN (275.0F) /**< The sun's gravity in m/s^2 */ +#define SENSORS_GRAVITY_STANDARD (SENSORS_GRAVITY_EARTH) +#define SENSORS_MAGFIELD_EARTH_MAX \ + (60.0F) /**< Maximum magnetic field on Earth's surface */ +#define SENSORS_MAGFIELD_EARTH_MIN \ + (30.0F) /**< Minimum magnetic field on Earth's surface */ +#define SENSORS_PRESSURE_SEALEVELHPA \ + (1013.25F) /**< Average sea level pressure is 1013.25 hPa */ +#define SENSORS_DPS_TO_RADS \ + (0.017453293F) /**< Degrees/s to rad/s multiplier \ + */ +#define SENSORS_RADS_TO_DPS \ + (57.29577793F) /**< Rad/s to degrees/s multiplier */ +#define SENSORS_GAUSS_TO_MICROTESLA \ + (100) /**< Gauss to micro-Tesla multiplier */ + +/** Sensor types */ +typedef enum { + SENSOR_TYPE_ACCELEROMETER = (1), /**< Gravity + linear acceleration */ + SENSOR_TYPE_MAGNETIC_FIELD = (2), + SENSOR_TYPE_ORIENTATION = (3), + SENSOR_TYPE_GYROSCOPE = (4), + SENSOR_TYPE_LIGHT = (5), + SENSOR_TYPE_PRESSURE = (6), + SENSOR_TYPE_PROXIMITY = (8), + SENSOR_TYPE_GRAVITY = (9), + SENSOR_TYPE_LINEAR_ACCELERATION = + (10), /**< Acceleration not including gravity */ + SENSOR_TYPE_ROTATION_VECTOR = (11), + SENSOR_TYPE_RELATIVE_HUMIDITY = (12), + SENSOR_TYPE_AMBIENT_TEMPERATURE = (13), + SENSOR_TYPE_OBJECT_TEMPERATURE = (14), + SENSOR_TYPE_VOLTAGE = (15), + SENSOR_TYPE_CURRENT = (16), + SENSOR_TYPE_COLOR = (17), + SENSOR_TYPE_TVOC = (18), + SENSOR_TYPE_VOC_INDEX = (19), + SENSOR_TYPE_NOX_INDEX = (20), + SENSOR_TYPE_CO2 = (21), + SENSOR_TYPE_ECO2 = (22), + SENSOR_TYPE_PM10_STD = (23), + SENSOR_TYPE_PM25_STD = (24), + SENSOR_TYPE_PM100_STD = (25), + SENSOR_TYPE_PM10_ENV = (26), + SENSOR_TYPE_PM25_ENV = (27), + SENSOR_TYPE_PM100_ENV = (28), + SENSOR_TYPE_GAS_RESISTANCE = (29), + SENSOR_TYPE_UNITLESS_PERCENT = (30), + SENSOR_TYPE_ALTITUDE = (31) +} sensors_type_t; + +/** struct sensors_vec_s is used to return a vector in a common format. */ +typedef struct { + union { + float v[3]; ///< 3D vector elements + struct { + float x; ///< X component of vector + float y; ///< Y component of vector + float z; ///< Z component of vector + }; ///< Struct for holding XYZ component + /* Orientation sensors */ + struct { + float roll; /**< Rotation around the longitudinal axis (the plane body, 'X + axis'). Roll is positive and increasing when moving + downward. -90 degrees <= roll <= 90 degrees */ + float pitch; /**< Rotation around the lateral axis (the wing span, 'Y + axis'). Pitch is positive and increasing when moving + upwards. -180 degrees <= pitch <= 180 degrees) */ + float heading; /**< Angle between the longitudinal axis (the plane body) + and magnetic north, measured clockwise when viewing from + the top of the device. 0-359 degrees */ + }; ///< Struct for holding roll/pitch/heading + }; ///< Union that can hold 3D vector array, XYZ components or + ///< roll/pitch/heading + int8_t status; ///< Status byte + uint8_t reserved[3]; ///< Reserved +} sensors_vec_t; + +/** struct sensors_color_s is used to return color data in a common format. */ +typedef struct { + union { + float c[3]; ///< Raw 3-element data + /* RGB color space */ + struct { + float r; /**< Red component */ + float g; /**< Green component */ + float b; /**< Blue component */ + }; ///< RGB data in floating point notation + }; ///< Union of various ways to describe RGB colorspace + uint32_t rgba; /**< 24-bit RGBA value */ +} sensors_color_t; + +/* Sensor event (36 bytes) */ +/** struct sensor_event_s is used to provide a single sensor event in a common + * format. */ +typedef struct { + int32_t version; /**< must be sizeof(struct sensors_event_t) */ + int32_t sensor_id; /**< unique sensor identifier */ + int32_t type; /**< sensor type */ + int32_t reserved0; /**< reserved */ + int32_t timestamp; /**< time is in milliseconds */ + union { + float data[4]; ///< Raw data */ + sensors_vec_t acceleration; /**< acceleration values are in meter per second + per second (m/s^2) */ + sensors_vec_t + magnetic; /**< magnetic vector values are in micro-Tesla (uT) */ + sensors_vec_t orientation; /**< orientation values are in degrees */ + sensors_vec_t gyro; /**< gyroscope values are in rad/s */ + float temperature; /**< temperature is in degrees centigrade (Celsius) */ + float distance; /**< distance in centimeters */ + float light; /**< light in SI lux units */ + float pressure; /**< pressure in hectopascal (hPa) */ + float relative_humidity; /**< relative humidity in percent */ + float current; /**< current in milliamps (mA) */ + float voltage; /**< voltage in volts (V) */ + float tvoc; /**< Total Volatile Organic Compounds, in ppb */ + float voc_index; /**< VOC (Volatile Organic Compound) index where 100 is + normal (unitless) */ + float nox_index; /**< NOx (Nitrogen Oxides) index where 100 is normal + (unitless) */ + float CO2; /**< Measured CO2 in parts per million (ppm) */ + float eCO2; /**< equivalent/estimated CO2 in parts per million (ppm + estimated from some other measurement) */ + float pm10_std; /**< Standard Particulate Matter <=1.0 in parts per million + (ppm) */ + float pm25_std; /**< Standard Particulate Matter <=2.5 in parts per million + (ppm) */ + float pm100_std; /**< Standard Particulate Matter <=10.0 in parts per + million (ppm) */ + float pm10_env; /**< Environmental Particulate Matter <=1.0 in parts per + million (ppm) */ + float pm25_env; /**< Environmental Particulate Matter <=2.5 in parts per + million (ppm) */ + float pm100_env; /**< Environmental Particulate Matter <=10.0 in parts per + million (ppm) */ + float gas_resistance; /**< Proportional to the amount of VOC particles in + the air (Ohms) */ + float unitless_percent; /** +#include +#include + +#include "i2cmaster.hpp" + +I2cMaster::I2cMaster () { + address = 0; + timer = 0; +} + +void I2cMaster::tick1ms () { + if (timer > 0) { + timer--; + } +} + +bool I2cMaster::begin (uint8_t addr) { + this->address = addr; + // TWBR = 13; // 100kHz (TWPS1:0 = 00), TWBR = (F_CPU - 16 * 100000) / (2 * 100000 * 4); + TWBR = 100; // 50kHz (TWPS1:0 = 00), TWBR = (F_CPU - 16 * 50000) / (2 * 50000 * 4); + TWCR = (1 << TWEN); + return true; +} + +void I2cMaster::end () { + TWCR = (1 << TWEN); + TWBR = 0; +} + +bool I2cMaster::read (uint8_t *buffer, uint8_t len) { + if (start(true)) { + if (readBytes(buffer, len)) { + if (stop()) { + return true; + } + } + } + return false; +} + + +bool I2cMaster::write (const uint8_t *buffer, uint8_t len) { + if (start(false)) { + if (writeBytes(buffer, len, false)) { + if (stop()) { + return true; + } + } + } + return false; +} + +bool I2cMaster::write_P (const uint8_t *buffer, uint8_t len) { + if (start(false)) { + if (writeBytes(buffer, len, true)) { + if (stop()) { + return true; + } + } + } + return false; +} + + +bool I2cMaster::writeByteAndBuffer (uint8_t byte, const uint8_t *buffer, uint8_t len) { + if (start(false)) { + do { + TWDR = byte; + TWCR = (1 << TWINT) | (1 << TWEN); // send byte + while (!(TWCR & (1 << TWINT))) {}; // wait until last action done + if ((TWSR & 0xf8) != 0x28) { + return false; + } + byte = *buffer++; + } while (len-- > 0); + return true; + } + return false; +} + + +bool I2cMaster::write_then_read (const uint8_t *write_buffer, uint8_t write_len, uint8_t *read_buffer, uint8_t read_len) { + if (start(false)) { + if (writeBytes(write_buffer, write_len, false)) { + if (start(true)) { + if (readBytes(read_buffer, read_len)) { + if (stop()) { + return true; + } + } + } + } + } + return false; +} + +// ------------------------------------------------------------- + +bool I2cMaster::readBytes (uint8_t *buffer, uint8_t len) { + while (len-- > 0) { + if (len > 0) { + TWCR = (1 << TWEA) | (1 << TWINT) | (1 << TWEN); // read data byte with ACK enabled + } else { + TWCR = (1 << TWINT) | (1 << TWEN); // read data byte with ACK disabled + } + while (!(TWCR & (1 << TWINT))) {}; // wait until last action done + uint8_t sr = TWSR & 0xf8; + if ((len > 0 && sr != 0x50) || (len == 0 && sr != 0x58)) { + return false; + } + *buffer++ = TWDR; + } + return true; +} + +bool I2cMaster::writeBytes (const uint8_t *buffer, uint8_t len, bool fromFlash) { + while (len-- > 0) { + // printf_P(PSTR("[wB:len=%d, byte=%02x]"), len + 1, *buffer); + TWDR = fromFlash ? pgm_read_byte(buffer++) : *buffer++; + TWCR = (1 << TWINT) | (1 << TWEN); // send data byte + timer = 5; + while (timer > 0 && !(TWCR & (1 << TWINT))) {}; // wait until last action done + if (!timer || (TWSR & 0xf8) != 0x28) { + return false; + } + } + return true; +} + +bool I2cMaster::start (bool read) { + TWCR = (1 << TWINT) | (1 << TWSTA) | (1 << TWEN); // send START condition + timer = 5; + while (timer > 0 && !(TWCR & (1 << TWINT))) {}; // wait until last action done + uint8_t sr = TWSR & 0xf8; + if (!timer || (sr != 0x08 && sr != 0x10)) { + return false; + } + TWDR = (address << 1) | (read ? 1 : 0); // address + R/nW + TWCR = (1 << TWINT) | (1 << TWEN); // send address/RW + timer = 5; + while (timer > 0 && !(TWCR & (1 << TWINT))) {}; // wait until last action done + sr = TWSR & 0xf8; + if (!timer || (!read && sr != 0x18) || (read && sr != 0x40)) { + return false; + } + return true; +} + +bool I2cMaster::stop () { + TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWSTO); + while (TWCR & ( 1 << TWSTO)); + return true; +} + diff --git a/software/test-software/src/i2cmaster.hpp b/software/test-software/src/i2cmaster.hpp new file mode 100644 index 0000000..89b1e46 --- /dev/null +++ b/software/test-software/src/i2cmaster.hpp @@ -0,0 +1,30 @@ +#ifndef I2C_MASTER +#define I2C_MASTER + +#include + +class I2cMaster { + public: + static void end (); + + public: + I2cMaster (); + void tick1ms (); + bool begin (uint8_t addr); + bool read (uint8_t *buffer, uint8_t len); + bool write (const uint8_t *buffer, uint8_t len); + bool write_P (const uint8_t *buffer, uint8_t len); + bool write_then_read (const uint8_t *write_buffer, uint8_t write_len, uint8_t *read_buffer, uint8_t read_len); + bool writeByteAndBuffer (uint8_t byte, const uint8_t *buffer, uint8_t len); + + private: + uint8_t address; + uint8_t timer; + bool start (bool read); + bool stop (); + bool writeBytes (const uint8_t *buffer, uint8_t len, bool fromFlash); + bool writeBytes_P (const uint8_t *buffer); + bool readBytes (uint8_t *buffer, uint8_t len); +}; + +#endif \ No newline at end of file diff --git a/software/test-software/src/i2cslave.cpp b/software/test-software/src/i2cslave.cpp new file mode 100644 index 0000000..2bf6ac2 --- /dev/null +++ b/software/test-software/src/i2cslave.cpp @@ -0,0 +1,92 @@ +#include +#include +#include + +#include "i2cslave.hpp" + +I2cSlave::I2cSlave () { + timer = 0; + fromMaster.rIndex = 0; + fromMaster.wIndex = 0; + toMaster.rIndex = 0; + toMaster.wIndex = 0; +} + +void I2cSlave::tick1ms () { + if (timer > 0) { + timer--; + } +} + +bool I2cSlave::begin (uint8_t addr, bool acceptGeneralCalls) { + if (addr > 127) { + return false; + } + TWAR = addr << 1 | (acceptGeneralCalls ? 1 : 0); + TWBR = 100; // 50kHz (TWPS1:0 = 00), TWBR = (F_CPU - 16 * 50000) / (2 * 50000 * 4); + TWCR = (1 << TWEA) | (1 << TWEN) | (1 << TWIE); + return true; +} + +void I2cSlave::end () { + TWCR = (1 << TWEN); + TWBR = 0; +} + +int I2cSlave::read () { + return getByte(fromMaster); +} + +void I2cSlave::write (uint8_t byte) { + putByte(toMaster, byte); +} + + +void I2cSlave::putByte (RingBuffer& buffer, uint8_t byte) { + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { + buffer.data[buffer.wIndex++] = byte; + if (buffer.wIndex >= sizeof(buffer.data)) { + buffer.wIndex = 0; + } + if (buffer.wIndex == buffer.rIndex) { + buffer.rIndex++; + if (buffer.rIndex >= sizeof(buffer.data)) { + buffer.rIndex = 0; + } + } + } +} + +int I2cSlave::getByte (RingBuffer& buffer) { + uint8_t b; + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { + if (buffer.rIndex == buffer.wIndex) { + return EOF; + } + b = buffer.data[buffer.rIndex++]; + if (buffer.rIndex >= sizeof(buffer.data)) { + buffer.rIndex = 0; + } + } + return b; +} + +void I2cSlave::handleTWIIsr () { + uint8_t sr = TWSR & 0xf8; + switch (sr) { + case 0x80: { // Previously addressed with own SLA+W; data has been received; ACK has been returned + putByte(fromMaster, TWDR); + TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWIE); // no TWEA -> only one byte accepted + break; + } + case 0xa8: { // Own SLA+R has been received; ACK has been returned + int response = getByte(toMaster);; + TWDR = response < 0 ? 0x00 : (uint8_t)response; + TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWIE); // no TWEA -> only one byte accepted + break; + } + default: TWCR = (1 << TWINT) | (1 << TWEA) | (1 << TWEN) | (1 << TWIE); break; + } + +} + diff --git a/software/test-software/src/i2cslave.hpp b/software/test-software/src/i2cslave.hpp new file mode 100644 index 0000000..2fe2dc7 --- /dev/null +++ b/software/test-software/src/i2cslave.hpp @@ -0,0 +1,32 @@ +#ifndef I2C_SLAVE +#define I2C_SLAVE + +#include + +class I2cSlave { + private: + typedef struct { + uint8_t rIndex; + uint8_t wIndex; + uint8_t data[8]; + } RingBuffer; + + public: + I2cSlave (); + void tick1ms (); + bool begin (uint8_t addr, bool acceptGeneralCalls); + void end (); + void handleTWIIsr (); + int read (); + void write (uint8_t byte); + + private: + uint8_t timer; + RingBuffer fromMaster; + RingBuffer toMaster; + void putByte (RingBuffer& buffer, uint8_t byte); + int getByte (RingBuffer& buffer); + +}; + +#endif \ No newline at end of file diff --git a/software/test-software/src/main.cpp b/software/test-software/src/main.cpp new file mode 100644 index 0000000..2a7faec --- /dev/null +++ b/software/test-software/src/main.cpp @@ -0,0 +1,447 @@ +#include +#include +#include +#include + +#include +#include + +#include "main.hpp" +#include "units/encoder.hpp" +#include "units/i2c.hpp" +#include "units/led.hpp" +#include "units/ieee485.hpp" +#include "units/led.hpp" +#include "units/lcd.hpp" +#include "units/switch.hpp" +#include "units/rgb.hpp" +#include "units/seg7.hpp" +#include "units/poti.hpp" +#include "units/r2r.hpp" +#include "units/motor.hpp" +#include "units/portexp.hpp" +#include "units/uart1.hpp" +#include "units/modbus.hpp" +#include "units/rtc8563.hpp" +#include "units/cc1101.hpp" + +const char MAIN_CPP_DATE[] PROGMEM = __DATE__; +const char MAIN_CPP_TIME[] PROGMEM = __TIME__; +#ifdef __AVR_ATmega328P__ + const char MAIN_CPP_PART_NAME[] PROGMEM = "ATmega328P"; +#endif +#ifdef __AVR_ATmega644P__ + const char MAIN_CPP_PART_NAME[] PROGMEM = "ATmega644P"; +#endif +#ifdef __AVR_ATmega1284P__ + const char MAIN_CPP_PART_NAME[] PROGMEM = "ATmega1284P"; +#endif + +#ifndef F_CPU + #if defined(__AVR_ATmega328P__) + #define F_CPU 16000000L + #define BAUD_RATE 38400 + #elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__) + #define F_CPU 12000000L + #define BAUD_RATE 115200 + #else + #error missing defined for F_CPU + #endif +#endif + +#ifndef BAUD_RATE + #if defined(__AVR_ATmega328P__) + #define BAUD_RATE 38400 + #elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__) + #define BAUD_RATE 115200 + #else + #error missing define BAUD_RATE + #endif +#endif + +const char PSTR_DIVIDER[] PROGMEM = "\n=====================================\n "; +const char PSTR_LINEFEED[] PROGMEM = "\n"; +const char PSTR_ERROR[] PROGMEM = "ERROR"; +const char PSTR_Done[] PROGMEM = "Done"; +// const char PSTR_HARDWARE_V1a[] PROGMEM = "V1a"; +// const char PSTR_HARDWARE_V2a[] PROGMEM = "V2a"; +// const char* const PSTR_HARDWARE[] PROGMEM = { PSTR_HARDWARE_V1a, PSTR_HARDWARE_V2a }; + +uint8_t hardwareVersion = 0; + +extern "C" { + void __cxa_pure_virtual () {} + int __cxa_guard_acquire(uint8_t *g) { return 0; } + void __cxa_guard_release(uint8_t *g) {} + void __cxa_guard_abort(uint8_t *g) {} + void __gxx_personality_sj0 () {} + void __cxa_rethrow () {} + void __cxa_begin_catch () {} + void __cxa_end_catch () {} + + int uart_putchar(char c, FILE *stream) { + if (c == '\n') { + uart_putchar('\r', stream); + } + if (stream == stdout) { + loop_until_bit_is_set(UCSR0A, UDRE0); + UDR0 = c; + } + return 0; + } + + + uint64_t volatile systemMillis = 0; + uint8_t volatile uartBuffer[32]; + uint8_t volatile rIndex = 0; + uint8_t volatile wIndex = 0; + + int uart_getchar (FILE *stream) { + // if (rIndex == wIndex) { + // // nothing in buffer + // return EOF; + // } + // printf_P(PSTR(" r%d"), rIndex); + while (rIndex == wIndex) { + // wait for character + } + + // don't use "char c" because german special characters would lead to negative return -> stream error + // char c = uartBuffer[rIndex++]; + + uint8_t c = uartBuffer[rIndex++]; + // printf_P(PSTR("(%02x) "), c); + if (c == '\r') { + c = '\n'; + } + putchar(c); // echo on terminal + return c; + } + + static FILE mystdout = { 0, 0, _FDEV_SETUP_WRITE , 0, 0, uart_putchar, NULL, 0 }; + static FILE mystdin = { 0, 0, _FDEV_SETUP_READ , 0, 0, NULL, uart_getchar, 0 }; + + #if defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__) + static volatile uint16_t timerFlashGreenLed = 0; + static volatile uint16_t timerFlashRedLed = 0; + void flashRedLed (uint16_t ms) { + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { + if (timerFlashRedLed == 0) { + PORTC |= (1 << PC2); + if (ms < 0xff80) { + ms += 0x80; // at least 128ms OFF after + } + timerFlashRedLed = ms; + } + } + } + void flashGreenLed (uint16_t ms) { + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { + if (timerFlashGreenLed == 0) { + PORTC |= (1 << PC4); + if (ms < 0xff80) { + ms += 0x80; // at least 128ms OFF after + } + timerFlashGreenLed = ms; + } + } + } + #endif + + static volatile uint32_t timer1ms = 0; + static volatile int keyUart0 = EOF; + + Led led; + Switch sw; + Rgb rgb; + Seg7 seg7; + Poti poti; + Encoder encoder; + R2r r2r; + Motor motor; + PortExp portExp; + Lcd lcd; + Uart1 uart1; + Modbus modbus; + Ieee485 ieee485; + I2c i2cSparkfun(I2c::SparkFunEnvCombo); + I2c i2cMaster(I2c::Master); + I2c i2cSlave(I2c::Slave); + Rtc8563 rtc8563(Rtc8563::NORMAL); + Cc1101 cc1101Send(Cc1101::Send); + Cc1101 cc1101Receive(Cc1101::Receive); +} + +const char *hardwareVersionPStr (uint8_t version) { + switch (version) { + case 1: return PSTR("V1a"); + case 2: return PSTR("V2a"); + default: return PSTR("V??"); + } +} + +uint8_t detectHardwareVersion () { + ADMUX = (1 << ADLAR) | (1 << REFS0) | 7; // ADC7, VREF=AVCC=3.3V + ADCSRA = (1 << ADEN) | 7; // ADC Enable, Prescaler 128 + ADCSRA |= (1 << ADSC); // start ADC + while (ADCSRA & (1 << ADSC)) {} // wait for result + hardwareVersion = 0; // unknown board version + // printf("Hardware-Version: ADC7H = %d\n", ADCH); + #if defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__) + + if (ADCH >= 0xf4) { + hardwareVersion = 1; + } else if (ADCH >= 0xe0) { + hardwareVersion = 2; + } + #endif + #if defined(__AVR_ATmega328P__) + if (ADCH < 0xd8 && ADCH >= 0xc0) { + hardwareVersion = 1; + } else if (ADCH < 0xd8 && ADCH >= 0xb0) { + hardwareVersion = 2; + } + #endif + + if (hardwareVersion < 1 || hardwareVersion > 2) { + #ifdef __AVR_ATmega644P__ + printf_P(PSTR("\nInvalid Hardware-Version: ADC7H = %d (ATmega644P, 3.3V)\n"), ADCH); + #elif __AVR_ATmega1284P__ + printf_P(PSTR("\nInvalid Hardware-Version: ADC7H = %d (ATmega1284P, 3.3V)\n"), ADCH); + #elif __AVR_ATmega328P__ + printf_P(PSTR("\nInvalid Hardware-Version: ADC7H = %d (ATmega328P, 5V)\n"), ADCH); + #endif + } else { + // const char *pHw; memcpy_P(&pHw, PSTR_HARDWARE + hardwareVersion - 1, sizeof(const char *)); + printf_P(PSTR("\n\nHardware %S detected (ADC7H=0x%02X)"), hardwareVersionPStr(hardwareVersion), ADCH); + } + + + ADMUX = 0; + ADCSRA = 0; + return hardwareVersion; +} + +void setTimer (uint32_t ms) { + ATOMIC_BLOCK(ATOMIC_FORCEON) { + timer1ms = ms; + } +} + +int wait (uint32_t ms) { + setTimer(ms); + do { + ATOMIC_BLOCK(ATOMIC_FORCEON) { + ms = timer1ms; + } + } while (ms > 0 && keyUart0 == EOF); + return keyUart0; +} + +int waitAndReadKey (uint32_t ms) { + keyUart0 = EOF; + int key = wait(ms); + keyUart0 = EOF; + return key; +} + +int main () { + + #if defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__) + // Nano-644 LEDs (Green, Orange, Red) + DDRC |= (1 << PC7) | (1 << PC4) | (1 << PC3) | (1 << PC2); + PORTC &= ~((1 << PC7) | (1 << PC4) | (1 << PC3) | (1 << PC2)); + + // Nano-644 push button SW2 + DDRC &= ~(1 << PC5); + PORTC |= (1 << PC5); // enable internal pullup resistor + #endif + + #ifdef __AVR_ATmega328P__ + DDRB |= (1 << PB5); + PORTB &= ~(1 << PB5); + #endif + + // UART0 interface on Nano-644 + UCSR0A = (1 << U2X0); + UCSR0B = (1 << RXCIE0) | (1 << RXEN0) | (1 <= 1 && hardwareVersion <= 2) { + printf_P(PSTR("Hardware: %S"), hardwareVersionPStr(hardwareVersion)); + } else { + printf_P(PSTR("ERROR: Invalid Hardware (%d)"), hardwareVersion); + for(;;); + } + printf_P(PSTR_DIVIDER); + printf_P(PSTR_LINEFEED); + printf_P(PSTR("Available units:\n\n")); + for (i = 0; i < sizeof(unit) / sizeof(unit[0]); i++) { + TestUnit *pu = unit[i]; + printf_P(PSTR("%3x ... "), i); + printf_P(pu->getName()); + printf_P(PSTR_LINEFEED); + } + printf_P(PSTR("\nSelect unit: ")); + rIndex = 0; wIndex = 0; + fgets(s, sizeof(s), stdin); + } while (sscanf(s, "%x", &i) != 1 || i < 0 || i >= sizeof(unit) / sizeof(unit[0]) ); + + TestUnit *pu = unit[i]; + printf_P(PSTR("\n\n[")); printf_P(pu->getName()); printf_P(PSTR("]: ")); + keyUart0 = EOF; + + pu->init(); + for (uint8_t subtest = 0; subtest < 0xff; subtest++) { + printf_P(PSTR("\n%4d: "), subtest); + if (pu->run(subtest) < 0) { + break; + } + if (keyUart0 == 27) { + keyUart0 = EOF; + break; + } + keyUart0 = EOF; + } + pu->cleanup(); + } +} + +uint64_t millis () { + volatile uint64_t millis = systemMillis; + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { + millis = systemMillis; + } + return millis; +} + +#ifndef USART0_RX_vect + #define USART0_RX_vect USART_RX_vect +#endif +ISR (USART0_RX_vect) { + uint8_t b = UDR0; + keyUart0 = b; + uartBuffer[wIndex++] = b; + // printf_P(PSTR(" w%d(%02x)"), wIndex, b); + if (wIndex == rIndex) { + // buffer overflow, kick out oldest byte + rIndex++; + } +} + +#ifdef USART1_RX_vect + ISR (USART1_RX_vect) { + uint8_t b = UDR1; + if (modbus.enabled) { + modbus.handleRxByte(b); + } + if (uart1.enabled) { + uart1.handleRxByte(b); + } + if (ieee485.enabled) { + ieee485.handleRxByte(b); + } + } +#endif + +ISR (TWI_vect) { + if (i2cMaster.enabled) { + i2cMaster.handleTwiIrq(); + } else if (i2cSlave.enabled) { + i2cSlave.handleTwiIrq(); + } else if (i2cSparkfun.enabled) { + i2cSparkfun.handleTwiIrq(); + } else { + TWCR = (1 << TWINT); // clear interrupt request bit and disable TWI + } +} + +ISR (TIMER2_COMPA_vect) { // every 100us + static uint16_t timer500ms = 0; + static uint8_t timer100us = 0; + + if (encoder.enabled) { + encoder.tick100us(); + } + if (motor.enabled) { + motor.tick100us(); + } + + timer100us++; + if (timer100us >= 10) { + timer100us = 0; + if (timer1ms > 0) { + timer1ms--; + } + systemMillis++; + i2cMaster.tick1ms(); + i2cSlave.tick1ms(); + i2cSparkfun.tick1ms(); + cc1101Send.tick1ms(); + cc1101Receive.tick1ms(); + #if defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__) + if (timerFlashRedLed > 0) { + if (--timerFlashRedLed < 128) { + PORTC &= ~(1 << PC2); // red LED + } + } + if (timerFlashGreenLed > 0) { + if (--timerFlashGreenLed < 128 ) { + PORTC &= ~(1 << PC4); // green LED + } + } + #endif + } + + timer500ms++; + if (timer500ms >= 5000) { + #if defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__) + PORTC ^= (1 << PC3); // orange LED blinking + #endif + #ifdef __AVR_ATmega328P__ + if (!seg7.enabled) { + PORTB ^= (1 << PB5); // LED L + } + #endif + timer500ms = 0; + } +} + diff --git a/software/test-software/src/main.hpp b/software/test-software/src/main.hpp new file mode 100644 index 0000000..7eeff16 --- /dev/null +++ b/software/test-software/src/main.hpp @@ -0,0 +1,38 @@ +#ifndef MAIN_HPP +#define MAIN_HPP + +#include +#include + +#define ENTER '\r' +#define CTRLC '\003' +#define ESCAPE 0x1b + +extern int wait (uint32_t ms); +extern int waitAndReadKey (uint32_t ms); +extern uint64_t millis (); + +extern uint8_t hardwareVersion; + +extern const char PSTR_DIVIDER[]; +extern const char PSTR_LINEFEED[]; +extern const char PSTR_ERROR[]; +extern const char PSTR_Done[]; + +#if defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__) + extern "C" { + extern void flashRedLed (uint16_t ms); + extern void flashGreenLed (uint16_t ms); + } +#endif + + +class TestUnit { + public: + virtual int8_t run (uint8_t subtest) = 0; + virtual void init () = 0; + virtual void cleanup () = 0; + virtual PGM_P getName () = 0; +}; + +#endif \ No newline at end of file diff --git a/software/test-software/src/units/cc1101.cpp b/software/test-software/src/units/cc1101.cpp new file mode 100644 index 0000000..aebe713 --- /dev/null +++ b/software/test-software/src/units/cc1101.cpp @@ -0,0 +1,753 @@ +#include +#include +#include +#include + +#include "cc1101.hpp" +#include "../main.hpp" + +// 868MHz Modem E07-900MM1DS (chipset CC1101) +// https://jlcpcb.com/partdetail/Chengdu_Ebyte_ElecTech-E07900MM10S/C5844212 + +#ifdef __AVR_ATmega328P__ + + // Arduino-Nano-5V + // ------------------------------------ + // not available + + void Cc1101::init () {} + void Cc1101::cleanup () {} + void Cc1101::setChipEnableLow () {} + void Cc1101::setChipEnableHigh () {} + int8_t Cc1101::run (uint8_t subtest) { return -1; } + PGM_P Cc1101::getName () { return PSTR("?"); } + +#endif + + +#if defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__) + + // Nano-644 + // -------------------------------------------------------- + // PA4 ... nCS + // PB4 ... nSS (not used, but must be high, otherwise AVR SPI master not working) + // PB5 ... MOSI + // PB6 ... MISO + // PB7 ... SCK + + // -------------------------------------------------------- + + // Output power table from CC1101 datasheet page 59 + const Cc1101::PATABLE_INIT_ITEM_t PMEM_CC1101_PATABLE_INIT[] PROGMEM = { + { 0xc6, "9.6" }, // 9.6 dBm / 29.4mA (default value) + { 0xc0, "11" }, // 11 dBm / 34.2mA + { 0xc5, "10" }, // 10 dBm / 30.0mA + { 0xcd, "7" }, // 7 dBm / 25.8mA + { 0x86, "5" }, // 5 dBm / 19.9mA + { 0x50, "0" }, // 0 dBm / 16.8mA + { 0x37, "-6" }, // -6 dBm / 16.4mA + { 0x26, "-10" }, // 10 dBm / 14.5mA + { 0x1d, "-15" }, // 15 dBm / 13.3mA + { 0x17, "-20" }, // 20 dBm / 12.6mA + { 0x03, "-30" }, // 30 dBm / 12.0mA + }; + const Cc1101::Register_t PMEM_CC1101_REGISTER_INIT PROGMEM = { + /* 0x00: iocfg2 0x0b (----) */ { Cc1101::CHIP_NOT_READY, 0, 0 }, // GDO2 + /* 0x01: iocfg1 0x2e (----) */ { Cc1101::HIGH_IMPEDANCE_WHEN_CHIP_SELECT_HIGH, 0, 0 }, // GDO1/MISO + /* 0x02: iocfg0 0x06 (----) */ { Cc1101::SYNC_SENT_OR_RECEIVED_UNTIL_END_OF_PACKET, 0, 0 }, // GDO0 -> PA5 + /* 0x03: fifothr 0x47 (0x07) */ { 7, 0, 1, 0 }, // fifo_thr = 0b111, close_in_rx=0, adc_retention = 1, (bit7=0) + /* 0x04: sync1 0x7a (0xd3) */ 0x7a, + /* 0x05: sync0 0x0e (0x91) */ 0x0e, + /* 0x06: pktlen 0x14 (0x3d) */ PACKET_LENGTH, + /* 0x07: pktctrl1 0x04 (----) */ { Cc1101::NO_ADDR_CHECK, 1, 0, 0, 0 }, // adr_chk=0b00, append_status=1, crc_autoflush=0, (bit4=0), pqt=0b000 + /* 0x08: pktctrl0 0x05 (----) */ { Cc1101::FIXED, 1, 0, Cc1101::NORMAL_USE_FIFO, 0, 0 }, // length_config=0b01, crc_en=1, (bit3=0), pkt_format=0b00, white_data=0, (bit7=0) + /* 0x09: addr 0x00 (----) */ 0x00, + /* 0x0a: channr 0x00 (----) */ 0x00, + /* 0x0b: fsctrl1 0x06 (0x08) */ { 6, 0, 0 }, // frqu_if=6, (bit5=0), (bit76=0b00) + /* 0x0c: fsctrl0 0x00 (----) */ { 0 }, // freqoff = 0 + /* 0x0d: frequ2 0x21 (----) */ 0x21, + /* 0x0e: frequ1 0x62 (----) */ 0x62, + /* 0x0f: frequ0 0x76 (----) */ 0x76, + /* 0x10: mdmcfg4 0xca (0x5b) */ { 0x0a, 0, 3 }, // drate_e=0x0a, chanbw_m=0, chanbw_e=3 + /* 0x11: mdmcfg3 0xf8 (----) */ { 0xf8 }, // drate_m=0xf8 + /* 0x12: mdmcfg2 0x16 (0x03) */ { Cc1101::SYNC_16_16_CARRIER_SENSE, 0, Cc1101::GFSK, 0}, // sync_mode=0b110, manchester_en=0, mod_format=0b001, dem_dcfilt_off=0 + /* 0x13: mdmcfg1 0x22 (----) */ { 2, 0, Cc1101::FOUR, 0 }, // chanspc_e=0b10, bit32=0, num_preamble=0b010, fec_en=0 + /* 0x14: mdmcfg0 0xf8 (----) */ { 0xf8 }, // chanspc_m = 0x08 + /* 0x15: deviatn 0x40 (0x47) */ { 0, 0, 4, 0 }, // deviation_m=0, (bit3=0), deviation_e=4, (bit7=0) + /* 0x16: mcsm2 0x07 (----) */ { 7, 0, 0, 0 }, // rx_time=7 (NA), rx_time_qual=0, rx_time_rssi=0, (bit76=0b00) + /* 0x17: mcsm1 0x30 (----) */ { Cc1101::TXOFF_IDLE, Cc1101::RXOFF_IDLE, Cc1101::RSSI_BELOW_THRESHOLD__UNLESS_RECEIVE_PACKET, 0 }, // mcsm1 (txoff_mode=0b00, rxoff_mode=0b00, cca_mode=0b11, (bit76=0b00) ) + /* 0x18: mcsm0 0x18 (----) */ { 0, 0, 2, Cc1101::IDLE_TO_RX_OR_TX, 0 }, // xosc_force_on=0, pin_ctrl_en=0, po_timeout=2 (149-155us), fs_autocal=0b01, (bit76=0b00) + /* 0x19: foccfg 0x16 (0x1d) */ 0x16, + /* 0x1a: bscfg 0x6c (0x1c) */ 0x6c, + /* 0x1b: agcctrl2 0x43 (0xc7) */ 0x43, + /* 0x1c: agcctrl1 0x49 (0x00) */ 0x49, + /* 0x1d: agcctrl0 0x91 (0xb2) */ 0x91, + /* 0x1e: worevt1 0x87 (----) */ 0x87, + /* 0x1f: worevt0 0x6b (----) */ 0x6b, + /* 0x20: worctrl 0xfb (0xf8) */ 0xfb, + /* 0x21: frend1 0x56 (0xb6) */ 0x56, + /* 0x22: frend0 0x10 (----) */ { 0, 0, 1, 0 }, // pa_power = 0, (bit3 = 0), lodiv_buf_current = 1, (bit76=0b00) + /* 0x23: fscal3 0xe9 (0xea) */ 0xe9, + /* 0x24: fscal2 0x2a (----) */ 0x2a, + /* 0x25: fscal1 0x00 (----) */ 0x00, + /* 0x26: fscal0 0x1f (0x11) */ 0x1f, + /* 0x27: rcctrl1 0x41 (----) */ 0x41, + /* 0x28: rcctrl0 0x00 (----) */ 0x00, + /* 0x29: fstest 0x59 (----) */ 0x59, + /* 0x2a: ptest 0x7f (----) */ 0x7f, + /* 0x2b: agctest 0x3f (----) */ 0x3f, + /* 0x2c: test2 0x81 (0x88) */ 0x81, + /* 0x2d: test1 0x35 (0x31) */ 0x35, + /* 0x2e: test0 0x09 (0x0b) */ 0x09 + }; + + // -------------------------------------------------------------------------------------- + + int8_t Cc1101::runSend (uint8_t subtest) { + if (subtest == 0) { + bool ok = true; + GDOx_CFG_t cfg0 = SYNC_SENT_OR_RECEIVED_UNTIL_END_OF_PACKET; + ok &= writeRegister(0x02, cfg0); + return ok; + } else if (subtest > 1) { + return -1; + } + + printf_P(PSTR(" use + and - for power change (other key -> back to default)")); + + uint16_t cnt = 0; + uint8_t paIndex = 0; + uint8_t pa_power; + int key = EOF; + do { + // if ((cnt & 0x0f) == 0) { + // paIndex = (cnt >> 4) & 0x07; + // union { FREND0_t value; uint8_t byte; } frend0 = { paIndex, 0, 1, 0 }; + // printf_P(PSTR("\n switch power ")); + // if (writeRegister(FREND0, frend0.byte )) { + // printf_P(PSTR("to %d (FREND0 = 0x%02X)"), frend0.value.pa_power, frend0.byte); + // } else { + // printf_P(PSTR("fails")); + // } + // } + if (key != EOF) { + uint8_t max = (sizeof(PMEM_CC1101_PATABLE_INIT) / sizeof(PMEM_CC1101_PATABLE_INIT[0])) - 1; + switch (key) { + case '+': if (paIndex == 0) paIndex = 1; else if (paIndex > 1) paIndex--; break; + case '-': if (paIndex == 0) paIndex = max; else if (paIndex < max) paIndex++; break; + default: paIndex = 0; break; // default value + } + + const PATABLE_INIT_ITEM_t *values = PMEM_CC1101_PATABLE_INIT; + + memcpy_P(&pa_power, &((values[paIndex]).pa_power), 1); + PGM_P info = (values[paIndex]).dbm; + printf_P(PSTR("\n switch power to ")); printf_P(info); + printf_P(PSTR("dBm ")); + if (writeRegister(0x3e, pa_power )) { + printf_P(PSTR("(PATABLE = 0x%02X)"), pa_power); + } else { + printf_P(PSTR("fails")); + } + } + + MainRadioControlState state = UNKNOWN; + uint8_t data[PACKET_LENGTH]; + printf_P(PSTR("\n [%04x]: state="), cnt++); + if (!readStatusRegister(MARCSTATE, (uint8_t *)&state)) { + printf_P(PSTR("E1")); + } else { + printf_P(PSTR("0x%02x"), state); + } + data[0] = pa_power; + printf_P(PSTR(" --> send %d bytes (HEX: %02X"), sizeof(data), paIndex); + for (uint8_t i = 1; i < sizeof(data); i++) { + data[i] = uint8_t((cnt + i - 1) & 0xff); + printf_P(PSTR(" %02X"), data[i]); + } + printf_P(PSTR("] -> ")); + + if (!sendData(data, sizeof(data))) { + flashRedLed(100); + printf_P(PSTR("E1")); + continue; + } + flashGreenLed(100); + key = waitAndReadKey(2000); + printf_P(PSTR("OK")); + + } while (key == EOF || (key != ESCAPE)); + + return 0; + } + + int8_t Cc1101::runReceive (uint8_t subtest) { + if (subtest == 0) { + bool ok = true; + GDOx_CFG_t cfg0 = SYNC_SENT_OR_RECEIVED_UNTIL_END_OF_PACKET; + ok &= writeRegister(0x02, cfg0); + return ok; + } else if (subtest > 1) { + return -1; + } + + int key = EOF; + uint16_t cnt = 0; + MainRadioControlState state; + while (key == EOF) { + printf_P(PSTR("\n [%04x] => start ... "), cnt++); + strobe(SRX); + do { + state = UNKNOWN; + if (!readStatusRegister(MARCSTATE, (uint8_t *)&state)) { + printf_P(PSTR("E1")); + _delay_ms(500); + break; + } + if (wait(0) != EOF) { + printf_P(PSTR("cancelled")); + _delay_ms(500); + break; + } + if (state == IDLE) { + printf_P(PSTR("? (IDLE)")); + _delay_ms(500); + break; + } + + } while (state != RX && state != RXFIFO_OVERFLOW); + + if (state != RX && state != RXFIFO_OVERFLOW) { + continue; + } + printf_P(PSTR("OK, receive ... ")); + + uint8_t length; + uint8_t lastLength = 0xff; + do { + uint8_t data[PACKET_LENGTH]; + if (!readStatusRegister(MARCSTATE, (uint8_t *)&state)) { + printf_P(PSTR("E2")); + _delay_ms(500); + continue; + } + if (wait(0) != EOF) { + printf_P(PSTR("cancelled")); + _delay_ms(500); + return -1; + } + if (!readStatusRegister(RXBYTES, (uint8_t *)&length)) { + printf_P(PSTR("E2")); + _delay_ms(500); + continue; + } + if (lastLength != length) { + lastLength = length; + } + if (length >= PACKET_LENGTH) { + if (receiveData(data, &length, sizeof(data))) { + if (length > 0) { + flashGreenLed(100); + printf_P(PSTR(" -> ")); + if (status.receivePacketStatusValid) { + printf_P(PSTR(" RSSI=%d, LQI=%d, CRC "), status.receivedPacketStatus.value.rssi, status.receivedPacketStatus.value.lqi); + if (status.receivedPacketStatus.value.crcOk) { + printf_P(PSTR("OK, ")); + } else { + printf_P(PSTR("ERROR, ")); + } + } + printf_P(PSTR("%d data bytes (HEX): "), length); + for (uint8_t i = 0; i < length; i++) { + printf_P(PSTR(" %02X"), data[i]); + } + printf_P(PSTR(" ... ")); + } + } + } + + } while (state == RX || state == RXFIFO_OVERFLOW); + + printf_P(PSTR("done (state=0x%02x)"), state); + } + return -1; + } + + int8_t Cc1101::runTest (uint8_t subtest) { + if (subtest > 0) { + return -1; + } + while (wait(0) == EOF) {} + return -1; + } + + + int8_t Cc1101::run (uint8_t subtest) { + switch (mode) { + case Send: return runSend(subtest); + case Receive: return runReceive(subtest); + case Test: return runTest(subtest); + default: return -1; + } + } + + uint8_t Cc1101::sendSpiByte (uint8_t b) { + SPDR = b; + while (!(SPSR & (1< "), addr, value); + if (ok && status.receivePacketStatusValid) { + printf_P(PSTR("status=0x%02x]"), status.spiResponse.byte); + } else { + printf_P(PSTR("ERR]")); + } + } + + return ok; + } + + bool Cc1101::writeRegisters (uint8_t addr, uint8_t *buffer, uint8_t length) { + bool ok = true; + uint8_t l = length; + uint8_t *p = buffer; + + addr = (addr & 0x3f) | 0x40; // write burst + setChipEnableLow(); + ok &= waitForMisoLow(); + sendSpiByte(addr); + while (length-- > 0) { + sendSpiByte(*buffer++); + } + setChipEnableHigh(); + + if (debugPrint.print.writeRegisters) { + printf_P(PSTR("\n [writeRegisters(0x%02x): "), addr & 0x3f); + while (l-- > 0) { + printf_P(PSTR(" 0x%02x"), *p++); + } + printf_P(PSTR(" -> ")); + if (ok && status.receivePacketStatusValid) { + printf_P(PSTR("status=0x%02x]"), status.spiResponse.byte); + } else { + printf_P(PSTR("ERR]")); + } + } + + return ok; + } + + + bool Cc1101::readRegister (uint8_t addr, uint8_t *value) { + bool ok = true; + addr = (addr & 0x3f) | 0x80; + setChipEnableLow(); + ok &= waitForMisoLow(); + status.spiResponse.byte = sendSpiByte(addr); + status.spiResponseValid = 1; + *value = sendSpiByte(0); + setChipEnableHigh(); + + if (debugPrint.print.readRegister) { + printf_P(PSTR("\n [readRegister(0x%02x) -> "), addr & 0x3f); + if (ok && status.spiResponseValid) { + printf_P(PSTR("0x%02x,status=0x%02x]"), *value, status.spiResponse.byte); + } else { + printf_P(PSTR("ERR]")); + } + } + return ok; + } + + bool Cc1101::readRegisters (uint8_t addr, uint8_t *buffer, uint8_t length) { + bool ok = true; + + uint8_t l = length; + uint8_t *p = buffer; + + addr |= 0xc0; // read burst + setChipEnableLow(); + ok &= waitForMisoLow(); + sendSpiByte(addr); + while (length-- > 0) { + *buffer++ = sendSpiByte(0); + } + setChipEnableHigh(); + + if (debugPrint.print.readRegisters) { + printf_P(PSTR("\n [readRegisters(0x%02x, ..., %d)] -> "), addr & 0x3f, l); + if (ok) { + while (l-- > 0) { + printf_P(PSTR(" 0x%02x"), *p++); + } + printf_P(PSTR("]")); + } else { + printf_P(PSTR("ERR]")); + } + } + + return ok; + } + + bool Cc1101::readStatusRegister (StatusAddress_t addr, uint8_t *value) { + if (addr < 0x30 || addr > 0x3d) { + return false; + } else { + return readRegisters(addr, value, 1); + } + } + + bool Cc1101::sendData (uint8_t *buffer, uint8_t length) { + timer = 10; + uint8_t ok = true; + uint8_t txbytes; + uint8_t states[16]; uint8_t statesIndex = 0; + // ok &= writeRegister(0x3f, length); + ok &= writeRegisters(0x3f, buffer, length); + ok &= readStatusRegister(TXBYTES, &txbytes); + ok &= (txbytes == 20); + if (ok) { + ok &= strobe(STX); // start sending bytes + // ok &= waitForGD0High(); // wait for start of SYNC + if (ok) { + uint8_t lastState = 0; + uint8_t state; + do { + ok &= readStatusRegister(MARCSTATE, &state); + if (state != lastState && statesIndex < 16) { + states[statesIndex++] = state; + } + lastState = state; + } while (ok && state != 0x13 && timer > 0); + ok &= state == 0x13; // check if in state TX + } + if (ok) { + uint8_t lastTxbytes = 20; + do { + ok &= readStatusRegister(TXBYTES, &txbytes); + if (lastTxbytes != txbytes) { + lastTxbytes = txbytes; + } + } while (ok && txbytes > 0 && timer > 0); + ok &= txbytes == 0; + } + } + if (!ok) { + strobe(SFTX); // flush TXfifo + } else { + uint8_t state; + uint8_t lastState = 0; + do { + ok &= readStatusRegister(MARCSTATE, &state); + if (lastState != state) { + lastState = state; + } + } while (ok && state != 0x01 && timer > 0); + ok &= state == 0x01; // check if in state IDLE + } + // ok &= waitForGD0Low(); // wait for end of package + + if (ok) { + printf_P(PSTR(" States[")); + for (uint8_t i = 0; i < statesIndex; i++) { + printf_P(PSTR(" 0x%02X"), states[i]); + } + printf_P(PSTR("] ")); + } + + return ok; + } + + bool Cc1101::receiveData (uint8_t *buffer, uint8_t *receivedLength, uint8_t maxBufferSize) { + bool ok = true; + STATUS_RXBYTES_t status; + uint8_t lastLength = 0; + uint8_t length = 0; + *receivedLength = 0; + timer = 50; + + this->status.receivePacketStatusValid = 0; + ok &= readStatusRegister(RXBYTES, &status.byte); + if (ok && status.rxbytes.num_rxbytes > 0) { + length = status.rxbytes.num_rxbytes; + + do { + _delay_us(400); // 20 Bytes in 4ms -> 200us/Byte -> CC1101 datasheet page 56: "twice that of which RF bytes are recived" + lastLength = length; + ok &= readStatusRegister(RXBYTES, &status.byte); + if (ok) { + // printf_P(PSTR(" [rxbytes=%d] "), status.byte); + length = status.byte & 0x7f; + } + ok &= timer > 0; + } while (ok && lastLength != length); + + if (ok) { + uint8_t extraBytesCount = this->status.receivePacketStatusEnabled ? 2 : 0; + if ((PACKET_LENGTH + extraBytesCount) != length) { + printf_P(PSTR(" ERROR[receive %d bytes, expect %d bytes] "), *receivedLength, PACKET_LENGTH + extraBytesCount); + *receivedLength = 0; + ok = false; + } else { + printf_P(PSTR(" OK[receive %d bytes] "), length); + *receivedLength = PACKET_LENGTH < maxBufferSize ? length - extraBytesCount : maxBufferSize; + ok &= readRegisters(0xff, buffer, *receivedLength); + if (!ok) { + *receivedLength = 0; + } else { + length -= *receivedLength; + if (length > extraBytesCount) { + printf_P(PSTR(" [WARN: buffer to small] ")); + while (length > extraBytesCount) { + uint8_t byte; + ok &= readRegister(0xff, &byte); + ok = false; + length--; + } + } + if (length > 0) { + ok &= readRegisters(0xff, this->status.receivedPacketStatus.byte, 2); + if (ok) { + this->status.receivePacketStatusValid = 1; + } + } + } + } + } + } + ok &= strobe(SFRX); + + return ok; + } + + + void Cc1101::printRegisters () { + const Register_t *regValues = &PMEM_CC1101_REGISTER_INIT; + printf_P(PSTR("\n")); + for (uint8_t addr = 0; addr < sizeof(Register_t); addr++) { + bool ok = true; + uint8_t regValue, value; + memcpy_P(®Value, ((const uint8_t *)regValues) + addr, 1); + ok &= readRegister(addr, &value); + if (value != regValue) { printf_P(PSTR(" != 0x%02x"), regValue); } + } + uint8_t data[8]; + for (uint8_t addr = 0x30; addr <= 0x3d; addr++) { + readStatusRegister((StatusAddress_t)addr, data); + } + readRegisters(0x3e, data, 8); // PATABLE + } + + bool Cc1101::resetCC1101 () { + bool ok = true; + setChipEnableLow(); + _delay_us(10); + setChipEnableHigh(); + _delay_us(50); + setChipEnableLow(); + ok &= waitForMisoLow(); + ok &= strobe(SRES); + ok &= waitForMisoLow(); + + + return ok; + } + + bool Cc1101::initRegister () { + const Register_t *regValues = &PMEM_CC1101_REGISTER_INIT; + bool ok = true; + // DebugPrint_t tmp = debugPrint.print; + // debugPrint.byte = 0xff; // print all + // printRegisters(); + + for (uint8_t addr = 0; ok && addr < sizeof(Register_t); addr++) { + uint8_t regValue; + memcpy_P(®Value, ((const uint8_t *)regValues) + addr, 1); + ok &= writeRegister(addr, regValue); + if ((addr == 0x07) && (regValue & 0x04)) { + status.receivePacketStatusEnabled = true; + } + } + + // debugPrint.print = tmp; + return ok; + } + + bool Cc1101::initPaTable () { + const PATABLE_INIT_ITEM_t *values = PMEM_CC1101_PATABLE_INIT; + uint8_t patable[8]; + uint8_t initValuesIndex = 0; + for (uint8_t i = 0; i < 8; i++) { + memcpy_P(&patable[i], &(values[initValuesIndex++].pa_power), 1); + if (initValuesIndex >= (sizeof(PMEM_CC1101_PATABLE_INIT) / sizeof(PATABLE_INIT_ITEM_t))) { + initValuesIndex = 0; + } + if (debugPrint.print.writePaTable) { + printf_P(PSTR("\nPTABLE %d: 0x%02x"), i, patable[i]); + } + } + return writeRegisters(0x3e, patable, 8); + } + +#endif + + diff --git a/software/test-software/src/units/cc1101.hpp b/software/test-software/src/units/cc1101.hpp new file mode 100644 index 0000000..a861f09 --- /dev/null +++ b/software/test-software/src/units/cc1101.hpp @@ -0,0 +1,281 @@ +#ifndef CC1101_HPP +#define CC1101_HPP + +#include +#include "../main.hpp" +#include + +class Cc1101 : public TestUnit { + public: + #define PACKET_LENGTH 20 + + public: + typedef enum { Test, Send, Receive } Cc1101Mode; + typedef enum { _IDLE = 0, _RX = 1, _TX = 2, _FSTXON = 3, _CALIBRATE = 4, _SETTLING = 5, _RXFIFO_OVFL = 6, _TXFIFO_UNFL = 7 } StatusState_t; + typedef struct { uint8_t fifoBytes:4; StatusState_t state:3; uint8_t chipNotReady:1; } Status_t; + typedef struct { int8_t rssi:8; uint8_t lqi:7; uint8_t crcOk:1; } ReceivedPacketStatus_t; // CC1101 datasheet page 37 + union { + struct { + union { + Status_t value; + uint8_t byte; + } spiResponse; + union { + ReceivedPacketStatus_t value; + uint8_t byte [2]; + } receivedPacketStatus; + uint8_t spiResponseValid: 1; + uint8_t receivePacketStatusEnabled:1; + uint8_t receivePacketStatusValid:1; + }; + uint32_t dword; + } status; + + public: + Cc1101 (Cc1101Mode mode) { timer = 0; this->mode = mode; status.dword = 0; } + virtual void init (); + virtual void cleanup (); + virtual int8_t run (uint8_t subtest); + virtual PGM_P getName (); + + public: + void tick1ms () { if (timer > 0) timer--; }; + + private: + typedef enum { SRES = 0x30, SCAL = 0x33, SRX = 0x34, STX = 0x35, SFRX = 0x3a, SFTX = 0x3b, SIDLE = 0x36 } StrobeCommand_t; + typedef enum { MARCSTATE = 0x35, TXBYTES = 0x3A, RXBYTES = 0x3B } StatusAddress_t; + typedef struct { uint8_t writeRegister:1; uint8_t writeRegisters:1; uint8_t readRegister:1; uint8_t readRegisters:1; uint8_t writePaTable:1; } DebugPrint_t; + + private: + int8_t runSend (uint8_t subtest); + int8_t runReceive (uint8_t subtest); + int8_t runTest (uint8_t subtest); + uint8_t sendSpiByte (uint8_t b); + void triggerOn(); + void triggerOff(); + void triggerToggle (); + void setChipEnableLow (); + void setChipEnableHigh (); + bool isMisoHigh (); + bool isGd0High (); + bool waitForMisoLow (); + bool waitForGD0High (); + bool waitForGD0Low (); + bool strobe (StrobeCommand_t strobe); + bool writeRegister (uint8_t addr, uint8_t value); + bool writeRegisters (uint8_t addr, uint8_t *buffer, uint8_t length); + bool readRegister (uint8_t addr, uint8_t *value); + bool readRegisters (uint8_t addr, uint8_t *buffer, uint8_t length); + bool readStatusRegister (StatusAddress_t addr, uint8_t *value); + bool sendData (uint8_t *buffer, uint8_t length); + bool receiveData (uint8_t *buffer, uint8_t *receivedLength, uint8_t maxBufferSize); + void printRegisters (); + + bool resetCC1101 (); + bool initRegister (); + bool initPaTable (); + + + private: + Cc1101Mode mode; + uint8_t timer; + union { + DebugPrint_t print; + uint8_t byte; + } debugPrint; + + + public: + typedef enum { + IOCFG2 = 0x00, IOCFG1 = 0x01, IOCFG0 = 0x02, + FIFOTHR = 0x03, + SYNC1 = 0x04, SYNC0 = 0x05, + PKTLEN = 0x06, + PKTCTRL1 = 0x07, PKTCTRL0 = 0x08, + ADDR = 0x00, CHANNR = 0x0a, + FSCTRL1 = 0x0b, FSCTRL0 = 0x0c, + FREQU2 = 0x0d, FREQU1 = 0x0e, FREQU0 = 0x0f, + MDMCFG4 = 0x10, MDMCFG3 = 0x11, MDMCFG2 = 0x12, MDMCFG1 = 0x13, MDMCFG0 = 0x14, + DEVIATN = 0x15, + MCSM2 = 0x16, MCSM1 = 0x17, MCSM0 = 0x18, + FOCCFG = 0x19, BSCFG = 0x1a, + AGCCTRL2 = 0x1b, AGCCTRL1 = 0x1c, AGCCTRL0 = 0x1d, + WOREVT1 = 0x1e, WOREVT0 = 0x1f, WORCTRL = 0x20, + FREND1 = 0x21, FREND0 = 0x22, + FSCAL3 = 0x23, FSCAL2 = 0x24, FSCAL1 = 0x25, FSCAL0 = 0x26, + RCCTRL1 = 0x27, RCCTRL0 = 0x28, + FSTEST = 0x29, PTEST = 0x2a, AGCTEST = 0x2b, + TEST2 = 0x2c, TEST1 = 0x2d, TEST0 = 0x2e + } RegisterAddress_t; + + typedef enum { + RX_FIFO_FILLED_OR_ABOVE_THRESHHOLD = 0x00, + RX_FIFO_FILLED_OR_ABOVE_THRESHHOLD_OR_END_OF_PACKAGE_UNTIL_FIFO_EMPTY = 0x01, + TX_FIFO_FILLED_OR_ABOVE_THRESHHOLD = 0x02, + TX_FIFO_FULL_UNTIL_BELOW_THRESHHOLD = 0x03, + RX_FIFO_OVERFLOW_UNTIL_FIFO_FLUSHED = 0x04, + TX_FIFO_UNDERFLOW_UNTIL_FIFO_FLUSHED = 0x05, + SYNC_SENT_OR_RECEIVED_UNTIL_END_OF_PACKET = 0x06, + PACKET_RECEIVED_WITH_CRC_OK_UNTIL_FIRST_BYTE_READ_FROM_RXFIFO = 0x07, + PREAMBLE_QUALITY_REACHED_UNTIL_REENTER_RX = 0x08, + RSSI_LEVEL_BELOW_THRESHOLD = 0x09, + LOCK_DETECTOR_OUTPUT = 0x0a, + SERIAL_CLOCK = 0x0b, + SERIAL_SYNCHRONOUS_DATA_OUTPUT = 0x0c, + SERIAL_ASYNC_DATA_OUTPUT = 0x0d, + CARRIER_DETECTED_UNTIL_ENTER_IDLE = 0x0e, + CRC_OK_UNTIL_REENTER_RX = 0x0f, + RX_HARD_DATA_1 = 0x16, + RX_HARD_DATA_0 = 0x17, + PA_PD = 0x1b, + LNA_PD = 0x1c, + RX_SYMBOL_TICK = 0x1d, + WAKEUP_ON_RECEIVE_EVENT0 = 0x24, + WAKEUP_ON_RECEIVE_EVENT1 = 0x25, + CLK_256 = 0x26, + CLK_32K = 0x27, + CHIP_NOT_READY = 0x29, + XOSC_STABLE = 0x2b, + HIGH_IMPEDANCE_WHEN_CHIP_SELECT_HIGH = 0x2e, + HW_TO_0 = 0x2f, + CLK_XOSC = 0x30, + CLK_XOSC_DIV_1P5 = 0x31, + CLK_XOSC_DIV_2 = 0x32, + CLK_XOSC_DIV_3 = 0x33, + CLK_XOSC_DIV_4 = 0x34, + CLK_XOSC_DIV_6 = 0x35, + CLK_XOSC_DIV_8 = 0x36, + CLK_XOSC_DIV_12 = 0x37, + CLK_XOSC_DIV_16 = 0x38, + CLK_XOSC_DIV_24 = 0x39, + CLK_XOSC_DIV_32 = 0x3a, + CLK_XOSC_DIV_48 = 0x3b, + CLK_XOSC_DIV_64 = 0x3c, + CLK_XOSC_DIV_96 = 0x3d, + CLK_XOSC_DIV_128 = 0x3e, + CLK_XOSC_DIV_192 = 0x3f + } GDOx_CFG_t; + + typedef enum { + SLEEP = 0, + IDLE = 1, + XOFF = 2, + MANCAL_VCOON = 3, + MANCAL_REGON = 4, + MANCAL = 5, + FS_WAKEUP_VCOON = 6, + FS_WAKEUP_REGON = 7, + CALIBRATE_START = 8, + SETTLING_BWBOOST = 9, + SETTLING_FS_LOCK = 10, + SETTLIN_IFADCON = 11, + CALIBRATE_END = 12, + RX = 13, + RX_END = 14, + RX_RST = 15, + TXRX_SETTLING = 16, + RXFIFO_OVERFLOW = 17, + FXTXON = 18, + TX = 19, + TX_END = 20, + RXTX_SETTLING = 21, + TXFIFO_UNDERFLOW = 22, + UNKNOWN = 255 + } MainRadioControlState; + + typedef struct { uint8_t pa_power; const char dbm[4]; } PATABLE_INIT_ITEM_t; + + typedef enum { NO_ADDR_CHECK = 0, CHECK_NO_BROADCAST = 1, CHECK_WITH_BROADCAST_0 = 2, CHECK_WITH_BROADCAST_0_AND_255 = 3 } ADR_CHK_t; + typedef enum { FIXED = 0, VARIABLE = 1, INFINITE = 2 } LENGTH_CONFIG_t; + typedef enum { NORMAL_USE_FIFO = 0, SYNC_SERIAL = 1, RANDOM_TX = 2, ASYNC_SERIAL = 3 } PKT_FORMAT_t; + typedef enum { FSK2 = 0, GFSK = 1, ASK_OOK = 3, FSK4 = 4, MSK = 7 } MOD_FORMAT_t; + typedef enum { NO_SYNC = 0, SYNC_15_16 = 1, SYNC_16_16 = 2, SYNC_30_32 = 3, CARRIER_SENSE = 4, SYNC_15_16_CARRIER_SENSE = 5, SYNC_16_16_CARRIER_SENSE = 6 , SYNC_30_326_CARRIER_SENSE = 7} SYNC_MODE_t; + typedef enum { TWO = 0, THREE = 1, FOUR = 2, SIX = 3, EIGHT = 4, TWELVE = 5, SIXTEEN = 6, TWENTYFOUR = 7 } NUM_PREAMBLE_t; + typedef enum { TXOFF_IDLE = 0, TXOFF_FSTXON = 1, STAY_IN_TX = 2, TXOFF_RX = 3 } TXOFF_MODE_t; + typedef enum { RXOFF_IDLE = 0, RXOFF_FSTXON = 1, RXOFF_TX = 2, STAY_IN_RX = 3 } RXOFF_MODE_t; + typedef enum { ALWAYS = 0, RSSI_BELOW_THRESHOLD = 1, UNLESS_RECEIVE_PACKET = 2, RSSI_BELOW_THRESHOLD__UNLESS_RECEIVE_PACKET = 3 } CCA_MODE_t; + typedef enum { NEVER = 0, IDLE_TO_RX_OR_TX = 1, RX_OR_TX_TO_IDLE = 2, RX_OR_TX_TO_IDLE_EVERY_4_TIME = 3 } FS_AUTOCAL_t; + + typedef struct { GDOx_CFG_t gdo0_cfg:6; uint8_t gdo0_inv:1; uint8_t bit7:1; } IOCFG0_t; + typedef struct { GDOx_CFG_t gdo1_cfg:6; uint8_t gdo1_inv:1; uint8_t bit7:1; } IOCFG1_t; + typedef struct { GDOx_CFG_t gdo2_cfg:6; uint8_t gdo2_inv:1; uint8_t bit7:1; } IOCFG2_t; + typedef struct { uint8_t fifo_thr:4; uint8_t close_in_rx:2; uint8_t adc_retention:1; uint8_t bit7:1; } FIFOTHR_t; + typedef struct { ADR_CHK_t adr_chk:2; uint8_t append_status:1; uint8_t crc_autoflush:1; uint8_t bit4:1; uint8_t pqt:3; } PKTCTRL1_t; + typedef struct { LENGTH_CONFIG_t length_config:2; uint8_t crc_en:1; uint8_t bit3:1; PKT_FORMAT_t pkt_format:2; uint8_t white_data:1; uint8_t bit7:1; } PKTCTRL0_t; + typedef struct { uint8_t frequ_if:5; uint8_t bit5:1; uint8_t bit76:2; } FSCTRL1_t; + typedef struct { uint8_t frequoff:8; } FSCTRL0_t; + typedef struct { uint8_t drate_e:4; uint8_t chanbw_m:2; uint8_t chanbw_e:2; } MDMCFG4_t; + typedef struct { uint8_t drate_m:8; } MDMCFG3_t; + typedef struct { SYNC_MODE_t sync_mode:3; uint8_t manchester_en:1; MOD_FORMAT_t mod_format:3; uint8_t dem_dcfilt_off:1; } MDMCFG2_t; + typedef struct { uint8_t chanspc_e:2; uint8_t bit32:2; NUM_PREAMBLE_t num_preamble:3; uint8_t fec_en:1; } MDMCFG1_t; + typedef struct { uint8_t chanspc_m:8; } MDMCFG0_t; + typedef struct { uint8_t deviation_m:3; uint8_t bit3:1; uint8_t deviation_e:3; uint8_t bit7:1; } DEVIATN_t; + typedef struct { uint8_t rx_time:3; uint8_t rx_time_qual:1; uint8_t rx_time_rssi:1; uint8_t bit765:3; } MCSM2_t; + typedef struct { TXOFF_MODE_t txoff_mode:2; RXOFF_MODE_t rxoff_mode:2; CCA_MODE_t cca_mode:2; uint8_t bit76:2; } MCSM1_t; + typedef struct { uint8_t xosc_force_on:1; uint8_t pin_ctrl_en:1; uint8_t po_timeout:2; FS_AUTOCAL_t fs_autocal:2; uint8_t bit76:2; } MCSM0_t; + typedef struct { uint8_t pa_power:3; uint8_t bit3:1; uint8_t lodiv_buf_current:2; uint8_t bit76:2; } FREND0_t; + + typedef union { + uint8_t byte; + struct { + uint8_t num_rxbytes:7; + uint8_t rxfifo_overflow:1; + } rxbytes; + } STATUS_RXBYTES_t; + + typedef struct { + IOCFG2_t iocfg2; + IOCFG1_t iocfg1; + IOCFG0_t iocfg0; + FIFOTHR_t fifothr; + uint8_t sync1; + uint8_t sync0; + uint8_t pktlen; + PKTCTRL1_t pktctrl1; + PKTCTRL0_t pktctrl0; + uint8_t addr; + uint8_t channr; + FSCTRL1_t fsctrl1; + FSCTRL0_t fsctrl0; + uint8_t frequ2; + uint8_t frequ1; + uint8_t frequ0; + MDMCFG4_t mdmcfg4; + MDMCFG3_t mdmcfg3; + MDMCFG2_t mdmcfg2; + MDMCFG1_t mdmcfg1; + MDMCFG0_t mdmcfg0; + DEVIATN_t deviatn; + MCSM2_t mcsm2; + MCSM1_t mcsm1; + MCSM0_t mcsm0; + uint8_t foccfg; + uint8_t bscfg; + uint8_t agcctrl2; + uint8_t agcctrl1; + uint8_t agcctrl0; + uint8_t worevt1; + uint8_t worevt0; + uint8_t worctrl; + uint8_t frend1; + FREND0_t frend0; + uint8_t fscal3; + uint8_t fscal2; + uint8_t fscal1; + uint8_t fscal0; + uint8_t rcctrl1; + uint8_t rcctrl0; + uint8_t fstest; + uint8_t ptest; + uint8_t agctest; + uint8_t test2; + uint8_t test1; + uint8_t test0; + + } Register_t; + + + +}; + +#endif \ No newline at end of file diff --git a/software/test-software/src/units/encoder.cpp b/software/test-software/src/units/encoder.cpp new file mode 100644 index 0000000..7b33b76 --- /dev/null +++ b/software/test-software/src/units/encoder.cpp @@ -0,0 +1,138 @@ +#include +#include + +#include "encoder.hpp" +#include "../main.hpp" + +// Encoder signals on rotation clockwise 1 step: +// A -----____------ one char app. 1ms..2ms (rotation speed) +// B -------___----- +// one step when: A = 0, B= 1->0 + +// Encoder signals on rotation counterclockwise 1 step: +// A -----____------ one char app. 1ms..2ms (rotation speed) +// B --______----- +// one step when: A = 0, B= 0->1 + +#if defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__) + + // Nano-644 + // --------------------------------------------------------------- + // PB0/T0 ... Encoder A + // PB1/T1 ... Encoder B + // PB2/INT2 ... push switch of encoder (pushed = 0) + + void Encoder::init () { + DDRB &= ~((1 << PB2) | (1 << PB1) | (1 << PB0)); + PORTB |= (1 << PORTB2) | (1 << PORTB1) | (1 << PORTB0); // enable pullup + enabled = 1; + } + + void Encoder::cleanup () { + enabled = 0; + DDRB &= ~((1 << PB2) | (1 << PB1) | (1 << PB0)); + PORTB &= ~((1 << PORTB2) | (1 << PORTB1) | (1 << PORTB0)); + } + + bool Encoder::isPressed () { + return (PINB & (1 << PB2)) == 0; + } + + bool Encoder::getA () { + return (PINB & (1 << PB0)) == 0; + } + + bool Encoder::getB () { + return (PINB & (1 << PB1)) == 0; + } + + +#endif + +#ifdef __AVR_ATmega328P__ + + // Arduino-Nano-5V + // --------------------------------------------------------------- + // PD4/T0 ... Encoder A + // PB0 ... Encoder B + // PD7 ... push switch of encoder (pushed = 0) + + void Encoder::init () { + DDRB &= ~(1 << PB0); + DDRD &= ~((1 << PD7) | (1 << PD4)); + PORTB |= (1 << PB0); // enable pullup + PORTD |= (1 << PD7) | (1 << PD4); // enable pullup + enabled = 1; + } + + void Encoder::cleanup () { + enabled = 0; + PORTB &= ~(1 << PB0); + PORTD &= ~((1 << PD7) | (1 << PD4)); + DDRB &= ~(1 << PB0); + DDRD &= ~((1 << PD7) | (1 << PD4)); + } + + bool Encoder::isPressed () { + return (PIND & (1 << PD7)) == 0; + } + + bool Encoder::getA () { + return (PIND & (1 << PD4)) == 0; + } + + bool Encoder::getB () { + return (PINB & (1 << PB0)) == 0; + } + +#endif + + +int8_t Encoder::run (uint8_t subtest) { + switch (subtest) { + case 0: { + while (wait(10) == EOF) { + printf_P(PSTR("\r => Encoder (push to clear): ")); + printf_P(PSTR("%5d (0x%02x) "), count, (uint8_t)count); + if (isPressed()) { + reset(); + } + } + return 0; + } + } + + return -1; +} + +struct EncoderState { + int8_t a:1; // signal A + int8_t b:1; // signal B +}; + +void Encoder::tick100us () { + static EncoderState lastState = { 1, 1 }; + static EncoderState lastStableState = { 1, 1 }; + + if (!enabled) { + count = 0; + return; + } + EncoderState nextState; + nextState.a = getA() ? 1 : 0; + nextState.b = getB() ? 1 : 0; + if (nextState.a == lastState.a && nextState.b == lastState.b) { + if (lastStableState.a == 0 && nextState.b != lastStableState.b) { + if (nextState.b == 0) { + count = count < 127 ? count + 1 : 127; + } else { + count = count > -128 ? count - 1 : -128; + } + } + lastStableState.a = nextState.a; + lastStableState.b = nextState.b; + } + lastState.a = nextState.a; + lastState.b = nextState.b; +} + diff --git a/software/test-software/src/units/encoder.hpp b/software/test-software/src/units/encoder.hpp new file mode 100644 index 0000000..9b0861b --- /dev/null +++ b/software/test-software/src/units/encoder.hpp @@ -0,0 +1,28 @@ +#ifndef ENCODER_HPP +#define ENCODER_PP + +#include +#include "../main.hpp" +#include + +class Encoder : public TestUnit { + public: + uint8_t enabled; + int8_t count; + + public: + Encoder () { reset(); enabled = 0; }; + virtual void init (); + virtual void cleanup (); + virtual int8_t run (uint8_t subtest); + virtual PGM_P getName () { return PSTR("Encoder"); } + void reset () { count = 0; } + void tick100us (); + bool isPressed (); + + private: + bool getA (); + bool getB (); +}; + +#endif \ No newline at end of file diff --git a/software/test-software/src/units/i2c.cpp b/software/test-software/src/units/i2c.cpp new file mode 100644 index 0000000..60dd22d --- /dev/null +++ b/software/test-software/src/units/i2c.cpp @@ -0,0 +1,216 @@ +#include +#include +#include +#include +#include + +#include "i2c.hpp" +#include "../adafruit/bme280.h" +#include "../main.hpp" + +// Sparkfun https://www.sparkfun.com/products/22858 +// ENS160 address 0x53 (air quality sensor) +// BME280 address 0x77 /humidity/temperature sensor) +// register 0xfe: humidity_7:0 +// register 0xfd: humidity_15:8 + +PGM_P I2c::getName () { + switch (mode) { + case SparkFunEnvCombo: return PSTR("I2C-Sparkfun Env-Combo"); + case Master: return PSTR("I2C-Master"); + case Slave: return PSTR("I2C-Slave"); + } + return "?"; +} + +void I2c::init () { + TWBR = 13; // 100kHz (TWPS1:0 = 00), TWBR = (F_CPU - 16 * 100000) / (2 * 100000 * 4); + TWBR = 28; // 50kHz (TWPS1:0 = 00), TWBR = (F_CPU - 16 * 50000) / (2 * 50000 * 4); + TWBR = 100; // 50kHz (TWPS1:0 = 00), TWBR = (F_CPU - 16 * 50000) / (2 * 50000 * 4); + TWCR = (1 << TWEN); + ADMUX = (1 << ADLAR) | (1 << REFS0); // ADC0, VREF=AVCC=3.3V + ADCSRA = (1 << ADEN) | 7; // ADC Enable, Prescaler 128 + enabled = true; +} + +void I2c::cleanup () { + enabled = false; + TWCR = (1 << TWEN); + TWBR = 0; + ADMUX = 0; + ADCSRA = 0; +} + +int8_t I2c::run (uint8_t subtest) { + if (subtest == 0 && mode == I2c::SparkFunEnvCombo) { + printf_P(PSTR(" BM280 ... ")); + if (!bm280.begin()) { + printf_P(PSTR("E1")); + return -1; + } + printf_P(PSTR("OK, ENS160 ... ")); + if (!ens160.begin()) { + printf_P(PSTR("E2")); + return -1; + } + if (!ens160.setMode(ENS160_OPMODE_STD)) { + printf_P(PSTR("E3")); + return -1; + } + if (!ens160.set_envdata(25.0, 65)) { + printf_P(PSTR("E4")); + return -1; + } + + printf_P(PSTR("OK")); + float accTemp = 0, accHumidity = 0; + int8_t accCount = -1; + + do { + // BME280 + float p = bm280.readPressure(); + printf_P(PSTR("\n => BM280: P= %.3fbar"), (double)p / 100000.0); + float t = bm280.readTemperature(); + printf_P(PSTR(", T= %.2f°C"), (double)t); + float h = bm280.readHumidity(); + printf_P(PSTR(", H= %.2f%%"), (double)h); + + if (accCount >= 0 && !isnanf(h) && !isnan(t)) { + accTemp += t; + accHumidity += h; + accCount++; + } + + bm280.setSampling( + Adafruit_BME280::MODE_NORMAL, + Adafruit_BME280::SAMPLING_X16, + Adafruit_BME280::SAMPLING_X16, + Adafruit_BME280::SAMPLING_X16, + Adafruit_BME280::FILTER_OFF, + Adafruit_BME280::STANDBY_MS_1000 + ); + + // ENS160 only activated every 32s to avoid wrong temperature measuerment + // if ES160 would be continously active, the temperature would be 4°C higher + // -> ES160 has not enough distance to BM280 + // This solution causes only a +0.3°C higher temperatur value + if (accCount < 0 || accCount >= 32) { + printf_P(PSTR(" | ENS160 (")); + if (accCount > 0) { + h = accHumidity / accCount; + t = accTemp / accCount; + accTemp = 0; + accHumidity = 0; + } + accCount = 0; + if (!ens160.set_envdata(t, h)) { + printf_P(PSTR("E1)")); + } else { + printf_P(PSTR("%.1f°C/%.1f%%): "), (double)t, (double)h); + if (!ens160.setMode(ENS160_OPMODE_STD)) { + printf_P(PSTR("E2")); + } else { + for (uint8_t i = 0; i < 100; i++) { + _delay_ms(15); + uint8_t status; + if (ens160.readStatus(&status)) { + if (status & ENS160_DATA_STATUS_NEWDAT) { + ENS160_DATA data; + if (ens160.readData(&data)) { + printf_P(PSTR(" aqi=%d("), data.aqi); + switch(data.aqi) { + case 1: printf_P(PSTR("excellent")); break; + case 2: printf_P(PSTR("good")); break; + case 3: printf_P(PSTR("moderate")); break; + case 4: printf_P(PSTR("poor")); break; + case 5: printf_P(PSTR("unhealthy")); break; + default: printf_P(PSTR("?")); break; + } + printf_P(PSTR("), tvoc=%dppb"), data.tvoc); + printf_P(PSTR(", eco2=%d("), data.eco2); + if (data.eco2 < 400) { + printf_P(PSTR("?")); + } else if (data.eco2 < 600) { + printf_P(PSTR("excellent")); + } else if (data.eco2 < 800) { + printf_P(PSTR("good")); + } else if (data.eco2 < 1000) { + printf_P(PSTR("fair")); + } else if (data.eco2 < 1500) { + printf_P(PSTR("poor")); + } else { + printf_P(PSTR("bad")); + } + printf_P(PSTR(")")); + } + break; + } + } + } + } + if (!ens160.setMode(ENS160_OPMODE_IDLE)) { + printf_P(PSTR("E3")); + } + } + } + + } while (wait(1000) == EOF); + + } else if (subtest == 0 && mode == I2c::Master) { + if (!master.begin(0x01)) { + printf_P(PSTR("E1")); + return -1; + } + do { + uint8_t buffer[1]; + // read poti + ADCSRA |= (1 << ADSC); // start ADC + while (ADCSRA & (1 << ADSC)) {} // wait for result + buffer[0] = ADCH; + printf_P(PSTR("\n I2C-MASTER: to slave: 0x%02x"), buffer[0]); + if (!master.write(buffer, 1)) { + printf_P(PSTR(" -> ERROR")); + } + printf_P(PSTR(", from slave: ")); + if (master.read(buffer, 1)) { + printf_P(PSTR("0x%02x"), buffer[0]); + } else { + printf_P(PSTR(" -> ERROR")); + } + } while (wait(1000) == EOF); + master.end(); + + } else if (subtest == 0 && mode == I2c::Slave) { + if (!slave.begin(0x01, false)) { + printf_P(PSTR("E1")); + return -1; + } + do { + int fromMaster = slave.read(); + if (fromMaster != EOF) { + ADCSRA |= (1 << ADSC); // start ADC + while (ADCSRA & (1 << ADSC)) {} // wait for result + slave.write(ADCH); + printf_P(PSTR("\n I2C SLAVE: from master: 0x%02x -> to master: 0x%02x"), fromMaster, ADCH); + } + } while (wait(0) == EOF); + slave.end(); + + } else { + printf_P(PSTR("end")); + return -1; + } + wait(500); + return 0; +} + +void I2c::handleTwiIrq () { + if (mode == I2c::Slave) { + DDRD |= (1 << PD7); + PORTD |= (1 << PD7); + slave.handleTWIIsr(); + PORTD &= ~(1 << PD7); + } else { + TWCR |= (1 << TWINT); // clear Interrupt Request + } +} diff --git a/software/test-software/src/units/i2c.hpp b/software/test-software/src/units/i2c.hpp new file mode 100644 index 0000000..2148cc0 --- /dev/null +++ b/software/test-software/src/units/i2c.hpp @@ -0,0 +1,43 @@ +#ifndef I2C_HPP +#define I2C_HPP + +#include +#include "../main.hpp" +#include "../adafruit/bme280.h" +#include "../adafruit/ens160.h" +#include "../i2cmaster.hpp" +#include "../i2cslave.hpp" + + +class I2c : public TestUnit { + public: + typedef enum I2cMode { SparkFunEnvCombo, Master, Slave } I2cMode; + + private: + I2cMode mode; + Adafruit_BME280 bm280; + ScioSense_ENS160 ens160; + I2cMaster master; + I2cSlave slave; + + public: + bool enabled; + + public: + I2c (I2cMode mode) { enabled = false; this->mode = mode; } + void tick1ms () { master.tick1ms(); slave.tick1ms(); } + virtual void init (); + virtual void cleanup (); + virtual int8_t run (uint8_t subtest); + virtual PGM_P getName (); + void handleTwiIrq (); + // uint16_t startRead (uint8_t address); + // uint16_t startWrite (uint8_t address); + // void stop (); + // uint16_t writeByte (uint8_t data); + // uint16_t writeData (uint8_t size, const uint8_t *data); + // uint16_t readData (uint8_t size, uint8_t *data); + // int32_t compensateBm280T (int32_t adcT); +}; + +#endif \ No newline at end of file diff --git a/software/test-software/src/units/ieee485.cpp b/software/test-software/src/units/ieee485.cpp new file mode 100644 index 0000000..8fcb67a --- /dev/null +++ b/software/test-software/src/units/ieee485.cpp @@ -0,0 +1,111 @@ +#include +#include +#include +#include + +#include "ieee485.hpp" +#include "../main.hpp" + +#ifdef __AVR_ATmega328P__ + +// Nano-328P +// ------------------------------------ +// IEE485 not supported (no UART1) + +void Ieee485::init () {} +void Ieee485::cleanup () {} +int8_t Ieee485::run (uint8_t subtest) { + return -1; +} + +#endif + + +#if defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__) + +// Nano-644 +// ------------------------------------ +// PB0 ... nRE .. Read enable +// PB1 ... DE .. Data enable + +#define SET_nRE (PORTB |= (1 << PB0)) +#define CLR_nRE (PORTB &= ~(1 << PB0)) +#define SET_DE (PORTB |= (1 << PB1)) +#define CLR_DE (PORTB &= ~(1 << PB1)) + +void Ieee485::init () { + // Poti + ADMUX = (1 << ADLAR) | (1 << REFS0); // ADC0, VREF=AVCC=3.3V + ADCSRA = (1 << ADEN) | 7; // ADC Enable, Prescaler 128 + + // Modbus + SET_nRE; + CLR_DE; + DDRB |= (1 << PB1) | (1 << PB0); + + // UART1 interface on Nano-644 + PORTD |= (1 << PD2); // enable RxD1 pullup + UCSR1A = (1 << U2X1); + UCSR1B = (1 << RXCIE1) | (1 << RXEN1) | (1 < send Byte 0x%02x"), ADCH); + int b; + ATOMIC_BLOCK(ATOMIC_FORCEON) { + b = receivedByte; + receivedByte = -1; + } + if (b >= 0) { + printf_P(PSTR("\n => receive Byte: 0x%02x"), b); + } + } + + } else { + printf_P(PSTR("end")); + return -1; + } + + return 0; +} + +void Ieee485::handleRxByte (uint8_t b) { + receivedByte = b; +} + +#endif \ No newline at end of file diff --git a/software/test-software/src/units/ieee485.hpp b/software/test-software/src/units/ieee485.hpp new file mode 100644 index 0000000..ffbb15c --- /dev/null +++ b/software/test-software/src/units/ieee485.hpp @@ -0,0 +1,22 @@ +#ifndef IEEE485_HPP +#define IEEE485_HPP + +#include +#include "../main.hpp" +#include + +class Ieee485 : public TestUnit { + public: + uint8_t enabled; + int16_t receivedByte; + + public: + Ieee485 () { enabled = 0; receivedByte = -1; } + virtual void init (); + virtual void cleanup (); + virtual int8_t run (uint8_t subtest); + virtual const char *getName () { return PSTR("IEEE485"); } + void handleRxByte (uint8_t); +}; + +#endif \ No newline at end of file diff --git a/software/test-software/src/units/lcd.cpp b/software/test-software/src/units/lcd.cpp new file mode 100644 index 0000000..e779c16 --- /dev/null +++ b/software/test-software/src/units/lcd.cpp @@ -0,0 +1,443 @@ +#include +#include +#include + +#include "lcd.hpp" +#include "../main.hpp" + +#if defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__) + + // Nano-644 / Nano-1284 + // --------------------------------------------------------------- + + // Nano-X-Base V1a V2a Beschreibung + // --------------------------------- ------- + // BL ........... PC0 PC0 Backlight ON(=1) / OFF(=0) + // E ........... PA3 PA3 LCD Enable (Verbindung via J25 erforderlich) + // R/W .......... PD6 PD6 Read/Write: Read=1, Write=0 + // RS ........... PD7 PD7 Register Select: Command=0, Data=1 + // Data ......... PB7:0 PB7:0 Achtung von 5V LCD nicht lesen! + + void Lcd::init () { + DDRA |= (1 << PA3) | (1 << PA0); + DDRB = 0xff; + DDRD |= (1 << PD7) | (1 << PD6); + initLcd(); + printf_P(PSTR("init LCD (")); + if (status == 1) { + printf_P(PSTR("OK)")); + } else { + printf_P(PSTR("ERROR %d)"), status); + } + setBacklightOn(); + } + + void Lcd::cleanup () { + clear(); + PORTA &= ~((1 << PA3) | (1 << PA0)); + DDRA &= ~((1 << PA3) | (1 << PA0)); + PORTB = 0; + DDRB = 0; + PORTD &= ~((1 << PD7) | (1 << PD6)); + DDRD &= ~((1 << PD7) | (1 << PD6)); + } + + void Lcd::setRS () { PORTD |= (1 << PD7); } + void Lcd::clrRS () { PORTD &= ~(1 << PD7); } + void Lcd::setRW () { PORTD |= (1 << PD6); } + void Lcd::clrRW () { PORTD &= ~(1 << PD6); } + void Lcd::setE () { PORTA |= (1 << PA3); } + void Lcd::clrE () { PORTA &= ~(1 << PA3); } + void Lcd::dataDirectionOut () { DDRB = 0xff; } + + void Lcd::dataDirectionIn () { + if (hardwareVersion == 1) { + // read back not allowed (missing level shifter 5V -> 3.3V) + DDRB = 0xff; + } else { + DDRB = 0x00; + } + } + + uint8_t Lcd::getData () { + if (hardwareVersion == 1) { + // read back not allowed (missing level shifter 5V -> 3.3V) + _delay_ms(1); + return 0x00; // bit 8 (busy) = 0 + } else { + return PINB; + } + } + + void Lcd::setData (uint8_t data) { + PORTB = data; + } + + void Lcd::setBacklightOn () { + PORTA |= (1 << PA0); + } + + void Lcd::setBacklightOff () { + PORTA &= ~(1 << PA0); + } + +#endif + +#ifdef __AVR_ATmega328P__ + + // Arduino Nano (5V) + // --------------------------------------------------------------- + + // Nano-X-Base V1a V2a Beschreibung + // --------------------------------- ------- + // BL ........... PC0 PC0 Backlight ON(=1) / OFF(=0) + // E ........... PC3 PC3 LCD Enable (Verbindung via J25 erforderlich) + // R/W .......... PD3 PD3 Read/Write: Read=1, Write=0 + // RS ........... PD2 PD2 Register Select: Command=0, Data=1 + // Data0 ........ PD4 PD4 + // Data1 .........PB0 PB0 + // Data2 .........PD7 PD7 + // Data3 .........PD6 PD6 + // Data4 .........PB2 PB2 + // Data5 .........PB3 PB3 + // Data6 .........PB4 PB4 + // Data7 .........PB5 PB5 + + // PC3 ..... E --> LCD Enable (Verbindung via J25 erforderlich) + // PD3 ..... R/W --> Read/Write: Read=1, Write=0 + // PD2 ..... RS --> Register Select: Command=0, Data=1 + + + void Lcd::init () { + clrRW(); + clrRS(); + clrE(); + setData(0); + DDRB |= (1 << PB5) | (1 << PB4) | (1 << PB3) | (1 << PB2) | (1 << PB0); + DDRC |= (1 << PC3) | (1 << PC0); + DDRD |= (1 << PD7) | (1 << PD6) | (1 << PD4) | (1 << PD3) | (1 << PD2); + initLcd(); + printf_P(PSTR("init LCD (")); + if (status == 1) { + printf_P(PSTR("OK)")); + } else { + printf_P(PSTR("ERROR %d)"), status); + } + setBacklightOn(); + } + + void Lcd::cleanup () { + clear(); + PORTB &= ~((1 << PB5) | (1 << PB4) | (1 << PB3) | (1 << PB2) | (1 << PB0)); + PORTC &= ~((1 << PC3) | (1 << PC0)); + PORTD &= ~((1 << PD7) | (1 << PD6) | (1 << PD4) | (1 << PD3) | (1 << PD2)); + DDRB &= ~((1 << PB5) | (1 << PB4) | (1 << PB3) | (1 << PB2) | (1 << PB0)); + DDRC &= ~((1 << PC3) | (1 << PC0)); + DDRD &= ~((1 << PD7) | (1 << PD6) | (1 << PD4) | (1 << PD3) | (1 << PD2)); + } + + void Lcd::setRS () { PORTD |= (1 << PD2); } + void Lcd::clrRS () { PORTD &= ~(1 << PD2); } + void Lcd::setRW () { PORTD |= (1 << PD3); } + void Lcd::clrRW () { PORTD &= ~(1 << PD3); } + void Lcd::setE () { PORTC |= (1 << PC3); } + void Lcd::clrE () { PORTC &= ~(1 << PC3); } + + void Lcd::setData (uint8_t data) { + if (data & 0x01) PORTD |= (1 << PD4); else PORTD &= ~((1 << PD4)); + if (data & 0x02) PORTB |= (1 << PB0); else PORTB &= ~((1 << PB0)); + if (data & 0x04) PORTD |= (1 << PD7); else PORTD &= ~((1 << PD7)); + if (data & 0x08) PORTD |= (1 << PD6); else PORTD &= ~((1 << PD6)); + if (data & 0x10) PORTB |= (1 << PB2); else PORTB &= ~((1 << PB2)); + if (data & 0x20) PORTB |= (1 << PB3); else PORTB &= ~((1 << PB3)); + if (data & 0x40) PORTB |= (1 << PB4); else PORTB &= ~((1 << PB4)); + if (data & 0x80) PORTB |= (1 << PB5); else PORTB &= ~((1 << PB5)); + } + + void Lcd::dataDirectionOut () { + if (!mode4Bit) { + DDRB |= (1 << PB0); + DDRD |= ((1 << PD7) | (1 << PD6) | (1 << PD4)); + } + DDRB |= ((1 << PB5) | (1 << PB4) | (1 << PB3) | (1 << PB2)); + } + + void Lcd::dataDirectionIn () { + if (hardwareVersion == 1) { + // read back not allowed (missing level shifter 5V -> 3.3V) + dataDirectionOut(); + } else { + if (!mode4Bit) { + DDRB &= ~(1 << PB0); + DDRD &= ~((1 << PD7) | (1 << PD6) | (1 << PD4)); + } + DDRB &= ~((1 << PB5) | (1 << PB4) | (1 << PB3) | (1 << PB2)); + } + } + + uint8_t Lcd::getData () { + if (hardwareVersion == 1) { + // read back not allowed (missing level shifter 5V -> 3.3V) + _delay_ms(1); + return 0x00; // bit 8 (busy) = 0 + } else { + uint8_t b = 0; + b |= ((PIND & (1 << PD4)) != 0) << 0; + b |= ((PINB & (1 << PB0)) != 0) << 1; + b |= ((PIND & (1 << PD7)) != 0) << 2; + b |= ((PIND & (1 << PD6)) != 0) << 3; + b |= ((PINB & (1 << PB2)) != 0) << 4; + b |= ((PINB & (1 << PB3)) != 0) << 5; + b |= ((PINB & (1 << PB4)) != 0) << 6; + b |= ((PINB & (1 << PB5)) != 0) << 7; + return b; + } + } + + void Lcd::setBacklightOn () { + PORTC |= (1 << PC0); + } + + void Lcd::setBacklightOff () { + PORTC &= ~(1 << PC0); + } + +#endif + +// Befehle für das Display + +#define DISP_CLEAR 0b00000001 // Display clear +#define DISP_ON 0b00001111 // Display on +#define DISP_OFF 0b00001011 // Display off +#define CURSOR_ON 0b00001111 // Cursor on +#define CURSOR_OFF 0b00001101 // Cursor off +#define BLINK_ON 0b00001111 // Cursor Blink +#define BLINK_OFF 0b00001110 // Cursor No Blink + +#define LCD_PULSE_LENGTH 15 +#define LCD_CMD_DISPLAY_CLEAR 0x01 // Display clear +#define LCD_CMD_CURSOR_HOME 0x02 // Move cursor digit 1 +#define LCD_CMD_SET_ENTRY_MODE 0x04 // Entry Mode Set +#define LCD_CMD_DISPLAY_ON_OFF 0x08 // Display on/off +#define LCD_CMD_SHIFT 0x10 // Display shift +#define LCD_CMD_SET_MODE4BIT 0x20 // 4/8 Bits... +#define LCD_CMD_SET_CGRAM_ADDR 0x40 // Character Generator ROM +#define LCD_CMD_SET_DDRAM_ADDR 0x80 // Display Data RAM +#define LCD_BUSY_FLAG 0x80 + + + +int8_t Lcd::run (uint8_t subtest) { + if (subtest == 0) { + for (uint8_t i = 0; i < 20 * 4; i++) { + char c = (char)(i + 32); + if (i % 20 == 0) { + setCursor(i / 20, 0); + } + putChar(c); + waitOnReady(); + } + printf_P(PSTR("LCD ")); + if (status == 1) { + printf_P(PSTR("OK")); + } else { + printf_P(PSTR("ERROR(%d)"), status); + } + while (wait(1) == EOF) { + } + + } else { + printf_P(PSTR("end")); + return -1; + } + wait(500); + return 0; +} + + +void Lcd::initLcd () { + + setData(0x00); + dataDirectionOut(); + + _delay_ms(16); // min 15ms warten für Reset des Displays + status = 0; + for (uint8_t i = 0; i < 4; i++) { + if (mode4Bit) { + setRegister(LCD_CMD_SET_MODE4BIT | 0x08); // 4 Bit, 2/4 Zeilen, 5x7 + } else { + setRegister(0x08); // 8 Bit, 2 Zeilen, 5x7 + } + if (i == 0) { + _delay_ms(5); + } else { + _delay_us(100); + } + } + + setRegister(LCD_CMD_DISPLAY_ON_OFF | 0x04); // display on, cursor off + if (!isReady(50)) { + status = -1; + return; + } + + setRegister(LCD_CMD_DISPLAY_ON_OFF | 0x04); // display on, cursor off + if (!isReady(50)) { + status = -3; + return; + } + + setRegister(LCD_CMD_DISPLAY_CLEAR); + if (!isReady(1200)) { + status = -4; + return; + } + + status = 1; +} + +void Lcd::setRegister (uint8_t cmd) { + clrRW(); + clrRS(); + writeData(cmd); +} + +void Lcd::writeData (uint8_t data) { + clrE(); + dataDirectionOut(); + if (mode4Bit) { + setData(data & 0xf0); // send High-Nibble + setE(); + _delay_us(LCD_PULSE_LENGTH); + clrE(); + _delay_us(1); + setData(data << 4); // send Low-Nibble + } else { + setData(data); // send data byte + } + setE(); + _delay_us(LCD_PULSE_LENGTH); + clrE(); + _delay_us(1); +} + +void Lcd::setDRAddr (uint8_t address) { + waitOnReady(); + setRegister(LCD_CMD_SET_DDRAM_ADDR | address); + waitOnReady(); +} + +void Lcd::waitOnReady () { + if (isReady(50) == 0) { + status = -6; + } +} + +bool Lcd::isReady (uint16_t us) { + if (status < 0) { + return false; + } + if (hardwareVersion == 1) { + // read back not allowed (missing level shifter) + _delay_ms(1); + return true; + } + + uint8_t busy; + dataDirectionIn(); + setData(0xff); // enable internal pull up + + do { + uint8_t data = 0; + setRW(); + clrRS(); + + _delay_us(1); + setE(); + _delay_us(LCD_PULSE_LENGTH); + data = getData() & 0xf0; // High Nibble + clrE(); + + _delay_us(1); + setE(); + _delay_us(LCD_PULSE_LENGTH); + data |= getData() >> 4; // Low Nibble + + clrE(); + _delay_us(1); + clrRW(); + + busy = data & LCD_BUSY_FLAG; + us = (us >= 11) ? us - 11 : 0; + } while (us > 0 && busy); + + if (status == 1 && busy) { + status = -5; + } + + setData(0x00); + dataDirectionOut(); + + return busy == 0; +} + + +void Lcd::setDisplayOn () { + if (status != 1) { + return; + } + waitOnReady(); + setRegister(LCD_CMD_DISPLAY_ON_OFF | 0x04); // display on + waitOnReady(); +} + +void Lcd::setDisplayOff () { + if (status != 1) { + return; + } + waitOnReady(); + setRegister(LCD_CMD_DISPLAY_ON_OFF); // display off + waitOnReady(); +} + +void Lcd::clear () { + if (status != 1) { + return; + } + waitOnReady(); + setRegister(LCD_CMD_DISPLAY_CLEAR); + waitOnReady(); +} + +void Lcd::setCursor (uint8_t rowIndex, uint8_t columnIndex) { + if (status != 1 || columnIndex >= 20) { + return; + } + uint8_t b; + switch (rowIndex) { + case 0: b = 0x00 + columnIndex; break; + case 1: b = 0x40 + columnIndex; break; + case 2: b = 0x14 + columnIndex; break; + case 3: b = 0x54 + columnIndex; break; + default: return; + } + setDRAddr(b); + waitOnReady(); +} + +void Lcd::putChar (char c) { + if (status != 1) { + return; + } + clrRW(); + setRS(); + writeData(c); + clrRS(); + waitOnReady(); +} + +void Lcd::puts (const char * str) { + while (*str && status == 1) { + putChar(*str++); + } +} \ No newline at end of file diff --git a/software/test-software/src/units/lcd.hpp b/software/test-software/src/units/lcd.hpp new file mode 100644 index 0000000..47a30cc --- /dev/null +++ b/software/test-software/src/units/lcd.hpp @@ -0,0 +1,48 @@ +#ifndef LCD_HPP +#define LCD_HPP + +#include +#include "../main.hpp" +#include + +class Lcd : public TestUnit { + public: + Lcd () { mode4Bit = hardwareVersion == 1 ? false : true; status = 0; }; + virtual void init (); + virtual void cleanup (); + virtual int8_t run (uint8_t subtest); + virtual PGM_P getName () { return PSTR("Lcd"); } + + private: + bool mode4Bit; + int8_t status; + + void initLcd (); + void setRegister (uint8_t cmd); + void setDRAddr (uint8_t address); + void writeData (uint8_t data); + void waitOnReady (); + bool isReady (uint16_t us); + void setDisplayOn (); + void setDisplayOff (); + void clear (); + void setCursor (uint8_t rowIndex, uint8_t columnIndex); + void putChar (char c); + void puts (const char * str); + + void setRS (); + void clrRS (); + void setRW (); + void clrRW (); + void setE (); + void clrE (); + uint8_t getData (); + void setData (uint8_t data); + void dataDirectionIn (); + void dataDirectionOut (); + void setBacklightOn (); + void setBacklightOff (); + +}; + +#endif \ No newline at end of file diff --git a/software/test-software/src/units/led.cpp b/software/test-software/src/units/led.cpp new file mode 100644 index 0000000..e908c21 --- /dev/null +++ b/software/test-software/src/units/led.cpp @@ -0,0 +1,139 @@ +#include +#include +#include + +#include "led.hpp" +#include "../main.hpp" + +#if defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__) + + // Nano-644 / Nano 1284 + // --------------------------------------------------------------- + + // Nano-X-Base V1a V2a + // ----------------------- + // Red PD4 PD7 + // Orange/Yellow PD5 PD6 + // Green PD6 PD5 + // Blue PD7 PD4 + + void Led::init () { + PORTD &= ~((1 << PD7) | (1 << PD6) | (1 << PD5) | (1 << PD4)); + DDRD |= (1 << PD7) | (1 << PD6) | (1 << PD5) | (1 << PD4); + } + + void Led::cleanup () { + DDRD &= ~((1 << PD7) | (1 << PD6) | (1 << PD5) | (1 << PD4)); + PORTD &= ~((1 << PD7) | (1 << PD6) | (1 << PD5) | (1 << PD4)); + } + + void Led::setLed (LED led, bool on) { + if (on) { + switch(led) { + case RED: PORTD |= (1 << PD4); break; + case ORANGE: PORTD |= (1 << PD5); break; + case GREEN: PORTD |= (1 << PD6); break; + case BLUE: PORTD |= (1 << PD7); break; + } + } else { + switch(led) { + case RED: PORTD &= ~(1 << PD4); break; + case ORANGE: PORTD &= ~(1 << PD5); break; + case GREEN: PORTD &= ~(1 << PD6); break; + case BLUE: PORTD &= ~(1 << PD7); break; + } + } + } + + void Led::ledToggle (LED led) { + switch(led) { + case RED: PORTD ^= (1 << PD4); break; + case ORANGE: PORTD ^= (1 << PD5); break; + case GREEN: PORTD ^= (1 << PD6); break; + case BLUE: PORTD ^= (1 << PD7); break; + } + } + +#endif + +#ifdef __AVR_ATmega328P__ + + // Arduino-Nano-5V + // --------------------------------------------------------------- + + // Nano-X-Base V1a V2a + // ----------------------- + // Red PD5 PD2 + // Orange/Yellow PB1 PD3 + // Green PD3 PB1 + // Blue PD2 PD5 + + void Led::init () { + PORTD &= ~((1 << PD5) | (1 << PD3) | (1 << PD2)); + PORTB &= ~(1 << PB1); + DDRD |= (1 << PD5) | (1 << PD3) | (1 << PD2); + DDRB |= (1 << PB1); + } + + void Led::cleanup () { + DDRD &= ~((1 << PD5) | (1 << PD3) | (1 << PD2)); + DDRB &= ~(1 << PB1); + PORTD &= ~((1 << PD5) | (1 << PD3) | (1 << PD2)); + PORTB &= ~(1 << PB1); + } + + void Led::setLed (LED led, bool on) { + if (on) { + switch(led) { + case RED: PORTD |= (1 << PD5); break; + case ORANGE: PORTB |= (1 << PB1); break; + case GREEN: PORTD |= (1 << PD3); break; + case BLUE: PORTD |= (1 << PD2); break; + } + } else { + switch(led) { + case RED: PORTD &= ~(1 << PD5); break; + case ORANGE: PORTB &= ~(1 << PB1); break; + case GREEN: PORTD &= ~(1 << PD3); break; + case BLUE: PORTD &= ~(1 << PD2); break; + } + } + } + + void Led::ledToggle (LED led) { + switch(led) { + case RED: PORTD ^= (1 << PD5); break; + case ORANGE: PORTB ^= (1 << PB1); break; + case GREEN: PORTD ^= (1 << PD3); break; + case BLUE: PORTD ^= (1 << PD2); break; + } + } + +#endif + +void Led::ledOn (LED led) { + setLed(led, true); +} + +void Led::ledOff (LED led) { + setLed(led, false); +} + + +int8_t Led::run (uint8_t subtest) { + if (subtest <= 15) { + subtest = (subtest) % 4; + switch (subtest) { + case 0: ledOff(BLUE); ledOn(RED); break; + case 1: ledOff(RED); ledOn(ORANGE); break; + case 2: ledOff(ORANGE); ledOn(GREEN); break; + case 3: ledOff(GREEN); ledOn(BLUE); break; + } + printf_P(PSTR("Test LED D%d"), subtest + 1); + wait(500); + return 0; + } + + return -1; +} + diff --git a/software/test-software/src/units/led.hpp b/software/test-software/src/units/led.hpp new file mode 100644 index 0000000..780827f --- /dev/null +++ b/software/test-software/src/units/led.hpp @@ -0,0 +1,25 @@ +#ifndef LED_HPP +#define LED_HPP + +#include +#include "../main.hpp" +#include + +class Led : public TestUnit { + public: + enum LED { RED, ORANGE, GREEN, BLUE }; + + public: + Led () {}; + virtual void init (); + virtual void cleanup (); + virtual int8_t run (uint8_t subtest); + virtual PGM_P getName () { return PSTR("Led"); } + + void setLed (LED led, bool on); + void ledOn (LED led); + void ledOff (LED led); + void ledToggle (LED led); +}; + +#endif \ No newline at end of file diff --git a/software/test-software/src/units/modbus.cpp b/software/test-software/src/units/modbus.cpp new file mode 100644 index 0000000..abbe36d --- /dev/null +++ b/software/test-software/src/units/modbus.cpp @@ -0,0 +1,160 @@ +#include +#include +#include + +#include "modbus.hpp" +#include "../main.hpp" + + +#ifdef __AVR_ATmega328P__ +void Modbus::init () {} +void Modbus::cleanup () {} +int8_t Modbus::run (uint8_t subtest) { return -1; } +void Modbus::handleRxByte (uint8_t b) {} +#endif + +#if defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__) + +// PB0 ... nRE .. Read enable +// PB1 ... DE .. Data enable + +#define SET_nRE (PORTB |= (1 << PB0)) +#define CLR_nRE (PORTB &= ~(1 << PB0)) +#define SET_DE (PORTB |= (1 << PB1)) +#define CLR_DE (PORTB &= ~(1 << PB1)) + + +void Modbus::init () { +} + +void Modbus::cleanup () { + enabled = 0; + UCSR1A = 0; + UCSR1B = 0; + UCSR1C = 0; + UBRR1H = 0; + UBRR1L = 0; + PORTD &= ~(1 << PD2); + DDRB &= ~((1 << PB1) | (1 << PB0)); + PORTB &= ~((1 << PB1) | (1 << PB0)); +} + +int8_t Modbus::run (uint8_t subtest) { + if (subtest == 0) { + SET_nRE; + CLR_DE; + DDRB |= (1 << PB1) | (1 << PB0); + + // UART1 interface on Nano-644 + PORTD |= (1 << PD2); // enable RxD1 pullup + UCSR1A = (1 << U2X1); + UCSR1B = (1 << RXCIE1) | (1 << RXEN1) | (1 <= 1 && subtest <= 4) { + uint8_t nre, de, b; + switch (subtest) { + case 1: nre = 1; de = 0; b = 0x01; break; + case 2: nre = 1; de = 1; b = 0x8e; break; + case 3: nre = 0; de = 0; b = 0x55; break; + case 4: nre = 0; de = 1; b = 0xaa; break; + default: return -1; + } + printf_P(PSTR(" DE=%u, nRE=%u send 0x%02x... "), de, nre, b); + if (nre) { + SET_nRE; + } else { + CLR_nRE; + } + if (de) { + SET_DE; + } else { + CLR_DE; + } + _delay_us(100); + receivedBytes = 0; + UDR1 = b; + _delay_ms(1); + if (receivedBytes > 0) { + printf_P(PSTR("0x%02x received"), received[0]); + receivedBytes = 0; + } else { + printf_P(PSTR("no byte received")); + } + printf_P(PSTR(" ... press key to proceed")); + while (wait(0xffffffff) == EOF) {} + CLR_DE; + SET_nRE; + + } else if (subtest == 5) { + static uint8_t frame[] = { 0x01, 0x04, 0x00, 0x00, 0x00, 0x02, 0x71, 0xcb }; + printf_P(PSTR("Modbus: lese Spannung von Eastron SDM-230 (Einphasenzähler)")); + SET_DE; + CLR_nRE; + _delay_us(100); + do { + SET_DE; + receivedBytes = 0; + for (uint8_t i = 0; i < sizeof(frame); i++) { + UCSR1A |= (1 << TXC1); + UDR1 = frame[i]; + while ((UCSR1A & (1 < Sending:")); + for (uint8_t i = 0; i < sizeof(frame); i++) { + printf_P(PSTR(" 0x%02x"), frame[i]); + } + int k = wait(100); + + printf_P(PSTR("\n RxD1:")); + if (receivedBytes == 0) { + printf_P(PSTR("?")); + } else { + for (uint8_t i = 0; i < receivedBytes; i++) { + if (i == sizeof(frame)) { + printf_P(PSTR(" ")); + } + printf_P(PSTR(" 0x%02x"), received[i]); + } + } + if (receivedBytes >= 16) { + union { + uint8_t b[4]; + float value; + } f; + f.b[0] = received[14]; + f.b[1] = received[13]; + f.b[2] = received[12]; + f.b[3] = received[11]; + printf_P(PSTR(" -> %4.8fV\n"), (double)f.value); + } + if (k != EOF) { + break; + } + + } while (wait(1000) == EOF); + + } else { + printf_P(PSTR("end")); + return -1; + } + wait(500); + return 0; +} + +void Modbus::handleRxByte (uint8_t b) { + if (receivedBytes < sizeof(received)) { + received[receivedBytes++] = b; + } +} + +#endif \ No newline at end of file diff --git a/software/test-software/src/units/modbus.hpp b/software/test-software/src/units/modbus.hpp new file mode 100644 index 0000000..44b6a9d --- /dev/null +++ b/software/test-software/src/units/modbus.hpp @@ -0,0 +1,24 @@ +#ifndef MODBUS_HPP +#define MODBUS_HPP + +#include +#include "../main.hpp" +#include + +class Modbus : public TestUnit { + public: + uint8_t enabled; + uint8_t receivedBytes; + uint8_t received[16]; + + + public: + Modbus () { enabled = 0; receivedBytes = 0; } + virtual void init (); + virtual void cleanup (); + virtual int8_t run (uint8_t subtest); + virtual PGM_P getName () { return PSTR("Modbus"); } + void handleRxByte (uint8_t); +}; + +#endif \ No newline at end of file diff --git a/software/test-software/src/units/motor.cpp b/software/test-software/src/units/motor.cpp new file mode 100644 index 0000000..7f8fbf9 --- /dev/null +++ b/software/test-software/src/units/motor.cpp @@ -0,0 +1,221 @@ +#include +#include +#include + +#include "motor.hpp" +#include "../main.hpp" + +#if defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__) + + // Nano-644 + // --------------------------------------------------------------- + // PB0 ..... rotation-sensor + // PB2 ..... nFault + // PB3 ..... PWM (OC0A) + // PB4 ..... EN + // PA3 ..... SW3 -> push button for Motor enable control + + #define ADC0K 64 + + void Motor::init () { + DDRD |= (1 << PD7); // sensor signal toggle on PD7 (LED D4 red) + ADMUX = (1 << ADLAR) | (1 << REFS0); // ADC0, VREF=AVCC=3.3V + ADCSRA = (1 << ADEN) | 7; // ADC Enable, Prescaler 128 + TCCR0A = (1 << COM0A1) | (1 << WGM01) | (1 << WGM00); // Fast PWM on OC0A + // TCCR0B = (1 << CS02) | ( 1 << CS00); // f = 12 MHz / 1024 = 11,71875 kHz -> fPWM=45Hz + TCCR0B = (1 << CS02); // f = 12 MHz / 256 = 46,875 kHz -> fPWM=183,1Hz + DDRB |= (1 << PB4) | (1 << PB3); // Motor enable + PORTA |= (1 << PORTA3); // push button for Motor enable control + setEnable(); + enabled = 1; + } + + void Motor::cleanup () { + DDRD &= ~(1 << PD7); + ADMUX = 0; + ADCSRA = 0; + TCCR0A = 0; + TCCR0B = 0; + DDRB &= ~((1 << PB4) | (1 << PB3)); + PORTA &= ~(1 << PORTA3); + enabled = 0; + } + + bool Motor::isSW3Pressed () { + return (PINA & (1 << PC3)) == 0; + } + + void Motor::clearEnable () { + PORTB &= ~(1 << PB4); + } + + void Motor::setEnable () { + PORTB |= (1 << PB4); + } + + bool Motor::isFaultLow () { + return (PINB & (1 << PB2)) == 0; + } + + bool Motor::isSensorHigh () { + return (PINB & (1 << PB0)) != 0; + } + + void Motor::toggleD4 () { + PORTD ^= (1 << PD7); + } + +#endif + +#ifdef __AVR_ATmega328P__ + + // Arduino-Nano-5V + // --------------------------------------------------------------- + // PD4 ..... rotation-sensor + // PD7 ..... nFault + // PD6/OC0A ..... PWM + // PB2 ..... EN + // PC3 ..... SW3 -> push button for Motor enable control + + #define ADC0K 91 + + void Motor::init () { + DDRD |= (1 << PD2); // sensor signal toggle on PD2 (LED D4 red) + ADMUX = (1 << ADLAR) | (1 << REFS0); // ADC0, VREF=AVCC=5V + ADCSRA = (1 << ADEN) | 7; // ADC Enable, Prescaler 128 + TCCR0A = (1 << COM0A1) | (1 << WGM01) | (1 << WGM00); // Fast PWM on OC0A + // TCCR0B = (1 << CS02) | ( 1 << CS00); // f = 16 MHz / 1024 = 15,625 kHz -> fPWM=61.04Hz + TCCR0B = (1 << CS02); // f = 16 MHz / 256 = 62.5 kHz -> fPWM=244.14Hz + DDRB |= (1 << PB2); + DDRC &= ~(1 << PC3); + DDRD |= (1 << PD6); + DDRD &= ~((1 << PD4) | (1 << PD7)); + PORTC |= ( 1 << PC3); + PORTD |= (1 << PD7) | (1 << PD5); + setEnable(); + enabled = 1; + } + + void Motor::cleanup () { + DDRD &= ~(1 << PD2); + enabled = 0; + ADMUX = 0; + ADCSRA = 0; + TCCR0A = 0; + TCCR0B = 0; + clearEnable(); + DDRB &= ~((1 << PB2)); + DDRC &= ~(1 << PC3); + DDRD &= ~((1 << PD7) | (1 << PD6) | (1 << PD4)); + PORTC &= ~( 1 << PC3); + PORTD &= ~((1 << PD7) | (1 << PD6)); + } + + bool Motor::isSW3Pressed () { + return (PINC & (1 << PC3)) == 0; + } + + void Motor::clearEnable () { + PORTB &= ~(1 << PB2); + } + + void Motor::setEnable () { + PORTB |= (1 << PB2); + } + + bool Motor::isFaultLow () { + return (PIND & (1 << PD7)) == 0; + } + + bool Motor::isSensorHigh () { + return (PIND & (1 << PD4)) != 0; + } + + void Motor::toggleD4 () { + PORTD ^= (1 << PD2); + } + +#endif + +int8_t Motor::run (uint8_t subtest) { + switch (subtest) { + case 0: { + printf_P(PSTR("\n")); + while (wait(10) == EOF) { + + printf_P(PSTR("\r SW3=%d->"), isSW3Pressed() ? 0 : 1); + if (isSW3Pressed()) { + clearEnable(); + printf_P(PSTR("EN=0")); + } else { + setEnable(); + printf_P(PSTR("EN=1")); + } + + ADCSRA |= (1 << ADSC); // start ADC + while (ADCSRA & (1 << ADSC)) {} // wait for result + printf_P(PSTR("\r => ADC0=%3d"), ADCH); + + ADMUX = (1 << ADLAR) | (1 << REFS1) | (1 << REFS0) | 2; // ADC2, VREF=2.5V + + int16_t x = ((int16_t)(ADCH) - 5) * ADC0K / 64; + if (x < 0) x = 0; else if (x > 255) x = 255; + uint8_t dutyCycle = 0xff - (uint8_t)x; + if (dutyCycle <= 1) { + dutyCycle = 0; + } else if (dutyCycle > 254) { + dutyCycle = 255; + } + OCR0A = dutyCycle; + printf_P(PSTR(" PWM/OC0A=%3d"), dutyCycle); + + ADCSRA |= (1 << ADSC); // start ADC + while (ADCSRA & (1 << ADSC)) {} // wait for result + printf_P(PSTR(" ADC2=%3d"), ADCH); + ADMUX = (1 << ADLAR) | (1 << REFS0); // ADC0, VREF=AVCC=3.3V + + printf_P(PSTR(" nFAULT=%d"), isFaultLow() ? 0 : 1); + printf_P(PSTR(" SENSOR=%d "), isSensorHigh()); + uint16_t timer; + ATOMIC_BLOCK(ATOMIC_FORCEON) { + timer = rpmTimer; + } + float rpm = 60.0 / (float)timer / 0.0001; + if (timer > 0) { + printf_P(PSTR(" n= %5d U/min (T=%04x)"), (int)rpm, timer); + } else { + printf_P(PSTR(" no rotation (T=%04x) "), timer); + } + + } + return 0; + } + } + + return -1; +} + +void Motor::tick100us () { + static uint16_t timerH = 0; + static uint16_t timerL = 0; + static bool lastSensorHigh = false; + + bool sensorHigh = isSensorHigh(); + if (!sensorHigh && sensorHigh != lastSensorHigh && timerL > 2) { + rpmTimer = timerL + timerH; + timerL = 0; + timerH = 0; + toggleD4(); + } + if (sensorHigh) { + timerH = timerH < 0x4000 ? timerH + 1 : 0x4000; + } else { + timerL = timerL < 0x4000 ? timerL + 1 : 0x4000; + } + if (timerH >= 0x4000 || timerL >= 0x4000) { + rpmTimer = 0; // no ratation detected + } + lastSensorHigh = sensorHigh; +} + + diff --git a/software/test-software/src/units/motor.hpp b/software/test-software/src/units/motor.hpp new file mode 100644 index 0000000..2cbd15a --- /dev/null +++ b/software/test-software/src/units/motor.hpp @@ -0,0 +1,30 @@ +#ifndef MOTOR_HPP +#define MOTOR_HPP + +#include +#include "../main.hpp" +#include + +class Motor : public TestUnit { + public: + uint8_t enabled; + uint16_t rpmTimer; + + public: + Motor () { enabled = 0; rpmTimer = 0; }; + virtual void init (); + virtual void cleanup (); + virtual int8_t run (uint8_t subtest); + virtual PGM_P getName () { return PSTR("Motor"); } + void tick100us (); + + private: + bool isSW3Pressed (); + void clearEnable (); + void setEnable (); + bool isFaultLow (); + bool isSensorHigh (); + void toggleD4 (); +}; + +#endif \ No newline at end of file diff --git a/software/test-software/src/units/portexp.cpp b/software/test-software/src/units/portexp.cpp new file mode 100644 index 0000000..a153589 --- /dev/null +++ b/software/test-software/src/units/portexp.cpp @@ -0,0 +1,195 @@ +#include +#include +#include + +#include "portexp.hpp" +#include "../main.hpp" + +// Port-Expander MCP23S17 + +// SN-Print Stecker IO16 +// MCP23S17 | IO16 (MEGA2560) | Ampel-Print | | MCP23S17 | IO16 (MEGA2560) | Ampel-Print | +// ------------------------------------------ -------------------------------------------- +// GPA0 | IO16O7 (PA7) | Taster RU | | GPB0 | IO16U7 (PC7) | Taster LU | +// GPA1 | IO16O6 (PA6) | Taster RO | | GPB1 | IO16U6 (PC6) | Taster LO | +// GPA2 | IO16O5 (PA5) | U-Gruen | | GPB2 | IO16U5 (PC5) | R-Gruen | +// GPA3 | IO16O4 (PA4) | U-Gelb | | GPB3 | IO16U4 (PC4) | R-Gelb | +// GPA4 | IO16O3 (PA3) | U-Rot | | GPB4 | IO16U3 (PC3) | R-Rot | +// GPA5 | IO16O2 (PA2) | L-Gruen | | GPB5 | IO16U2 (PC2) | O-Gruen | +// GPA6 | IO16O1 (PA1) | L-Gelb | | GPB6 | IO16U1 (PC1) | O-Gelb | +// GPA7 | IO16O0 (PA0) | L-Rot | | GPB7 | IO16U0 (PC0) | O-Rot | + +#if defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__) + + // Nano-644 / Nano1284 + // -------------------------------------------------------- + // PA7 ... nCS + // PB5 ... MOSI + // PB6 ... MISO + // PB7 ... SCK + + void PortExp::init () { + PRR0 &= (1 << PRSPI); + PORTA |= (1 << PA7); + DDRA |= (1 << PA7); // SPI nCS + // PORTB/DDRB must be configured before SPCR !! + PORTB |= (1 << PB4); // nSS must be HIGH, otherwise SPI master will not become active!! + DDRB |= (1 << PB7) | (1 << PB5) | (1 << PB4); // SPI SCK (=PB7) and SPI MOSI (=PB5) + DDRB &= ~(1 << PB6); + + SPCR |= (1 << SPE) | (1 << MSTR) | (1 << SPR1) | (1 << SPR0); // SPI enable , Master, f=12MHz/128=93,75kHz + // SPCR = (1 << SPE) | (1 << MSTR); // SPI enable , Master, f=12MHz/4 = 3MHz + } + + void PortExp::cleanup () { + DDRB &= ~(1 << PB6); // // SPI MISO (=PB6) + DDRB &= ~((1 << PB7) | (1 << PB5)); // SPI SCK (=PB7) and SPI MOSI (=PB5) + DDRA &= ~(1 << PA7); + PORTA &= ~(1 << PA7); // SPI nCS + SPCR = 0; + } + + void PortExp::setChipEnable () { + PORTA &= ~(1 << PA7); + } + + void PortExp::clearChipEnable () { + PORTA |= (1 << PA7); + } + + +#endif + +#ifdef __AVR_ATmega328P__ + + // Arduino-Nano-5V + // ------------------------------------ + // PC1 ... nCS (MANUAL (!) connection PA1 - PA7 required) + // PB3 ... MOSI + // PB4 ... MISO + // PB5 ... SCK + + void PortExp::init () { + PRR &= (1 << PRSPI); + PORTC |= (1 << PC1); + DDRC |= (1 << PC1); // SPI nCS + // PORTB/DDRB must be configured before SPCR !! + PORTB |= (1 << PB2); // nSS must be HIGH, otherwise SPI master will not become active!! + DDRB |= (1 << PB5) | (1 << PB3) | (1 << PB2); // SPI SCK (=PB5), SPI MOSI (=PB3), SPI nSS (=PB2) + + SPCR |= (1 << SPE) | (1 << MSTR) | (1 << SPR1) | (1 << SPR0); // SPI enable , Master, f=16MHz/128=125kHz + // SPCR = (1 << SPE) | (1 << MSTR); // SPI enable , Master, f=12MHz/4 = 3MHz + + if (hardwareVersion == 2) { + PORTD |= (1 << PD7); // nCS when V2a/JP39.2-3 jumpered + DDRD |= (1 << PD7); + } + } + + void PortExp::cleanup () { + PORTC &= ~(1 << PC1); + DDRC &= ~(1 << PC1); + PORTB &= ~(1 << PB2); + DDRB &= ~((1 << PB5) | (1 << PB3) | (1 << PB2)); + SPCR = 0; + } + + void PortExp::setChipEnable () { + if (hardwareVersion == 2) { + PORTD &= ~(1 << PD7); + } + } + + void PortExp::clearChipEnable () { + if (hardwareVersion == 2) { + PORTD |= (1 << PD7); + } + } + +#endif + + + +int8_t PortExp::writeByte (uint8_t addr, uint8_t b) { + // no response via SPI MISO because SO stays tristate on write cycle + setChipEnable(); + SPDR = 0x40; // WRITE BYTE + while ((SPSR & (1 << SPIF)) == 0) {} + SPDR = addr; // register address + while ((SPSR & (1 << SPIF)) == 0) {} + SPDR = b; // value + while ((SPSR & (1 << SPIF)) == 0) {} + clearChipEnable(); + + _delay_us(5); + return 0; +} + +uint8_t PortExp::readByte (uint8_t addr) { + // response via SPI MISO only on third byte + setChipEnable(); + SPDR = 0x41; // write "READ BYTE" + while ((SPSR & (1 << SPIF)) == 0) {} + SPDR = addr; // write "register address" + while ((SPSR & (1 << SPIF)) == 0) {} + SPDR = 0; // additional 8 clocks to get response from port expander + while ((SPSR & (1 << SPIF)) == 0) {} + clearChipEnable(); + return SPDR; +} + +void PortExp::checkResponse (uint8_t address, uint8_t response, uint8_t desired) { + printf_P(PSTR(" (read 0x%02x -> 0x%02x"), address, response); + if (response != desired) { + printf_P(PSTR(" ERROR")); + if (response == 0xff) { + printf_P(PSTR(" JP39.2/3 jumpered (left)?")); + } + } else { + printf_P(PSTR(" OK")); + } + printf_P(PSTR(")")); +} + + +int8_t PortExp::run (uint8_t subtest) { + #ifdef __AVR_ATmega328P__ + if (hardwareVersion == 1) { + printf_P(PSTR("ERROR - nCS not controlable\n")); + return -1; + } + #endif + if (subtest == 0) { + while (wait(500) == EOF) { + printf_P(PSTR("\n => start ...")); + for (uint8_t i = 0; i < 8; i++) { + writeByte(0, ~(1 << i)); // IODIRA (Bank = 0) + writeByte(0x12, (1 << i)); // GPIOA (Bank = 0) + printf_P(PSTR("\n Bank0 - GPA%d = 1"), i); + checkResponse (0x12, readByte(0x12), (1 << i)); + wait(200); + writeByte(0x12, 0); // GPIOA (Bank = 0) + printf_P(PSTR("\n Bank0 - GPA%d = 0"), i); + checkResponse (0x12, readByte(0x12), 0); + writeByte(0, 0xff); // IODIRA (Bank = 0) + wait(200); + } + for (uint8_t i = 0; i < 8; i++) { + writeByte(1, ~(1 << i)); // IODIRB (Bank = 0) + writeByte(0x13, (1 << i)); // GPIOB (Bank = 0) + printf_P(PSTR("\n Bank0 - GPB%d = 1"), i); + checkResponse (0x13, readByte(0x13), (1 << i)); + wait(200); + writeByte(0x13, 0); // GPIOB (Bank = 0) + printf_P(PSTR("\n Bank0 - GPB%d = 0"), i); + checkResponse (0x13, readByte(0x13), 0); + writeByte(1, 0xff); // IODIRB (Bank = 0) + wait(200); + } + } + return 0; + } + + return -1; +} + diff --git a/software/test-software/src/units/portexp.hpp b/software/test-software/src/units/portexp.hpp new file mode 100644 index 0000000..8705662 --- /dev/null +++ b/software/test-software/src/units/portexp.hpp @@ -0,0 +1,24 @@ +#ifndef PORTEXP_HPP +#define PORTEXP_HPP + +#include +#include "../main.hpp" +#include + +class PortExp : public TestUnit { + public: + PortExp () {}; + virtual void init (); + virtual void cleanup (); + virtual int8_t run (uint8_t subtest); + virtual PGM_P getName () { return PSTR("PortExp"); } + + private: + void setChipEnable (); + void clearChipEnable (); + int8_t writeByte (uint8_t addr, uint8_t b); + uint8_t readByte (uint8_t addr); + void checkResponse (uint8_t address, uint8_t response, uint8_t desired); +}; + +#endif \ No newline at end of file diff --git a/software/test-software/src/units/poti.cpp b/software/test-software/src/units/poti.cpp new file mode 100644 index 0000000..94fc5a4 --- /dev/null +++ b/software/test-software/src/units/poti.cpp @@ -0,0 +1,34 @@ +#include +#include + +#include "poti.hpp" +#include "../main.hpp" + +void Poti::init () { + ADMUX = (1 << REFS0); // ADC0, VREF=AVCC=3.3V + ADCSRA = (1 << ADEN) | 7; // ADC Enable, Prescaler 128 +} + +void Poti::cleanup () { + ADMUX = 0; + ADCSRA = 0; +} + +int8_t Poti::run (uint8_t subtest) { + switch (subtest) { + case 0: { + printf_P(PSTR("\n")); + while (wait(10) == EOF) { + printf_P(PSTR("\r => Measure ADC0: ")); + ADCSRA |= (1 << ADSC); // start ADC + while (ADCSRA & (1 << ADSC)) {} // wait for result + printf_P(PSTR("%4d (0x%03x)"), ADC, ADC); + } + return 0; + } + } + + return -1; +} + + diff --git a/software/test-software/src/units/poti.hpp b/software/test-software/src/units/poti.hpp new file mode 100644 index 0000000..b13dd29 --- /dev/null +++ b/software/test-software/src/units/poti.hpp @@ -0,0 +1,17 @@ +#ifndef POTI_HPP +#define POTI_PP + +#include +#include "../main.hpp" +#include + +class Poti : public TestUnit { + public: + Poti () {}; + virtual void init (); + virtual void cleanup (); + virtual int8_t run (uint8_t subtest); + virtual PGM_P getName () { return PSTR("Poti"); } +}; + +#endif \ No newline at end of file diff --git a/software/test-software/src/units/r2r.cpp b/software/test-software/src/units/r2r.cpp new file mode 100644 index 0000000..54664b1 --- /dev/null +++ b/software/test-software/src/units/r2r.cpp @@ -0,0 +1,48 @@ +#include +#include + +#include "r2r.hpp" +#include "../main.hpp" + +#if defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__) + // AVCC=3.3, POTI Vmax=3.3V + #define K 1.0 +#endif + +#ifdef __AVR_ATmega328P__ + // AVCC=4.7V, POTI Vmax=3.3V + #define K 1.32 +#endif + +void R2r::init () { + ADMUX = (1 << REFS0) | 2; // ADC2, VREF=AVCC (=3.3V for Nano-644/1284, =5V for Arduino Nano) + ADCSRA = (1 << ADEN) | 7; // ADC Enable, Prescaler 128 +} + +void R2r::cleanup () { + ADMUX = 0; + ADCSRA = 0; +} + +int8_t R2r::run (uint8_t subtest) { + switch (subtest) { + case 0: { + printf_P(PSTR("\n")); + while (wait(10) == EOF) { + printf_P(PSTR("\r => Measure ADC2: ")); + ADCSRA |= (1 << ADSC); // start ADC + while (ADCSRA & (1 << ADSC)) {} // wait for result + printf_P(PSTR("%4d (0x%03x)"), ADC, ADC); + // uint8_t sw = (uint8_t)( ((float)(ADC) + 4.0) / 64.0 * K ); + float swf = ((float)(ADC) * K) / 64.8 + 0.55; + uint8_t sw = (uint8_t)swf ; + printf_P(PSTR(" %3.1f => SW9:6 = %d %d% d %d "), swf, sw >> 3, (sw >> 2) & 0x01, (sw >> 1) & 0x01, sw & 0x01 ); + } + return 0; + } + } + + return -1; +} + + diff --git a/software/test-software/src/units/r2r.hpp b/software/test-software/src/units/r2r.hpp new file mode 100644 index 0000000..84e97e6 --- /dev/null +++ b/software/test-software/src/units/r2r.hpp @@ -0,0 +1,17 @@ +#ifndef R2R_HPP +#define R2R_PP + +#include +#include "../main.hpp" +#include + +class R2r : public TestUnit { + public: + R2r () {}; + virtual void init (); + virtual void cleanup (); + virtual int8_t run (uint8_t subtest); + virtual PGM_P getName () { return PSTR("R2R"); } +}; + +#endif \ No newline at end of file diff --git a/software/test-software/src/units/rgb.cpp b/software/test-software/src/units/rgb.cpp new file mode 100644 index 0000000..3f69cbd --- /dev/null +++ b/software/test-software/src/units/rgb.cpp @@ -0,0 +1,152 @@ +#include +#include + +#include "rgb.hpp" +#include "../main.hpp" + +#if defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__) + + // Nano-644 + // --------------------------------------------------------------- + // PB0 ..... Red (inverse logic -> 0 = ON) + // PB1 ..... Green (inverse logic -> 0 = ON) + // PB2 ..... Blue (inverse logic -> 0 = ON) + + void Rgb::init () { + ledOff(RED); + ledOff(GREEN); + ledOff(BLUE); + DDRB |= (1 << PB2) | (1 << PB1) | (1 << PB0); + } + + void Rgb::cleanup () { + ledOff(RED); + ledOff(GREEN); + ledOff(BLUE); + DDRB &= ~((1 << PB2) | (1 << PB1) | (1 << PB0)); + } + + void Rgb::setLed (LED led, bool on) { + if (on) { + switch(led) { + case RED: PORTB &= ~(1 << PB0); break; + case GREEN: PORTB &= ~(1 << PB1); break; + case BLUE: PORTB &= ~(1 << PB2); break; + } + } else { + switch(led) { + case RED: PORTB |= (1 << PB0); break; + case GREEN: PORTB |= (1 << PB1); break; + case BLUE: PORTB |= (1 << PB2); break; + } + } + } + + void Rgb::ledToggle (LED led) { + switch(led) { + case RED: PORTB ^= (1 << PB0); break; + case GREEN: PORTB ^= (1 << PB1); break; + case BLUE: PORTB ^= (1 << PB2); break; + } + } + + +#endif + +#ifdef __AVR_ATmega328P__ + + // Arduino-Nano-5V + // --------------------------------------------------------------- + // PD4 ..... Red (inverse logic -> 0 = ON) + // PB0 ..... Green (inverse logic -> 0 = ON) + // PD7 ..... Blue (inverse logic -> 0 = ON) + + void Rgb::init () { + ledOff(RED); + ledOff(GREEN); + ledOff(BLUE); + DDRB |= (1 << PB0); + DDRD |= (1 << PD7) | (1 << PD4); + } + + void Rgb::cleanup () { + ledOff(RED); + ledOff(GREEN); + ledOff(BLUE); + DDRB &= ~(1 << PB0); + DDRD &= ~((1 << PD7) | (1 << PD4)); + } + + void Rgb::setLed (LED led, bool on) { + if (on) { + switch (led) { + case RED: PORTD &= ~(1 << PD4); break; + case GREEN: PORTB &= ~(1 << PB0); break; + case BLUE: PORTD &= ~(1 << PD7); break; + } + } else { + switch (led) { + case RED: PORTD |= (1 << PD4); break; + case GREEN: PORTB |= (1 << PB0); break; + case BLUE: PORTD |= (1 << PD7); break; + } + } + } + + void Rgb::ledToggle (LED led) { + switch (led) { + case RED: PORTD ^= (1 << PD4); break; + case GREEN: PORTB ^= ~(1 << PB0); break; + case BLUE: PORTD ^= (1 << PD7); break; + } + } + +#endif + +void Rgb::ledOn (LED led) { + setLed(led, true); +} + +void Rgb::ledOff (LED led) { + setLed(led, false); +} + +int8_t Rgb::run (uint8_t subtest) { + switch (subtest) { + case 0: { + ledOn(RED); + printf_P(PSTR("Red")); + wait(3000); + ledOff(RED); + return 0; + } + + case 1: { + ledOn(GREEN); + printf_P(PSTR("Green")); + wait(3000); + ledOff(GREEN); + return 0; + } + + case 2: { + ledOn(BLUE); + printf_P(PSTR("Blue")); + wait(3000); + ledOff(BLUE); + return 0; + } + + case 3: { + ledOn(RED); ledOn(GREEN); ledOn(BLUE); + printf_P(PSTR("All")); + wait(3000); + ledOff(RED); ledOff(GREEN); ledOff(BLUE); + return 0; + } + } + + return -1; +} + + diff --git a/software/test-software/src/units/rgb.hpp b/software/test-software/src/units/rgb.hpp new file mode 100644 index 0000000..12e9da4 --- /dev/null +++ b/software/test-software/src/units/rgb.hpp @@ -0,0 +1,25 @@ +#ifndef RGB_HPP +#define RGB_PP + +#include +#include "../main.hpp" +#include + +class Rgb : public TestUnit { + public: + enum LED { RED, GREEN, BLUE }; + + public: + Rgb () {}; + virtual void init (); + virtual void cleanup (); + virtual int8_t run (uint8_t subtest); + virtual PGM_P getName () { return PSTR("Rgb"); } + + void setLed (LED led, bool on); + void ledOn (LED led); + void ledOff (LED led); + void ledToggle (LED led); +}; + +#endif \ No newline at end of file diff --git a/software/test-software/src/units/rtc8563.cpp b/software/test-software/src/units/rtc8563.cpp new file mode 100644 index 0000000..6ae6497 --- /dev/null +++ b/software/test-software/src/units/rtc8563.cpp @@ -0,0 +1,253 @@ +#include +#include +#include +#include +#include + +#include "rtc8563.hpp" +#include "../adafruit/bme280.h" +#include "../main.hpp" + +// RTC BME653EMA on Nano-644 + +const char PSTR_WEEKDAYS[] PROGMEM = "So\0Mo\0Di\0Mi\0Do\0Fr\0Sa\0"; + +// const uint8_t CONFIG[] PROGMEM = { +// /* config -> */ 0x00, 0x00, +// /* enable nINT -> */ 0x01, 0x01, // TIE = 1 +// /* set clock -> */ 0x02, 0x00, 0x00, 0x08, 0x16, 0x02, 0x08, 0x24 +// }; + +void Rtc8563::handleTwiIrq () { + TWCR |= (1 << TWINT); // clear Interrupt Request +} + +#ifdef __AVR_ATmega328P__ +void Rtc8563::init () {} +void Rtc8563::cleanup () {} +int8_t Rtc8563::run (uint8_t subtest) { return -1; } +PGM_P Rtc8563::getName () { return PSTR("?"); } +#endif + +#if defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__) + +void Rtc8563::init () { + PORTC &= ~(1 << PC7); // nInt and nPowerOn (Q7 -> BATTERY) + DDRC |= (1 << PC7); + TWBR = 13; // 100kHz (TWPS1:0 = 00), TWBR = (F_CPU - 16 * 100000) / (2 * 100000 * 4); + TWBR = 28; // 50kHz (TWPS1:0 = 00), TWBR = (F_CPU - 16 * 50000) / (2 * 50000 * 4); + TWBR = 100; // 50kHz (TWPS1:0 = 00), TWBR = (F_CPU - 16 * 50000) / (2 * 50000 * 4); + TWCR = (1 << TWEN); + enabled = true; +} + +void Rtc8563::cleanup () { + enabled = false; + TWCR = (1 << TWEN); + TWBR = 0; + // PORTC &= ~(1 << PC7); + // DDRC &= ~(1 << PC7); +} + +PGM_P Rtc8563::getName () { + return PSTR("RTC-8563"); +} + +uint8_t Rtc8563::bcd2bin (uint8_t value) { + return (value >> 4) * 10 + (value & 0x0f); +} + +int8_t Rtc8563::run (uint8_t subtest) { + int key = EOF; + if (subtest == 0) { + // printf_P(PSTR(" BM280 ... ")); + rtc8563.begin(0x51); + Clock_t clock; + // uint8_t bufferConfig[] = { 0x00, 0x00, 0x01, 0x01 }; + // uint8_t bufferSetClock[] = { 0x02, 0x00, 0x00, 0x08, 0x16, 0x02, 0x08, 0x24 }; + + Rtc8563Reg_t reg; + uint8_t *pReg = (uint8_t *)(void *)® + memset(®, 0, sizeof(reg)); + + printf_P(PSTR("\n => config 8563 ... ")); + reg.reg1.field.tie = 1; + if (!rtc8563.write(pReg, 2)) { + printf_P(PSTR_ERROR); + } else { + printf_P(PSTR_Done); + } + printf_P(PSTR("\n press:")); + printf_P(PSTR("\n t .... timer on/off")); + printf_P(PSTR("\n p .... power on/off (PC7->Q1)")); + printf_P(PSTR("\n c .... init clock")); + printf_P(PSTR("\n w/W .. weekday (+/-)\n")); + printf_P(PSTR("\n y/Y .. year (+/-)")); + printf_P(PSTR("\n m/M .. month (+/-)")); + printf_P(PSTR("\n d/D .. day (+/-)")); + printf_P(PSTR("\n h/H .. hour (+/-)")); + printf_P(PSTR("\n n/N .. minute (+/-)")); + printf_P(PSTR("\n s/S .. second (+/-)\n")); + + do { + uint8_t addr = 0x00; + printf_P(PSTR("\n => read register 0-15 (hex):")); + if (!rtc8563.write_then_read(&addr, 1, pReg, sizeof(reg))) { + printf_P(PSTR_ERROR); + key = waitAndReadKey(1000); + continue; + } + memccpy(&clock, ®.clock, sizeof(clock), sizeof(clock)); + for (uint8_t i = 0; i < 16; i++) { + if (i % 4 == 0) { + printf_P(PSTR(" ")); + } + printf_P(PSTR(" %02X"), pReg[i]); + } + uint16_t year = (clock.month.field.century ? 2100 : 2000) + bcd2bin(clock.year.byte); + int8_t month = bcd2bin(clock.month.byte); + int8_t day = bcd2bin(clock.day.byte); + int8_t hrs = bcd2bin(clock.hour.byte); + int8_t min = bcd2bin(clock.min.byte); + int8_t sec = bcd2bin(clock.sec.byte); + int8_t weekday = clock.weekday.byte; + + PGM_P d = weekday >= 0 && weekday < 7 ? &PSTR_WEEKDAYS[weekday * 3] : PSTR("??"); + printf_P(PSTR(" --> ")); + printf_P(d); + printf_P(PSTR(", %d %04d-%02d-%02d %02d:%02d:%02d"), weekday, year, month, day, hrs, min, sec); + printf_P(PSTR(" - Timer=0x%02x"), reg.timer); + + key = waitAndReadKey(1000); + bool ok = true; + bool change = false; + switch (key) { + case 't': ok &= setTimer(reg.timerControl.field.enable ? 0 : 10, reg); break; + case 'c': ok &= setClock(5, 2024,8,16, 17,12,10 ); break; // ok &= rtc8563.write(bufferSetClock, sizeof(bufferSetClock)); break; + case 'p': powerOnOff(10, reg); break; + case 'y': year++; change = true; break; + case 'Y': year--; change = true; break; + case 'm': month++; change = true; break; + case 'M': month--; change = true; break; + case 'd': day++; change = true; break; + case 'D': day--; change = true; break; + case 'h': hrs++; change = true; break; + case 'H': hrs--; change = true; break; + case 'n': min++; change = true; break; + case 'N': min--; change = true; break; + case 's': sec++; change = true; break; + case 'S': sec--; change = true; break; + case 'w': weekday++; change = true; break; + case 'W': weekday--; change = true; break; + } + if (change) { + printf_P(PSTR("\n set: %04d-%02d-%02d %02d:%02d:%02d"), year, month, day, hrs, min, sec); + setClock(weekday, year, month, day, hrs, min, sec); + } + + } while (key != ESCAPE); + + return 0; + } + + return -1; +} + +bool Rtc8563::setTimer (uint8_t seconds, Rtc8563Reg_t ®) { + + reg.timerControl.field.fd = FDTIMER_1HZ; + reg.timerControl.field.enable = seconds > 0; + reg.timer = seconds; + reg.reg1.field.tie = seconds > 0; + // clear and alarm flag behavior on I2C write different to datasheet + // datasheet: tf cleared to 0, af remains unchanged + // realchip: tf remains 1 and af is set to 1 (no negative result because tie=0 and aie=0) + reg.reg1.field.tf = 0; // clear timer flag + reg.reg1.field.af = 1; // alarm flag remains unchanged + if (seconds > 0) { + printf_P(PSTR("\n Timer set to %ds (1:%02X) ... "), seconds, reg.reg1.byte); + } else { + printf_P(PSTR("\n Timer off ... ")); + } + if (rtc8563.writeByteAndBuffer(0x01, ®.reg1.byte, 1) && rtc8563.writeByteAndBuffer(14, ®.timerControl.byte, 2)) { + printf_P(PSTR("OK")); + return true; + } else { + printf_P(PSTR("fails")); + return false; + } +} + +bool Rtc8563::powerOnOff (uint8_t delayOffSeconds, Rtc8563Reg_t ®) { + int key = EOF; + if (PORTC & (1 << PC7)) { + printf_P(PSTR("\n power on ...")); + DDRC |= ( 1<< PC7); + PORTC &= ~(1 << PC7); + setTimer(0, reg); + } else { + printf_P(PSTR("\n")); + key = EOF; + for (int8_t i = 9; i > 0 && key == EOF; i--) { + printf_P(PSTR("\r press ESC to abort, power off in %ds (press key to skip timer) "), i); + key = waitAndReadKey(1000); + } + if (key == ESCAPE) { + return true; + } + setTimer(10, reg); + reg.reg1.field.af = 1; // alarm flag remains unchanged + reg.reg1.field.tf = 0; // timer flag clear + reg.reg1.field.tie = 1; // enable timer interrupt + rtc8563.writeByteAndBuffer(0x01, ®.reg1.byte, 1); + printf_P(PSTR("\n power off now ...")); + DDRC |= ( 1<< PC7); + PORTC |= (1 << PC7); + _delay_ms(5); + DDRC &= ~( 1<< PC7); + PORTC &= ~(1 << PC7); + waitAndReadKey(5000); + printf_P(PSTR("power off fails, I am still alive :-) ... proceed")); + } + return true; +} + + +bool Rtc8563::setClock (int8_t weekday, uint16_t year, int8_t month, int8_t day, int8_t hour, int8_t min, int8_t sec) { + Clock_t clock; + clock.month.field.century = (year < 2000 || year > 2100) ? 1: 0; + uint8_t y = year % 100; clock.year.field.bcdL = y % 10; clock.year.field.bcdH = y / 10; + + while (weekday < 0) { weekday += 7; } + while (weekday > 6) { weekday -= 7; } + clock.weekday.field.bcdL = weekday; + + while (month < 1) { month += 12; } + while (month > 12) { month -= 12; } + clock.month.field.bcdL = month % 10; clock.month.field.bcdH = month / 10; + + while (day < 1) { day += 31; } + while (day > 31) { day -= 31; } + clock.day.field.bcdL = day % 10; clock.day.field.bcdH = day / 10; + + while (hour < 0) { hour += 24; } + while (hour > 23) { hour -= 24; } + clock.hour.field.bcdL = hour % 10; clock.hour.field.bcdH = hour / 10; + + while (min < 0) { min += 60; } + while (min > 59) { min -= 60; } + clock.min.field.bcdL = min % 10; clock.min.field.bcdH = min / 10; + + while (sec < 0) { sec += 60; } + while (sec > 59) { sec -= 60; } + clock.sec.field.bcdL = sec % 10; clock.sec.field.bcdH = sec / 10; + + printf_P(PSTR("\n %p %p %p %p %p %p %p -> write: "), &clock.sec.byte, &clock.min.byte, &clock.hour.byte, &clock.day.byte, &clock.weekday.byte, &clock.month.byte, &clock.year.byte ); + for (uint8_t i = 0; i < sizeof(clock); i++) { + printf_P(PSTR(" %02x"), ((uint8_t *)(void *)&clock)[i]); + } + return rtc8563.writeByteAndBuffer(0x02, (uint8_t *)(void *)&clock, sizeof(clock)); +} + +#endif + diff --git a/software/test-software/src/units/rtc8563.hpp b/software/test-software/src/units/rtc8563.hpp new file mode 100644 index 0000000..ca79713 --- /dev/null +++ b/software/test-software/src/units/rtc8563.hpp @@ -0,0 +1,70 @@ +#ifndef RTC8563_HPP +#define RTC8563_HPP + +#include +#include "../main.hpp" +#include "../adafruit/bme280.h" +#include "../adafruit/ens160.h" +#include "../i2cmaster.hpp" +#include "../i2cslave.hpp" + + +class Rtc8563 : public TestUnit { + public: + typedef enum { NORMAL } Rtc8563Mode_t; + + private: + I2cMaster rtc8563; + typedef enum { FDCLOCKOUT_32768HZ = 0, FDCLOCKOUT_1024HZ = 1, FDCLOCKOUT_32HZ = 2, FDCLOCKOUT_1HZ = 3 } FDCLOCKOUT_t; + typedef enum { FDTIMER_4096HZ = 0, FDTIMER_64HZ = 1, FDTIMER_1HZ = 2, FDTIMER_1D60HZ = 3 } FDTIMER_t; + typedef struct { + union { uint8_t byte; struct { uint8_t bcdL:4; uint8_t bcdH:3; uint8_t voltageLow:1; } field; } sec; + union { uint8_t byte; struct { uint8_t bcdL:4; uint8_t bcdH:3; uint8_t notUsed:1; } field; } min; + union { uint8_t byte; struct { uint8_t bcdL:4; uint8_t bcdH:2; uint8_t notUsed:2; } field; } hour; + union { uint8_t byte; struct { uint8_t bcdL:4; uint8_t bcdH:2; uint8_t notUsed:2; } field; } day; + union { uint8_t byte; struct { uint8_t bcdL:3; } field; uint8_t notUsed:5; } weekday; + union { uint8_t byte; struct { uint8_t bcdL:4; uint8_t bcdH:1; uint8_t notUsed:2; uint8_t century:1; } field; } month; + union { uint8_t byte; struct { uint8_t bcdL:4; uint8_t bcdH:4; } field; } year; + } Clock_t; // identical to 8563 register 2..8 + + typedef struct { + union { uint8_t byte; struct { uint8_t bcdL:4; uint8_t bcdH:3; uint8_t enable:1; } field; } min; + union { uint8_t byte; struct { uint8_t bcdL:4; uint8_t bcdH:2; uint8_t notUsed:1; uint8_t enable:1; } field; } hour; + union { uint8_t byte; struct { uint8_t bcdL:4; uint8_t bcdH:2; uint8_t notUsed:1; uint8_t enable:1; } field; } day; + union { uint8_t byte; struct { uint8_t bcdL:3; } field; uint8_t notUsed:4; uint8_t enable_W:1; } weekday; + } Alarm_t; + + typedef struct { + union { uint8_t byte; struct { uint8_t notUsed210:3; uint8_t testC:1; uint8_t notUsed4:1; uint8_t stop:1; uint8_t notUsed6:1; uint8_t test1:1; } field; } reg0; + union { uint8_t byte; struct { uint8_t tie:1; uint8_t aie:1; uint8_t tf:1; uint8_t af:1; uint8_t ti_tp:1; uint8_t notUsed:3; } field; } reg1; + Clock_t clock; + Alarm_t alarm; + union { uint8_t byte; struct { FDCLOCKOUT_t fd:2; uint8_t notUsed65432:5; uint8_t enable:1; } field; } clockoutControl; + union { uint8_t byte; struct { FDTIMER_t fd:2; uint8_t notUsed65432:5; uint8_t enable:1; } field; } timerControl; + uint8_t timer; + } Rtc8563Reg_t; + + + public: + bool enabled; + + public: + Rtc8563 (Rtc8563Mode_t mode) { enabled = false; this->mode = mode; } + void tick1ms () { rtc8563.tick1ms(); } + virtual void init (); + virtual void cleanup (); + virtual int8_t run (uint8_t subtest); + virtual PGM_P getName (); + void handleTwiIrq (); + + private: + Rtc8563Mode_t mode; + uint8_t bcd2bin (uint8_t value); + int8_t runModeNormal (uint8_t subtest); + int8_t runModeBattery (uint8_t subtest); + bool setTimer (uint8_t seconds, Rtc8563Reg_t ®); + bool powerOnOff (uint8_t delayOffSeconds, Rtc8563Reg_t ®); + bool setClock (int8_t weekday, uint16_t year, int8_t month, int8_t day, int8_t hour, int8_t min, int8_t sec); +}; + +#endif \ No newline at end of file diff --git a/software/test-software/src/units/seg7.cpp b/software/test-software/src/units/seg7.cpp new file mode 100644 index 0000000..f522456 --- /dev/null +++ b/software/test-software/src/units/seg7.cpp @@ -0,0 +1,283 @@ +#include +#include + +#include "seg7.hpp" +#include "../main.hpp" + +#if defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__) + + // Nano-644 / Nano 1284 + // --------------------------------------------------------------- + + // Nano-X-Base V1a V2a + // --------------------------------- + // Anode Segment A ....... PB0 PB0 + // Anode Segment B ....... PB1 PB1 + // Anode Segment C ....... PB2 PB2 + // Anode Segment D ....... PB3 PB3 + // Anode Segment E ....... PB4 PB4 + // Anode Segment F ....... PB5 PB5 + // Anode Segment G ....... PB6 PB6 + // Anode DP .............. PB7 PB7 + // --------------------------------- + // Cathode Char 1 ........ PA0 PD4 + // Cathode Char 2 ........ PA1 PD5 + // Cathode Char 3 ........ PA2 PD6 + // Cathode Char 4 ........ PA3 PD7 + // --------------------------------- + // nOE (Output Enable) ... PD5 PA1 + // Anode L1:2 ............ PD6 PA2 + // Anode L3 .............. PD7 PA3 + +void Seg7::init () { + setAnodes(0); + setCathodes(0); + DDRB = 0xff; + switch (hardwareVersion) { + case 1: { + DDRA |= (1 << PA3) | (1 << PA2) | (1 << PA1) | (1 << PA0); + DDRD |= (1 << PD7) | (1 << PD6) | (1 << PD5); + break; + } + case 2: { + DDRA |= (1 << PA3) | (1 << PA2) | (1 << PA1); + DDRD |= (1 << PD7) | (1 << PD6) | (1 << PD5) | (1 << PD4); + } + break; + } + } + + void Seg7::cleanup () { + setAnodes(0); + setCathodes(0); + DDRB = 0x00; + switch (hardwareVersion) { + case 1: { + DDRA &= ~((1 << PA3) | (1 << PA2) | (1 << PA1) | (1 << PA0)); + DDRD &= ~((1 << PD7) | (1 << PD6) | (1 << PD5)); + break; + } + case 2: { + DDRA &= ~((1 << PA3) | (1 << PA2) | (1 << PA1)); + DDRD &= ~((1 << PD7) | (1 << PD6) | (1 << PD5) | (1 << PD4)); + } + break; + } + } + + void Seg7::setAnodes (uint16_t a) { + if (a & 0x0001) PORTB |= (1 << PB0); else PORTB &= ~(1 << PB0); // Anode Char A + if (a & 0x0002) PORTB |= (1 << PB1); else PORTB &= ~(1 << PB1); // Anode Char B + if (a & 0x0004) PORTB |= (1 << PB2); else PORTB &= ~(1 << PB2); // Anode Char C + if (a & 0x0008) PORTB |= (1 << PB3); else PORTB &= ~(1 << PB3); // Anode Char D + if (a & 0x0010) PORTB |= (1 << PB4); else PORTB &= ~(1 << PB4); // Anode Char E + if (a & 0x0020) PORTB |= (1 << PB5); else PORTB &= ~(1 << PB5); // Anode Char F + if (a & 0x0040) PORTB |= (1 << PB6); else PORTB &= ~(1 << PB6); // Anode Char G + if (a & 0x0080) PORTB |= (1 << PB7); else PORTB &= ~(1 << PB7); // Anode Char DP + switch (hardwareVersion) { + case 1: { + if (a & 0x0100) PORTD |= (1 << PD6); else PORTD &= ~(1 << PD6); // Anode L1/L2 + if (a & 0x0200) PORTD |= (1 << PD7); else PORTD &= ~(1 << PD7); // Anode L3 + break; + } + case 2: { + if (a & 0x0100) PORTA |= (1 << PA2); else PORTA &= ~(1 << PA2); // Anode L1/L2 + if (a & 0x0200) PORTA |= (1 << PA3); else PORTA &= ~(1 << PA3); // Anode L3 + break; + } + } + } + + void Seg7::setCathodes (uint8_t c) { + switch (hardwareVersion) { + case 1: { + if (c & 0x01) PORTA |= (1 << PA0); else PORTA &= ~(1 << PA0); // Chathode Char 1 (most left) + if (c & 0x02) PORTA |= (1 << PA1); else PORTA &= ~(1 << PA1); // Chathode Char 2 + if (c & 0x04) PORTA |= (1 << PA2); else PORTA &= ~(1 << PA2); // Chathode Char 3 + if (c & 0x08) PORTA |= (1 << PA3); else PORTA &= ~(1 << PA3); // Chathode Char 4 (most right) + break; + } + case 2: { + if (c & 0x01) PORTD |= (1 << PD4); else PORTD &= ~(1 << PD4); // Chathode Char 1 (most left) + if (c & 0x02) PORTD |= (1 << PD5); else PORTD &= ~(1 << PD5); // Chathode Char 2 + if (c & 0x04) PORTD |= (1 << PD6); else PORTD &= ~(1 << PD6); // Chathode Char 3 + if (c & 0x08) PORTD |= (1 << PD7); else PORTD &= ~(1 << PD7); // Chathode Char 4 (most right) + break; + } + } + } + + void Seg7::setOE (bool enabled) { + switch (hardwareVersion) { + case 1: if (enabled) PORTD &= ~(1 << PD5); else PORTD |= (1 << PD5); break; + case 2: if (enabled) PORTA &= ~(1 << PA1); else PORTA |= (1 << PA1); break; + } + } + +#endif + +#ifdef __AVR_ATmega328P__ + + // Arduino-Nano-5V + // --------------------------------------------------------------- + + // Nano-X-Base V1a V2a + // --------------------------------- + // Anode Segment A ....... PD4 PD4 + // Anode Segment B ....... PB0 PB0 + // Anode Segment C ....... PD7 PD7 + // Anode Segment D ....... PD6 PD6 + // Anode Segment E ....... PB2 PB2 + // Anode Segment F ....... PB3 PB3 + // Anode Segment G ....... PB4 PB4 + // Anode DP .............. PB5 PB5 + // --------------------------------- + // Cathode Char 1 ........ PC0 PD5 + // Cathode Char 2 ........ PC1 PB1 + // Cathode Char 3 ........ PC2 PD3 + // Cathode Char 4 ........ PC3 PD2 + // --------------------------------- + // nOE (Output Enable) ... PB1 PC1 + // Anode L1:2 ............ PD3 PC2 + // Anode L3 .............. PD2 PC3 + + + void Seg7::init () { + enabled = 1; + setAnodes(0); + setCathodes(0); + switch (hardwareVersion) { + case 1: { + DDRB |= (1 << PB5) | (1 << PB4) | (1 << PB3) | (1 << PB2) | (1 << PB1) | (1 << PB0); + DDRC |= (1 << PC3) | (1 << PC2) | (1 << PC1) | (1 << PC0); + DDRD |= (1 << PD7) | (1 << PD6) | (1 << PD4) | (1 << PD3) | (1 << PD2); + break; + } + case 2: { + DDRB |= (1 << PB5) | (1 << PB4) | (1 << PB3) | (1 << PB2) | (1 << PB1) | (1 << PB0); + DDRC |= (1 << PC3) | (1 << PC2) | (1 << PC1); + DDRD |= (1 << PD7) | (1 << PD6) | (1 << PD5) | (1 << PD4) | (1 << PD3) | (1 << PD2); + break; + } + } + + } + + void Seg7::cleanup () { + enabled = 0; + setAnodes(0); + setCathodes(0); + switch (hardwareVersion) { + case 1: { + DDRB &= ~((1 << PB5) | (1 << PB4) | (1 << PB3) | (1 << PB2) | (1 << PB1) | (1 << PB0)); + DDRC &= ~((1 << PC3) | (1 << PC2) | (1 << PC1) | (1 << PC0)); + DDRD &= ~((1 << PD7) | (1 << PD6) | (1 << PD4) | (1 << PD3) | (1 << PD2)); + break; + } + case 2: { + DDRB &= ~((1 << PB5) | (1 << PB4) | (1 << PB3) | (1 << PB2) | (1 << PB1) | (1 << PB0) ); + DDRC &= ~((1 << PC3) | (1 << PC2) | (1 << PC1)); + DDRD &= ~((1 << PD7) | (1 << PD6) | (1 << PD5) | (1 << PD4) | (1 << PD3) | (1 << PD2)); + break; + } + } + + } + + void Seg7::setAnodes (uint16_t a) { + if (a & 0x0001) PORTD |= (1 << PD4); else PORTD &= ~(1 << PD4); // Anode Char A + if (a & 0x0002) PORTB |= (1 << PB0); else PORTB &= ~(1 << PB0); // Anode Char B + if (a & 0x0004) PORTD |= (1 << PD7); else PORTD &= ~(1 << PD7); // Anode Char C + if (a & 0x0008) PORTD |= (1 << PD6); else PORTD &= ~(1 << PD6); // Anode Char D + if (a & 0x0010) PORTB |= (1 << PB2); else PORTB &= ~(1 << PB2); // Anode Char E + if (a & 0x0020) PORTB |= (1 << PB3); else PORTB &= ~(1 << PB3); // Anode Char F + if (a & 0x0040) PORTB |= (1 << PB4); else PORTB &= ~(1 << PB4); // Anode Char G + if (a & 0x0080) PORTB |= (1 << PB5); else PORTB &= ~(1 << PB5); // Anode Char DP + switch (hardwareVersion) { + case 1: { + if (a & 0x0100) PORTD |= (1 << PD3); else PORTD &= ~(1 << PD3); // Anode L1/L2 + if (a & 0x0200) PORTD |= (1 << PD2); else PORTD &= ~(1 << PD2); // Anode L3 + break; + } + case 2: { + if (a & 0x0100) PORTC |= (1 << PC2); else PORTC &= ~(1 << PC2); // Anode L1/L2 + if (a & 0x0200) PORTC |= (1 << PC3); else PORTC &= ~(1 << PC3); // Anode L3 + break; + } + } + } + + void Seg7::setCathodes (uint8_t c) { + switch (hardwareVersion) { + case 1: { + if (c & 0x01) PORTC |= (1 << PC0); else PORTC &= ~(1 << PC0); // Chathode Char 1 (most left) + if (c & 0x02) PORTC |= (1 << PC1); else PORTC &= ~(1 << PC1); // Chathode Char 2 + if (c & 0x04) PORTC |= (1 << PC2); else PORTC &= ~(1 << PC2); // Chathode Char 3 + if (c & 0x08) PORTC |= (1 << PC3); else PORTC &= ~(1 << PC3); // Chathode Char 4 (most right) + break; + } + case 2: { + if (c & 0x01) PORTD |= (1 << PD5); else PORTD &= ~(1 << PD5); // Chathode Char 1 (most left) + if (c & 0x02) PORTB |= (1 << PB1); else PORTB &= ~(1 << PB1); // Chathode Char 2 + if (c & 0x04) PORTD |= (1 << PD3); else PORTD &= ~(1 << PD3); // Chathode Char 3 + if (c & 0x08) PORTD |= (1 << PD2); else PORTD &= ~(1 << PD2); // Chathode Char 4 (most right) + break; + } + } + } + + void Seg7::setOE (bool enabled) { + switch (hardwareVersion) { + case 1: if (enabled) PORTB &= ~(1 << PB1); else PORTB |= (1 << PB1); break; + case 2: if (enabled) PORTC &= ~(1 << PC1); else PORTC |= (1 << PC1); break; + } + } + +#endif + +const char *segName[] = { "A", "B", "C", "D", "E", "F", "G", "DP" }; + + +int8_t Seg7::run (uint8_t subtest) { + if (subtest == 0) { + setCathodes(0x0f); // all segment cathodes conected to GND + setAnodes(0x3ff); // all segments ON + setOE(true); + printf_P(PSTR("ON")); + wait(2000); + setAnodes(0); + return 0; + + } else if (subtest == 1) { + printf_P(PSTR("OFF")); + wait(1000); + return 0; + + } else if (subtest == 2) { + setAnodes(0x100); // L1/L2 ON + printf_P(PSTR("L1/L2 ON")); + wait(1000); + setAnodes(0); + return 0; + + } else if (subtest == 3) { + setAnodes(0x200); // L3 ON + printf_P(PSTR("L1/L2 ON")); + wait(1000); + setAnodes(0); + return 0; + + } else if (subtest < (4 + 4 * 8)) { + uint8_t chIndex = (subtest - 4) / 8; + uint8_t segIndex = (subtest - 4) % 8; + setCathodes(1 << chIndex); + setAnodes(1 << segIndex); + printf_P(PSTR("Char %d - %s -> %02x"), chIndex, segName[segIndex], (1 << segIndex)); + wait(400); + return 0; + } + + return -1; +} + + diff --git a/software/test-software/src/units/seg7.hpp b/software/test-software/src/units/seg7.hpp new file mode 100644 index 0000000..0e71fde --- /dev/null +++ b/software/test-software/src/units/seg7.hpp @@ -0,0 +1,25 @@ +#ifndef SEG7_HPP +#define SEG7_HPP + +#include +#include "../main.hpp" +#include + +class Seg7 : public TestUnit { + public: + bool enabled; + + public: + Seg7 () { enabled = false; } + virtual void init (); + virtual void cleanup (); + virtual int8_t run (uint8_t subtest); + virtual PGM_P getName () { return PSTR("Seg7"); } + + private: + void setAnodes (uint16_t); + void setCathodes (uint8_t mask); + void setOE (bool enabled); +}; + +#endif \ No newline at end of file diff --git a/software/test-software/src/units/switch.cpp b/software/test-software/src/units/switch.cpp new file mode 100644 index 0000000..4ce9456 --- /dev/null +++ b/software/test-software/src/units/switch.cpp @@ -0,0 +1,100 @@ +#include +#include +#include + +#include "switch.hpp" +#include "../main.hpp" + +#if defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__) + + // Nano-644 + // --------------------------------------------------------------- + // PA0 ..... SW1 + // PA1 ..... SW2 + // PA2 ..... SW3 + // PA3 ..... SW4 + + void Switch::init () { + DDRA &= ~((1 << PORTA3) | (1 << PORTA2) | (1 << PORTA1) | (1 << PORTA0)); + PORTA |= (1 << PORTA3) | (1 << PORTA2) | (1 << PORTA1) | (1 << PORTA0); + } + + void Switch::cleanup () { + PORTA &= ~((1 << PORTA3) | (1 << PORTA2) | (1 << PORTA1) | (1 << PORTA0)); + DDRA &= ~((1 << PORTA3) | (1 << PORTA2) | (1 << PORTA1) | (1 << PORTA0)); + } + + bool Switch::isPressed (SWITCH sw) { + switch (sw) { + case SW1: return (PINA & ( 1 << PA0)) == 0; + case SW2: return (PINA & ( 1 << PA1)) == 0; + case SW3: return (PINA & ( 1 << PA2)) == 0; + case SW4: return (PINA & ( 1 << PA3)) == 0; + default: return false; + } + } + +#endif + +#ifdef __AVR_ATmega328P__ + + // Arduino-Nano-5V + // --------------------------------------------------------------- + // PC0 ..... SW1 + // PC1 ..... SW2 + // PC2 ..... SW3 + // PC3 ..... SW4 + + void Switch::init () { + DDRC &= ~((1 << PORTC3) | (1 << PORTC2) | (1 << PORTC1) | (1 << PORTC0)); + PORTC |= (1 << PORTC3) | (1 << PORTC2) | (1 << PORTC1) | (1 << PORTC0); + } + + void Switch::cleanup () { + PORTC &= ~((1 << PORTC3) | (1 << PORTC2) | (1 << PORTC1) | (1 << PORTC0)); + DDRC &= ~((1 << PORTC3) | (1 << PORTC2) | (1 << PORTC1) | (1 << PORTC0)); + } + + bool Switch::isPressed (SWITCH sw) { + switch (sw) { + case SW1: return (PINC & ( 1 << PC0)) == 0; + case SW2: return (PINC & ( 1 << PC1)) == 0; + case SW3: return (PINC & ( 1 << PC2)) == 0; + case SW4: return (PINC & ( 1 << PC3)) == 0; + default: return false; + } + } + +#endif + +int8_t Switch::run (uint8_t subtest) { + if (subtest < 16) { + SWITCH sw = (SWITCH)(subtest / 4); + switch (subtest % 4) { + case 1: { + if (!isPressed(sw)) { + printf_P(PSTR("Press SW%d"), sw + 1); + while (!isPressed(sw) && wait(0) == EOF) {} + wait(10); + } + return 0; + } + + case 0: case 2: { + if (isPressed(sw)) { + printf_P(PSTR("Release SW%d "), sw + 1); + while (isPressed(sw) && wait(0) == EOF) {} + wait(10); + } + return 0; + } + + case 3: { + return 0; + } + } + + } + + return -1; +} diff --git a/software/test-software/src/units/switch.hpp b/software/test-software/src/units/switch.hpp new file mode 100644 index 0000000..03bf0b2 --- /dev/null +++ b/software/test-software/src/units/switch.hpp @@ -0,0 +1,20 @@ +#ifndef SWITCH_HPP +#define SWITCH_HPP + +#include +#include "../main.hpp" +#include + +class Switch : public TestUnit { + typedef enum { SW1 = 0, SW2 = 1, SW3 = 2, SW4 = 3 } SWITCH; + + public: + Switch () {}; + virtual void init (); + virtual void cleanup (); + virtual int8_t run (uint8_t subtest); + virtual PGM_P getName () { return PSTR("Switch"); } + bool isPressed (SWITCH sw); +}; + +#endif \ No newline at end of file diff --git a/software/test-software/src/units/uart1.cpp b/software/test-software/src/units/uart1.cpp new file mode 100644 index 0000000..57e0bfb --- /dev/null +++ b/software/test-software/src/units/uart1.cpp @@ -0,0 +1,65 @@ +#include +#include +#include + +#include "uart1.hpp" +#include "../main.hpp" + +#ifdef __AVR_ATmega328P__ + void Uart1::init () {} + void Uart1::cleanup () {} + int8_t Uart1::run (uint8_t subtest) { return -1; } + void Uart1::handleRxByte (uint8_t b) {} +#endif + +#if defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__) + +int uart1_putchar(char c, FILE *stream) { + if (c == '\n') { + uart1_putchar('\r', stream); + } + loop_until_bit_is_set(UCSR1A, UDRE1); + UDR1 = c; + return 0; +} + +static FILE mystderr = { 0, 0, _FDEV_SETUP_WRITE , 0, 0, uart1_putchar, NULL, 0 }; + +void Uart1::init () { + PORTD |= (1 << PD2); // enable RxD1 pullup + UCSR1A = (1 << U2X1); + UCSR1B = (1 << RXCIE1) | (1 << RXEN1) | (1 < send text via UART1 now...")); + fprintf_P(stderr, PSTR("Hello UART1, ECHO-Modus active\n")); + } while (wait(5000) == EOF); + return 0; + } + + return -1; +} + +void Uart1::handleRxByte (uint8_t b) { + uart1_putchar(b, stderr); +} + +#endif \ No newline at end of file diff --git a/software/test-software/src/units/uart1.hpp b/software/test-software/src/units/uart1.hpp new file mode 100644 index 0000000..40437e1 --- /dev/null +++ b/software/test-software/src/units/uart1.hpp @@ -0,0 +1,21 @@ +#ifndef UART1_HPP +#define UART1_HPP + +#include +#include "../main.hpp" +#include + +class Uart1 : public TestUnit { + public: + uint8_t enabled; + + public: + Uart1 () { enabled = 0; } + virtual void init (); + virtual void cleanup (); + virtual int8_t run (uint8_t subtest); + virtual PGM_P getName () { return PSTR("Uart1"); } + void handleRxByte (uint8_t); +}; + +#endif \ No newline at end of file