Commit e5c4924d6d38a91c8d2f6a1f6105e22088b10e03 deye-sun-12k
receivedSat, 5. Apr 2025, 10:39:17 (by user sx)
Sat, 5 Apr 2025 08:39:17 +0000 (10:39 +0200)
authorManfred Steiner <sx@htl-kaindorf.at>
Sat, 5 Apr 2025 08:39:00 +0000 (10:39 +0200)
committerManfred Steiner <sx@htl-kaindorf.at>
Sat, 5 Apr 2025 08:39:00 +0000 (10:39 +0200)
67 files changed:
software/deye-sun-12k/.gdb_history [new file with mode: 0644]
software/deye-sun-12k/.gdbinit [new file with mode: 0644]
software/deye-sun-12k/.gitignore [new file with mode: 0644]
software/deye-sun-12k/.vscode/c_cpp_properties.json [new file with mode: 0644]
software/deye-sun-12k/.vscode/launch.json [new file with mode: 0644]
software/deye-sun-12k/.vscode/settings.json [new file with mode: 0644]
software/deye-sun-12k/.vscode/tasks.json [new file with mode: 0644]
software/deye-sun-12k/LICENSE [new file with mode: 0644]
software/deye-sun-12k/Makefile [new file with mode: 0644]
software/deye-sun-12k/README.md [new file with mode: 0644]
software/deye-sun-12k/create-release [new file with mode: 0755]
software/deye-sun-12k/create-release.old [new file with mode: 0755]
software/deye-sun-12k/nano-1284/Makefile [new file with mode: 0644]
software/deye-sun-12k/nano-1284/release/v2024-11-08_181806/nano-x-base_test-software_nano-m1284p_12mhz.bin [new file with mode: 0755]
software/deye-sun-12k/nano-1284/release/v2024-11-08_181806/nano-x-base_test-software_nano-m1284p_12mhz.elf [new file with mode: 0755]
software/deye-sun-12k/nano-1284/release/v2024-11-08_181806/nano-x-base_test-software_nano-m1284p_12mhz.hex [new file with mode: 0644]
software/deye-sun-12k/nano-1284/src [new symlink]
software/deye-sun-12k/nano-644/Makefile [new file with mode: 0644]
software/deye-sun-12k/nano-644/release/v2024-11-08_181803/nano-x-base_test-software_nano-m644p_12mhz.bin [new file with mode: 0755]
software/deye-sun-12k/nano-644/release/v2024-11-08_181803/nano-x-base_test-software_nano-m644p_12mhz.elf [new file with mode: 0755]
software/deye-sun-12k/nano-644/release/v2024-11-08_181803/nano-x-base_test-software_nano-m644p_12mhz.hex [new file with mode: 0644]
software/deye-sun-12k/nano-644/src [new symlink]
software/deye-sun-12k/src/adafruit/bme280.cpp [new file with mode: 0644]
software/deye-sun-12k/src/adafruit/bme280.h [new file with mode: 0644]
software/deye-sun-12k/src/adafruit/ens160.cpp [new file with mode: 0644]
software/deye-sun-12k/src/adafruit/ens160.h [new file with mode: 0644]
software/deye-sun-12k/src/adafruit/sensor.h [new file with mode: 0644]
software/deye-sun-12k/src/i2cmaster.cpp [new file with mode: 0644]
software/deye-sun-12k/src/i2cmaster.hpp [new file with mode: 0644]
software/deye-sun-12k/src/i2cslave.cpp [new file with mode: 0644]
software/deye-sun-12k/src/i2cslave.hpp [new file with mode: 0644]
software/deye-sun-12k/src/main.cpp [new file with mode: 0644]
software/deye-sun-12k/src/main.hpp [new file with mode: 0644]
software/deye-sun-12k/src/units/cc1101.cpp [new file with mode: 0644]
software/deye-sun-12k/src/units/cc1101.hpp [new file with mode: 0644]
software/deye-sun-12k/src/units/deye.cpp [new file with mode: 0644]
software/deye-sun-12k/src/units/deye.hpp [new file with mode: 0644]
software/deye-sun-12k/src/units/encoder.cpp [new file with mode: 0644]
software/deye-sun-12k/src/units/encoder.hpp [new file with mode: 0644]
software/deye-sun-12k/src/units/i2c.cpp [new file with mode: 0644]
software/deye-sun-12k/src/units/i2c.hpp [new file with mode: 0644]
software/deye-sun-12k/src/units/ieee485.cpp [new file with mode: 0644]
software/deye-sun-12k/src/units/ieee485.hpp [new file with mode: 0644]
software/deye-sun-12k/src/units/lcd.cpp [new file with mode: 0644]
software/deye-sun-12k/src/units/lcd.hpp [new file with mode: 0644]
software/deye-sun-12k/src/units/led.cpp [new file with mode: 0644]
software/deye-sun-12k/src/units/led.hpp [new file with mode: 0644]
software/deye-sun-12k/src/units/modbus.cpp [new file with mode: 0644]
software/deye-sun-12k/src/units/modbus.hpp [new file with mode: 0644]
software/deye-sun-12k/src/units/motor.cpp [new file with mode: 0644]
software/deye-sun-12k/src/units/motor.hpp [new file with mode: 0644]
software/deye-sun-12k/src/units/portexp.cpp [new file with mode: 0644]
software/deye-sun-12k/src/units/portexp.hpp [new file with mode: 0644]
software/deye-sun-12k/src/units/poti.cpp [new file with mode: 0644]
software/deye-sun-12k/src/units/poti.hpp [new file with mode: 0644]
software/deye-sun-12k/src/units/r2r.cpp [new file with mode: 0644]
software/deye-sun-12k/src/units/r2r.hpp [new file with mode: 0644]
software/deye-sun-12k/src/units/rgb.cpp [new file with mode: 0644]
software/deye-sun-12k/src/units/rgb.hpp [new file with mode: 0644]
software/deye-sun-12k/src/units/rtc8563.cpp [new file with mode: 0644]
software/deye-sun-12k/src/units/rtc8563.hpp [new file with mode: 0644]
software/deye-sun-12k/src/units/seg7.cpp [new file with mode: 0644]
software/deye-sun-12k/src/units/seg7.hpp [new file with mode: 0644]
software/deye-sun-12k/src/units/switch.cpp [new file with mode: 0644]
software/deye-sun-12k/src/units/switch.hpp [new file with mode: 0644]
software/deye-sun-12k/src/units/uart1.cpp [new file with mode: 0644]
software/deye-sun-12k/src/units/uart1.hpp [new file with mode: 0644]

diff --git a/software/deye-sun-12k/.gdb_history b/software/deye-sun-12k/.gdb_history
new file mode 100644 (file)
index 0000000..3339046
--- /dev/null
@@ -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/deye-sun-12k/.gdbinit b/software/deye-sun-12k/.gdbinit
new file mode 100644 (file)
index 0000000..139597f
--- /dev/null
@@ -0,0 +1,2 @@
+
+
diff --git a/software/deye-sun-12k/.gitignore b/software/deye-sun-12k/.gitignore
new file mode 100644 (file)
index 0000000..a959910
--- /dev/null
@@ -0,0 +1,4 @@
+.depend
+**/build
+**/dist
+**/sim
diff --git a/software/deye-sun-12k/.vscode/c_cpp_properties.json b/software/deye-sun-12k/.vscode/c_cpp_properties.json
new file mode 100644 (file)
index 0000000..87fd0ec
--- /dev/null
@@ -0,0 +1,18 @@
+{
+    "configurations": [
+        {
+            "name": "Linux AVR",
+            "includePath": [
+                "/usr/lib/avr/include/**",
+                "/usr/lib/gcc/avr/**"
+            ],
+            "defines": [],
+            "compilerPath": "/usr/bin/avr-g++",
+            "compilerArgs": [ "-mmcu=atmega1284p", "-DF_CPU=12000000", "-Os" ],
+            "cStandard": "gnu11",
+            "cppStandard": "gnu++11",
+            "intelliSenseMode": "linux-gcc-x64"
+        }
+    ],
+    "version": 4
+}
diff --git a/software/deye-sun-12k/.vscode/launch.json b/software/deye-sun-12k/.vscode/launch.json
new file mode 100644 (file)
index 0000000..f29cf2e
--- /dev/null
@@ -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/deye-sun-12k/.vscode/settings.json b/software/deye-sun-12k/.vscode/settings.json
new file mode 100644 (file)
index 0000000..58539af
--- /dev/null
@@ -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/deye-sun-12k/.vscode/tasks.json b/software/deye-sun-12k/.vscode/tasks.json
new file mode 100644 (file)
index 0000000..74fb1c7
--- /dev/null
@@ -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/deye-sun-12k/LICENSE b/software/deye-sun-12k/LICENSE
new file mode 100644 (file)
index 0000000..c9565b9
--- /dev/null
@@ -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/deye-sun-12k/Makefile b/software/deye-sun-12k/Makefile
new file mode 100644 (file)
index 0000000..6c33dbc
--- /dev/null
@@ -0,0 +1,22 @@
+.PHONY: all release clean-all clean
+
+SEP = --------------------------------------------------------
+
+all:
+       @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-644 release
+       -@make -C nano-1284 release
+
+clean-all: clean
+       test -d nano-644/release && rm -r nano-644/release
+       test -d nano-1284/release && rm -r nano-1284/release
+
+clean:
+       @make -C nano-644 clean
+       @make -C nano-1284 clean
+
diff --git a/software/deye-sun-12k/README.md b/software/deye-sun-12k/README.md
new file mode 100644 (file)
index 0000000..cfc24f0
--- /dev/null
@@ -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/deye-sun-12k/create-release b/software/deye-sun-12k/create-release
new file mode 100755 (executable)
index 0000000..90a8fff
--- /dev/null
@@ -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/deye-sun-12k/create-release.old b/software/deye-sun-12k/create-release.old
new file mode 100755 (executable)
index 0000000..225277f
--- /dev/null
@@ -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/deye-sun-12k/nano-1284/Makefile b/software/deye-sun-12k/nano-1284/Makefile
new file mode 100644 (file)
index 0000000..0c210b6
--- /dev/null
@@ -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_deye-sun-12k_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,--section-start=.text=$(START_ADDRESS) -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,--section-start=.text=$(START_ADDRESS) -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/deye-sun-12k/nano-1284/release/v2024-11-08_181806/nano-x-base_test-software_nano-m1284p_12mhz.bin b/software/deye-sun-12k/nano-1284/release/v2024-11-08_181806/nano-x-base_test-software_nano-m1284p_12mhz.bin
new file mode 100755 (executable)
index 0000000..06e910a
Binary files /dev/null and b/software/deye-sun-12k/nano-1284/release/v2024-11-08_181806/nano-x-base_test-software_nano-m1284p_12mhz.bin differ
diff --git a/software/deye-sun-12k/nano-1284/release/v2024-11-08_181806/nano-x-base_test-software_nano-m1284p_12mhz.elf b/software/deye-sun-12k/nano-1284/release/v2024-11-08_181806/nano-x-base_test-software_nano-m1284p_12mhz.elf
new file mode 100755 (executable)
index 0000000..31affaa
Binary files /dev/null and b/software/deye-sun-12k/nano-1284/release/v2024-11-08_181806/nano-x-base_test-software_nano-m1284p_12mhz.elf differ
diff --git a/software/deye-sun-12k/nano-1284/release/v2024-11-08_181806/nano-x-base_test-software_nano-m1284p_12mhz.hex b/software/deye-sun-12k/nano-1284/release/v2024-11-08_181806/nano-x-base_test-software_nano-m1284p_12mhz.hex
new file mode 100644 (file)
index 0000000..11d524a
--- /dev/null
@@ -0,0 +1,2416 @@
+:100000000C94BA070C94E4070C94E4070C94E407EE\r
+:100010000C94E4070C94E4070C94E4070C94E407B4\r
+:100020000C94E4070C94E00B0C94E4070C94E407A4\r
+:100030000C94E4070C94E4070C94E4070C94E40794\r
+:100040000C94E4070C94E4070C94E4070C94E40784\r
+:100050000C94240B0C94E4070C94E4070C94E40730\r
+:100060000C94E4070C94E4070C94A00B0C94E407A4\r
+:100070000C945B0B0C94E4070C94E4070C94E407D9\r
+:100080000C94E4070C94E4070C94E40707634236ED\r
+:10009000B79BD8A71A39685618AEBAAB558C1D3C19\r
+:1000A000B7CC5763BD6DEDFD753EF6177231BF00DD\r
+:1000B0000000803F08000000BE922449123EABAA17\r
+:1000C000AA2ABECDCCCC4C3E00000080BEABAAAA72\r
+:1000D000AA3E00000000BF000000803F00000000BA\r
+:1000E00000084178D3BB4387D1133D190E3CC3BDF3\r
+:1000F0004282AD2B3E68EC8276BED98FE1A93E4CA0\r
+:1001000080EFFFBE01C4FF7F3F00000000006E6172\r
+:100110006E00696E660000407A10F35A00A0724EBD\r
+:1001200018090010A5D4E80000E87648170000E49C\r
+:100130000B54020000CA9A3B000000E1F5050000E4\r
+:1001400080969800000040420F000000A086010049\r
+:100150000000102700000000E80300000000640019\r
+:10016000000000000A000000000001000000000084\r
+:100170002C76D888DC674F0823DFC1DFAE59E1B1A8\r
+:10018000B796E5E3E453C63AE651997696E8E6C2B7\r
+:100190008426EB898C9B62ED407C6FFCEFBC9C9FBE\r
+:1001A00040F2BAA56FA5F490055A2AF75C936B6CE0\r
+:1001B000F9676DC11BFCE0E40D47FEF520E6B500D4\r
+:1001C000D0ED902E0300943577050080841E080042\r
+:1001D00000204E0A000000C80C333333330F986EF2\r
+:1001E00012831141EF8D2114893BE65516CFFEE6AF\r
+:1001F000DB18D1844B381BF77C1D901DA4BBE42475\r
+:10020000203284725E228100C9F124ECA1E53D27F1\r
+:100210006364696E6F70737578585B000A25346487\r
+:100220003A20005D3A20000A0A5B000A53656C65BB\r
+:10023000637420756E69743A2000253378202E2E61\r
+:100240002E2000417661696C61626C6520756E6973\r
+:1002500074733A0A0A004E6F204E616E6F2D582D4E\r
+:1002600042617365206465746563746564004E6102\r
+:100270006E6F2D582D426173653A20255300202F53\r
+:100280002000202F20000A0A48617264776172659D\r
+:100290002025532064657465637465642028414497\r
+:1002A0004337483D30782530325829000A496E7668\r
+:1002B000616C6964204E616E6F2D582D42617365CB\r
+:1002C0002048617264776172652D56657273696F3B\r
+:1002D0006E3A204144433748203D20256420284180\r
+:1002E000546D65676131323834502C20332E3356CB\r
+:1002F000290A00563F3F00563261005631610044E2\r
+:100300006F6E65004552524F52000A000A3D3D3D56\r
+:100310003D3D3D3D3D3D3D3D3D3D3D3D3D3D3D3D0D\r
+:100320003D3D3D3D3D3D3D3D3D3D3D3D3D3D3D3DFD\r
+:100330003D3D0A200041546D6567613132383450CB\r
+:100340000031383A31383A3036004E6F7620203856\r
+:100350002032303234000A505441424C452025644A\r
+:100360003A203078253032780020213D2030782521\r
+:10037000303278000A00205B5741524E3A206275B5\r
+:100380006666657220746F20736D616C6C5D200011\r
+:10039000204F4B5B7265636569766520256420623A\r
+:1003A000797465735D2000204552524F525B72652F\r
+:1003B00063656976652025642062797465732C20F5\r
+:1003C0006578706563742025642062797465735D57\r
+:1003D00020005D20002030782530325800205374F2\r
+:1003E000617465735B004552525D005D002030789A\r
+:1003F00025303278000A205B726561645265676956\r
+:100400007374657273283078253032782C202E2E44\r
+:100410002E2C202564295D202D3E20004552525D62\r
+:10042000003078253032782C7374617475733D30E8\r
+:1004300078253032785D000A205B72656164526510\r
+:100440006769737465722830782530327829202DD9\r
+:100450003E20004552525D007374617475733D30E7\r
+:1004600078253032785D00202D3E20002030782520\r
+:10047000303278000A205B7772697465526567696B\r
+:10048000737465727328307825303278293A2000E9\r
+:100490004552525D007374617475733D3078253038\r
+:1004A00032785D000A205B7772697465526567690E\r
+:1004B00073746572283078253032782C2030782596\r
+:1004C00030327829202D3E20004F4B006661696C48\r
+:1004D00073004F4B2C20696E697420504154414287\r
+:1004E0004C45202E2E2E20006661696C73004F4B08\r
+:1004F0002C20696E69742072656769737465722057\r
+:100500002E2E2E20006661696C7300207265736563\r
+:100510007420434331313031202E2E2E20004343AE\r
+:100520002D313130312D3F0043432D313130312DCC\r
+:10053000546573740043432D313130312D5265635E\r
+:10054000656976650043432D313130312D53656E39\r
+:100550006400646F6E65202873746174653D307843\r
+:10056000253032782900202E2E2E200020253032F2\r
+:100570005800256420646174612062797465732079\r
+:1005800028484558293A20004552524F522C200005\r
+:100590004F4B2C200020525353493D25642C204CB6\r
+:1005A00051493D25642C204352432000202D3E20FC\r
+:1005B0000045320063616E63656C6C6564004532B2\r
+:1005C000004F4B2C2072656365697665202E2E2EB8\r
+:1005D00020003F202849444C45290063616E636533\r
+:1005E0006C6C6564004531000A205B253034785D11\r
+:1005F000203D3E207374617274202E2E2E20004FF9\r
+:100600004B004531005D202D3E2000202530325822\r
+:1006100000202D2D3E2073656E64202564206279B4\r
+:1006200074657320284845583A20253032580030E8\r
+:100630007825303278004531000A205B2530347847\r
+:100640005D3A2073746174653D006661696C730086\r
+:100650002850415441424C45203D203078253032CD\r
+:1006600058290064426D20000A207377697463681A\r
+:1006700020706F77657220746F200020757365207D\r
+:100680002B20616E64202D20666F7220706F77655D\r
+:1006900072206368616E676520286F7468657220D8\r
+:1006A0006B6579202D3E206261636B20746F20643E\r
+:1006B000656661756C742900292E06477A0E14044C\r
+:1006C0000400000600216276CAF81622F8400730BE\r
+:1006D00018166C434991876BFB5610E92A001F419D\r
+:1006E00000597F3F813509C6392E3600C0313100AF\r
+:1006F00000C531300000CD37000000863500000015\r
+:100700005030000000372D360000262D3130001DFE\r
+:100710002D313500172D323000032D3330002535B3\r
+:100720006420283078253032782920000D20203DA3\r
+:100730003E20456E636F6465722028707573682073\r
+:10074000746F20636C656172293A2000456E636F97\r
+:1007500064657200656E64000A2049324320534C80\r
+:100760004156453A2066726F6D206D6173746572F3\r
+:100770003A20307825303278202D3E20746F206D5D\r
+:1007800061737465723A20307825303278004531D3\r
+:1007900000202D3E204552524F52003078253032F5\r
+:1007A00078002C202066726F6D20736C6176653A3C\r
+:1007B0002000202D3E204552524F52000A2049323F\r
+:1007C000432D4D41535445523A20746F20736C6150\r
+:1007D00076653A203078253032780045310045334F\r
+:1007E00000290062616400706F6F72006661697257\r
+:1007F00000676F6F6400657863656C6C656E74008C\r
+:100800003F002C2065636F323D25642800292C2091\r
+:1008100074766F633D2564707062003F00756E688A\r
+:1008200065616C74687900706F6F72006D6F6465DC\r
+:100830007261746500676F6F6400657863656C6CE6\r
+:10084000656E7400206171693D25642800453200A1\r
+:10085000252E3166C2B0432F252E31662525293A33\r
+:1008600020004531290020207C20454E5331363070\r
+:100870002028002C20483D20252E32662525002CDE\r
+:1008800020543D20252E3266C2B043000A203D3E52\r
+:1008900020424D3238303A20503D20252E336662BA\r
+:1008A0006172004F4B004534004533004532004F24\r
+:1008B0004B2C20454E53313630202E2E2E20004515\r
+:1008C000310020424D323830202E2E2E2000493269\r
+:1008D000432D536C617665004932432D4D6173742D\r
+:1008E0006572004932432D537061726B66756E20DC\r
+:1008F000456E762D436F6D626F00656E64000A2051\r
+:10090000203D3E2072656365697665204279746595\r
+:100910003A20307825303278000A20203D3E20737E\r
+:10092000656E642042797465203078253032780015\r
+:100930004945454534383500656E64004552524F8F\r
+:100940005228256429004F4B004C43442000455257\r
+:10095000524F5220256429004F4B2900696E69745B\r
+:10096000204C43442028004C636400546573742079\r
+:100970004C454420442564004C656400656E640069\r
+:10098000202D3E2025342E3866560A00203078254A\r
+:10099000303278002020003F000A20202020202034\r
+:1009A00020527844313A0020307825303278000ADD\r
+:1009B000203D3E2053656E64696E673A004D6F645A\r
+:1009C0006275733A206C657365205370616E6E7545\r
+:1009D0006E6720766F6E2045617374726F6E205360\r
+:1009E000444D2D323330202845696E70686173653F\r
+:1009F0006E7AC3A4686C65722900202E2E2E20709A\r
+:100A000072657373206B657920746F2070726F63E9\r
+:100A1000656564006E6F2062797465207265636538\r
+:100A200069766564003078253032782072656365B8\r
+:100A300069766564002044453D25752C206E52453D\r
+:100A40003D25752073656E64203078253032782E10\r
+:100A50002E2E2000696E6974004D6F6462757300FC\r
+:100A600020206E6F20726F746174696F6E2028543D\r
+:100A70003D253034782920200020206E3D2025356A\r
+:100A80006420552F6D696E2028543D253034782917\r
+:100A9000002053454E534F523D25642000206E46A2\r
+:100AA00041554C543D25640020414443323D25339B\r
+:100AB0006400202050574D2F4F4330413D25336473\r
+:100AC000000D20203D3E20414443303D253364004D\r
+:100AD000454E3D3100454E3D30000D205357333DCE\r
+:100AE00025642D3E000A004D6F746F72000A2020AD\r
+:100AF00042616E6B30202D204750422564203D20FE\r
+:100B000030000A202042616E6B30202D2047504279\r
+:100B10002564203D2031000A202042616E6B302088\r
+:100B20002D204750412564203D2030000A202042DE\r
+:100B3000616E6B30202D204750412564203D2031CF\r
+:100B4000000A203D3E207374617274202E2E2E0008\r
+:100B50002900204F4B00204A5033392E322F3320AA\r
+:100B60006A756D706572656420286C656674293FCE\r
+:100B700000204552524F5200202872656164203097\r
+:100B80007825303278202D3E20307825303278009C\r
+:100B9000506F7274457870002534642028307825B1\r
+:100BA00030337829000D20203D3E204D656173755E\r
+:100BB000726520414443303A20000A00506F746946\r
+:100BC000002025332E3166203D3E205357393A36DA\r
+:100BD000203D2025642025642520642025642020D4\r
+:100BE00000253464202830782530337829000D2002\r
+:100BF000203D3E204D65617375726520414443324E\r
+:100C00003A20000A0052325200416C6C00426C756E\r
+:100C10006500477265656E00526564005267620048\r
+:100C20002025303278000A2025702025702025707C\r
+:100C3000202570202570202570202570202D3E2035\r
+:100C400077726974653A2000706F776572206F66FD\r
+:100C500066206661696C732C204920616D20737475\r
+:100C6000696C6C20616C697665203A2D29202E2EE6\r
+:100C70002E2070726F63656564000A20706F77655F\r
+:100C800072206F6666206E6F77202E2E2E000D204C\r
+:100C900070726573732045534320746F2061626FD7\r
+:100CA00072742C20706F776572206F666620696E93\r
+:100CB0002025647320287072657373206B6579201A\r
+:100CC000746F20736B69702074696D6572292000E0\r
+:100CD0000A000A20706F776572206F6E202E2E2E0C\r
+:100CE000006661696C73004F4B000A2054696D65A2\r
+:100CF00072206F6666202E2E2E20000A2054696D09\r
+:100D000065722073657420746F2025647320283108\r
+:100D10003A2530325829202E2E2E20000A207365C5\r
+:100D2000743A20253034642D253032642D2530323C\r
+:100D30006420253032643A253032643A25303264FA\r
+:100D400000202D2054696D65723D30782530327851\r
+:100D5000002C20256420253034642D253032642D6C\r
+:100D60002530326420253032643A253032643A2509\r
+:100D70003032640020202D2D3E20003F3F002025F2\r
+:100D80003032580020000A203D3E20726561642008\r
+:100D9000726567697374657220302D31352028685B\r
+:100DA0006578293A000A202020732F53202E2E2008\r
+:100DB0007365636F6E6420282B2F2D290A000A208B\r
+:100DC00020206E2F4E202E2E206D696E75746520AA\r
+:100DD000282B2F2D29000A202020682F48202E2E76\r
+:100DE00020686F757220282B2F2D29000A202020C3\r
+:100DF000642F44202E2E2064617920282B2F2D294A\r
+:100E0000000A2020206D2F4D202E2E206D6F6E7435\r
+:100E10006820282B2F2D29000A202020792F5920E7\r
+:100E20002E2E207965617220282B2F2D29000A2073\r
+:100E30002020772F57202E2E207765656B646179EF\r
+:100E400020282B2F2D290A000A20202063202E2E57\r
+:100E50002E2E20696E697420636C6F636B000A200C\r
+:100E6000202070202E2E2E2E20706F776572206F1E\r
+:100E70006E2F6F666620285043372D3E5131290072\r
+:100E80000A20202074202E2E2E2E2074696D65726B\r
+:100E9000206F6E2F6F6666000A2070726573733A5A\r
+:100EA000000A203D3E20636F6E6669672038353644\r
+:100EB00033202E2E2E20005254432D383536330049\r
+:100EC000536F004D6F004469004D6900446F004648\r
+:100ED00072005361000043686172202564202D2058\r
+:100EE0002573202D3E2025303278004C312F4C3296\r
+:100EF000204F4E004C312F4C32204F4E004F464673\r
+:100F0000004F4E00536567370052656C656173652D\r
+:100F10002053572564200050726573732053572562\r
+:100F200064005377697463680048656C6C6F205582\r
+:100F3000415254312C204543484F2D4D6F647573F9\r
+:100F4000206163746976650A000A203D3E2073655E\r
+:100F50006E6420746578742076696120554152541E\r
+:100F600031206E6F772E2E2E005561727431000085\r
+:100F7000DC3D9F3E11241FBECFEFD0E4DEBFCDBFCE\r
+:100F800012E0A0E0B1E0E2E8F5E900E00BBF02C04A\r
+:100F900007900D92A635B107D9F724E0A6E5B2E097\r
+:100FA00001C01D92A83EB207E1F717E0CAEBD7E0F7\r
+:100FB00004C02197FE010E94FC40C83BD107C9F73D\r
+:100FC0000E94453C0C94BF4A0C940000FC01108226\r
+:100FD00011820895FC019181992311F09150918320\r
+:100FE0000895FC01608384E68093B80084E08093D8\r
+:100FF000BC0081E0089584E08093BC001092B800AA\r
+:1010000008954150FB0194E824EC4F3FD1F0442374\r
+:1010100019F02093BC0002C09093BC008091BC00EA\r
+:1010200087FFFCCF8091B900887F442319F0803579\r
+:1010300019F009C0883539F48091BB008193415083\r
+:10104000E4CF81E0089580E00895DC01FB0184E8AD\r
+:1010500035E0442389F0222311F0949101C090815E\r
+:101060009093BB008093BC0011963C931197909194\r
+:10107000BC0097FFFCCF02C081E008959091B900B9\r
+:1010800041503196987F983221F380E00895FC0119\r
+:1010900084EA8093BC0085E081838091BC0087FF57\r
+:1010A000FCCF9091B900987F983011F09031B1F455\r
+:1010B0009081990F962B9093BB0084E88093BC009D\r
+:1010C00085E081838091BC0087FFFCCF9091B900BF\r
+:1010D000987F611105C081E0983129F080E0089582\r
+:1010E00081E09034D9F708950F931F93CF93DF9346\r
+:1010F000D62F8A01C22F60E00E944708811102C0EA\r
+:1011000080E016C0F80124E8D093BB002093BC0017\r
+:101110009091BC0097FFFCCF9091B900987F9832D6\r
+:1011200079F7D1919FEF9C0FCC2311F0C92FECCF11\r
+:10113000DF91CF911F910F91089584E98093BC00B6\r
+:101140008091BC0084FDFCCF81E00895FF920F9355\r
+:101150001F93CF93DF93EC018B01F42E61E00E948B\r
+:101160004708882379F04F2DB801CE010E9401086D\r
+:10117000882341F0CE01DF91CF911F910F91FF9015\r
+:101180000C949D0880E0DF91CF911F910F91FF900B\r
+:101190000895FF920F931F93CF93DF93EC018B0180\r
+:1011A000F42E60E00E944708882381F020E04F2D54\r
+:1011B000B801CE010E942508882341F0CE01DF91BD\r
+:1011C000CF911F910F91FF900C949D0880E0DF91CB\r
+:1011D000CF911F910F91FF900895FF920F931F934E\r
+:1011E000CF93DF93EC018B01F42E60E00E9447085F\r
+:1011F000882381F021E04F2DB801CE010E942508FF\r
+:10120000882341F0CE01DF91CF911F910F91FF9084\r
+:101210000C949D0880E0DF91CF911F910F91FF907A\r
+:101220000895CF92DF92EF92FF920F931F93CF9387\r
+:10123000DF93EC016B01142F790160E00E944708F5\r
+:10124000882301F120E0412FB601CE010E9425083C\r
+:101250008823C1F061E0CE010E944708882391F005\r
+:10126000402FB701CE010E940108882359F0CE011A\r
+:10127000DF91CF911F910F91FF90EF90DF90CF9072\r
+:101280000C949D0880E0DF91CF911F910F91FF900A\r
+:10129000EF90DF90CF900895FC01108211821282AE\r
+:1012A000138614860895FC019081992311F09150C2\r
+:1012B0009083089567FD0CC0660F642B6093BA009D\r
+:1012C00084E68093B80085E48093BC0081E00895B3\r
+:1012D00080E0089584E08093BC001092B8000895E7\r
+:1012E000FB012FB7F894918181E0890F8183DB01A5\r
+:1012F000A90FB11D12964C93883008F0118281819C\r
+:101300009081891305C08F5F8083883008F0108238\r
+:101310002FBF0895462FBC01655F7F4F0C94700965\r
+:10132000FB019FB7F89480812181821304C09FBF85\r
+:101330008FEF9FEF089521E0280F2083DB01A80F96\r
+:10134000B11D12968C91283018F49FBF90E008953B\r
+:101350001082FBCFBC016F5F7F4F0C9490092091EE\r
+:10136000B900287F203819F0283A49F013C040917D\r
+:10137000BB00BC016F5F7F4F0E94700909C0BC01B8\r
+:10138000655F7F4F0E94900997FD80E08093BB00CE\r
+:1013900085E801C085EC8093BC000895CF93DF936E\r
+:1013A00090915F0480915E049817D1F3E0915F04FF\r
+:1013B00081E08E0F80935F04F0E0E05AFB4FC08124\r
+:1013C000CD3009F4CAE0D0E06091E4047091E50406\r
+:1013D000CE010E948946CE01DF91CF9108950F93EF\r
+:1013E0001F93CF93C82F8B018A3019F48DE00E9490\r
+:1013F000EF098091E4049091E5040817190731F48E\r
+:101400008091C00085FFFCCFC093C60080E090E0D3\r
+:10141000CF911F910F910895089580E090E0089575\r
+:101420000895089508950895089508952FB7F8949C\r
+:101430004091900450919104452B59F4429A803880\r
+:101440003FEF930710F480589F4F9093910480933F\r
+:1014500090042FBF08952FB7F894409192045091B3\r
+:101460009304452B59F4449A80383FEF930710F4C6\r
+:1014700080589F4F90939304809392042FBF0895B8\r
+:10148000813041F0823019F487EF92E0089583EFC4\r
+:1014900092E008958BEF92E00895CF9387E68093D2\r
+:1014A0007C0087E880937A0080917A008064809342\r
+:1014B0007A0080917A0086FDFCCF1092880480919A\r
+:1014C0007900843F10F081E005C080917900803E72\r
+:1014D00018F082E080938804809188049FEF980F31\r
+:1014E000923088F0809179001F928F938CEA92E07D\r
+:1014F0009F938F930E94C546109288040F900F907F\r
+:101500000F900F9014C0C09179000E94400A1F9262\r
+:10151000CF939F938F9386E892E09F938F930E943F\r
+:10152000C5460F900F900F900F900F900F90109254\r
+:101530007C0010927A0080918804CF910895F894ED\r
+:1015400060938C0470938D0480938E0490938F0429\r
+:10155000789408950E949F0AF89480918C04909149\r
+:101560008D04A0918E04B0918F047894892B8A2BDE\r
+:101570008B2B31F08091000190910101019661F374\r
+:1015800080910001909101010895CF93DF93CFEFF7\r
+:10159000DFEFD0930101C09300010E94AA0AD0930B\r
+:1015A0000101C0930001DF91CF910895CF93DF93A4\r
+:1015B000CDB7DEB728970FB6F894DEBF0FBECDBF0C\r
+:1015C0007091800460918104509182044091830461\r
+:1015D0003091840420918504909186048091870441\r
+:1015E00079836A835B834C833D832E839F838887C3\r
+:1015F0008FB7F894E0918004709181046091820427\r
+:101600005091830440918404309185042091860494\r
+:1016100090918704E9837A836B835C834D833E8357\r
+:101620002F8398878FBF29813A814B815C816D819F\r
+:101630007E818F81988528960FB6F894DEBF0FBE05\r
+:10164000CDBFDF91CF9108951F920F920FB60F92E9\r
+:1016500011240BB60F922F933F938F939F93EF9389\r
+:10166000FF938091C600282F30E030930101209332\r
+:101670000001E0915E0491E09E0F90935E04F0E023\r
+:10168000E05AFB4F808390915E0480915F04981331\r
+:1016900005C080915F048F5F80935F04FF91EF919D\r
+:1016A0009F918F913F912F910F900BBE0F900FBE86\r
+:1016B0000F901F9018951F920F920FB60F92112442\r
+:1016C0000BB60F922F933F934F935F936F937F933C\r
+:1016D0008F939F93AF93BF93CF93EF93FF93C0915B\r
+:1016E000CE0080912D04882329F06C2F8BE294E0AA\r
+:1016F0000E943E2C80914104882329F06C2F8FE3B7\r
+:1017000094E00E94713880912804882329F06C2F7E\r
+:1017100086E294E00E946627FF91EF91CF91BF91FE\r
+:10172000AF919F918F917F916F915F914F913F9179\r
+:101730002F910F900BBE0F900FBE0F901F9018951A\r
+:101740001F920F920FB60F9211240BB60F922F9388\r
+:101750003F934F935F936F937F938F939F93AF9339\r
+:10176000BF93EF93FF9380919403882319F084E053\r
+:1017700093E00DC080910303882319F083E792E082\r
+:1017800006C080912504882329F085E993E00E9412\r
+:10179000AF2603C080E88093BC00FF91EF91BF911A\r
+:1017A000AF919F918F917F916F915F914F913F91F9\r
+:1017B0002F910F900BBE0F900FBE0F901F9018959A\r
+:1017C0001F920F920FB60F9211240BB60F922F9308\r
+:1017D0003F934F935F936F937F938F939F93AF93B9\r
+:1017E000BF93EF93FF9380915104882321F08FE4FE\r
+:1017F00094E00E94272380914A04882321F088E402\r
+:1018000094E00E94952D80918B048F5F8A3018F4AC\r
+:1018100080938B0494C010928B0480918C049091DF\r
+:101820008D04A0918E04B0918F04892B8A2B8B2B71\r
+:1018300099F080918C0490918D04A0918E04B091C8\r
+:101840008F040197A109B10980938C0490938D04B2\r
+:10185000A0938E04B0938F04209180043091810472\r
+:1018600040918204509183046091840470918504B6\r
+:101870008091860490918704A1E00E94B940209352\r
+:1018800080043093810440938204509383046093D6\r
+:1018900084047093850480938604909387048DE775\r
+:1018A00093E00E94EA078FE793E00E9453098CEED1\r
+:1018B00092E00E94EA078EEE92E00E9453098EE0C9\r
+:1018C00094E00E94EA0780E194E00E94530980912D\r
+:1018D0006A02882329F080916A02815080936A020B\r
+:1018E00080915F02882329F080915F02815080936C\r
+:1018F0005F028091900490919104892B69F080910E\r
+:101900009004909191040197909391048093900496\r
+:101910008038910508F44298809192049091930444\r
+:10192000892B69F080919204909193040197909390\r
+:101930009304809392048038910508F44498809130\r
+:10194000890490918A04019690938A048093890473\r
+:101950008838934140F098B188E0892788B910927F\r
+:101960008A0410928904FF91EF91BF91AF919F91EA\r
+:101970008F917F916F915F914F913F912F910F9038\r
+:101980000BBE0F900FBE0F901F901895CF93DF9353\r
+:10199000EC01198218828091D50481110EC085ED69\r
+:1019A00094E00E940D0A892B41F083ED94E00E949F\r
+:1019B000E60785ED94E00E94100A198A1A8A1B8AAC\r
+:1019C0001C8A88E994E09B838A8386E994E09D835E\r
+:1019D0008C8384E994E09F838E8383ED94E09983E4\r
+:1019E0008883DF91CF910895CF93DF9300D0CDB757\r
+:1019F000DEB74A83FC0180819181009739F06983C9\r
+:101A000042E0BE016F5F7F4F0E94C9080F900F90A8\r
+:101A1000DF91CF910895CF92EF920F93CF93DF9301\r
+:101A2000EC016295660F660F607C47702770822F0D\r
+:101A3000880F880F880F262F242B282B2FAB029579\r
+:101A4000000F007E88AD8F71082B08AF8E2D877038\r
+:101A5000880F880F880F9EA9292F207C9C2D9770B6\r
+:101A6000E22EE82AE92AE894E7F8EEAA40E064EFDB\r
+:101A7000CE010E94F40C48AD42954695477062EF46\r
+:101A8000CE010E94F40C9EA9492F477060E2469F48\r
+:101A900090011124892F869586958695877064E03C\r
+:101AA000869FA0011124422B532B97FB992790F975\r
+:101AB000492B65EFCE010E94F40C9FA9492F477076\r
+:101AC00080E2489F90011124892F869586958695FE\r
+:101AD000877064E0869FA0011124422B532B9295BE\r
+:101AE000969596959370492B64EFCE01DF91CF9137\r
+:101AF0000F91EF90CF900C94F40C0F93CF93DF9352\r
+:101B00001F92CDB7DEB7FC0180819181009749F02B\r
+:101B1000698301E09E012F5F3F4F41E0B9010E94C0\r
+:101B2000110989810F90DF91CF910F9108950F9343\r
+:101B3000CF93DF9300D0CDB7DEB7FC0180819181D8\r
+:101B4000009749F0698302E09E012F5F3F4F41E01B\r
+:101B5000B9010E94110989819A81982789279827BC\r
+:101B60000F900F90DF91CF910F9108950E94970DE4\r
+:101B700098278927982708950C94970D0C94B60DF3\r
+:101B80000F93CF93DF9300D01F92CDB7DEB7FC0148\r
+:101B900080819181009749F0698303E09E012F5F66\r
+:101BA0003F4F41E0B9010E94110929816A81862FC6\r
+:101BB00090E0A0E0B0E0BA2FA92F982F8827A22BA1\r
+:101BC0002B81BC01CD01622B0F900F900F90DF9104\r
+:101BD000CF910F9108956F927F928F929F92AF92C3\r
+:101BE000BF92CF92DF92EF92FF920F931F93CF930A\r
+:101BF000DF93EC019FA9892F807C803409F043C0DA\r
+:101C0000492F477060E2469F90011124892F8695E5\r
+:101C1000869586958770E4E08E9FA0011124422B63\r
+:101C2000532B9295969596959370492B64EFCE0120\r
+:101C30000E94F40C0E94D60A922E832E742E652EDA\r
+:101C400063EFCE010E947D0D83FF1FC00E94D60A64\r
+:101C5000A92CB82CC72CD62CE12CF12C00E010E0DC\r
+:101C60000E94C540203D3740410551056105710581\r
+:101C70008105910509F038F487EB9BE00197F1F7B6\r
+:101C800000C00000DDCF80E001C081E0DF91CF9196\r
+:101C90001F910F91FF90EF90DF90CF90BF90AF908A\r
+:101CA0009F908F907F906F9008951F93CF93DF93B5\r
+:101CB000EC0168E80E94B60D9E8B8D8B6AE8CE0120\r
+:101CC0000E94B60D988F8F8B6CE8CE010E94B60DE6\r
+:101CD0009A8F898F6EE8CE010E94B60D9C8F8B8FF4\r
+:101CE00060E9CE010E94B60D9E8F8D8F62E9CE0114\r
+:101CF0000E94B60D98A38F8F64E9CE010E94B60DA5\r
+:101D00009AA389A366E9CE010E94B60D9CA38BA37A\r
+:101D100068E9CE010E94B60D9EA38DA36AE9CE01AB\r
+:101D20000E94B60D98A78FA36CE9CE010E94B60D54\r
+:101D30009AA789A76EE9CE010E94B60D9CA78BA732\r
+:101D400061EACE010E947D0D8DA761EECE010E9459\r
+:101D5000B60D9FA78EA763EECE010E947D0D88ABC6\r
+:101D600064EECE010E947D0D182F65EECE010E941B\r
+:101D70007D0D90E11902900111248F70282B3AAB50\r
+:101D800029AB66EECE010E947D0D182F65EECE01C7\r
+:101D90000E947D0D90E119029001112490E044E031\r
+:101DA000959587954A95E1F7822B932B9CAB8BAB4E\r
+:101DB00067EECE010E947D0D8DABDF91CF911F911B\r
+:101DC000089563EF0E947D0D81700895CF92DF9298\r
+:101DD000EF92FF920F931F93CF93DF93EC0160ED8F\r
+:101DE0000E947D0D90E0A0E0B0E089879A87AB87E4\r
+:101DF000BC8780369105A105B10569F546EB60EE1B\r
+:101E0000CE010E94F40C8FE295E70197F1F700C034\r
+:101E10000000CE010E94E10E8111F5CFCE010E949B\r
+:101E2000550EC12CD12CE12CF12C05E010E025E061\r
+:101E300030E045E050E063E070E0CE010E940B0D21\r
+:101E40009FE729EA83E0915020408040E1F700C0FD\r
+:101E5000000081E001C080E0DF91CF911F910F91E0\r
+:101E6000FF90EF90DF90CF900895CF93DF93EC0138\r
+:101E7000888199810E94F107882329F0CE01DF91A2\r
+:101E8000CF910C94E60E80E0DF91CF9108954F92B0\r
+:101E90005F926F927F928F929F92AF92BF92CF92FA\r
+:101EA000DF92EF92FF92CF93DF93EC016AEF0E94F3\r
+:101EB000C00D6115710520E88207910509F485C000\r
+:101EC0006B017C0184E0F594E794D794C7948A95DC\r
+:101ED000D1F74D885E88C701B60128E030E040E0C8\r
+:101EE00050E00E94173F612C712CD301C201880F72\r
+:101EF000991FAA1FBB1F281B390B4A0B5B0BAF890D\r
+:101F0000B88D0E94413F4B015C01C701B60120E141\r
+:101F100030E040E050E00E94173FCA01B901641967\r
+:101F20007509860997099B01AC010E94D93E9B0166\r
+:101F3000AC017CE055954795379527957A95D1F773\r
+:101F4000A98DBA8D0E94413F2B013C01C501B4010E\r
+:101F500020E038E040E050E00E94173F69017A013C\r
+:101F6000C301B20120E030E440E050E00E94173F9E\r
+:101F7000BA01A9014C0D5D1D6E1D7F1D89899A89CD\r
+:101F8000AB89BC899A01AB01280F391F4A1F5B1F1F\r
+:101F90002D873E874F87588BA5E0B0E00E94363FE3\r
+:101FA00060587F4F8F4F9F4F20E031E040E050E07E\r
+:101FB0000E94173FCA01B9010E94314220E030E07F\r
+:101FC00048EC52E40E94814104C060E070E080EC83\r
+:101FD0009FE7DF91CF91FF90EF90DF90CF90BF9080\r
+:101FE000AF909F908F907F906F905F904F900895EB\r
+:101FF0002F923F924F925F926F927F928F929F9219\r
+:10200000AF92BF92CF92DF92EF92FF920F931F9306\r
+:10201000CF93DF93CDB7DEB76D970FB6F894DEBFE1\r
+:102020000FBECDBF1C010E94470F67EFC1010E9488\r
+:10203000C00D6F87788B898B9A8B611571058048ED\r
+:10204000910509F49AC2F10185859685A785B08925\r
+:102050006C017D01FF0CCC08DC2C76019C01AD01EC\r
+:102060006C2D7C2D8C2D9C2D345F414051096109D4\r
+:1020700071098109910929873A874B875C873B0160\r
+:102080004C0159016A017B018C010E94493F422E9B\r
+:102090003D874E875B8B6C8B7D8B8E8B9B8FD101AD\r
+:1020A0005E963C915E975D962C91932F990F990BBC\r
+:1020B000492F592F692F792F892F0E94493F0CE012\r
+:1020C0000E9479402C8F3D8F49835F8B688F798F79\r
+:1020D000582E9A8FF10130A1278D932F990F990BCC\r
+:1020E000A42CBD84CE84DB88EC88FD880E891B8DF2\r
+:1020F000492F592F692F792F892F0E94493FF22E9E\r
+:10210000032F142FB52FF62FE72FD82EE92EA0E09E\r
+:102110000E94CE4084F421503F4F4F4F5F4F6F4F8E\r
+:102120007F4F8F4F9F4FF22E032F142FB52FF62F77\r
+:10213000E72FD82EE92E2F2D302F412F5B2F6F2F19\r
+:102140007E2F8D2D9E2D08E00E949240AC8CBD8C80\r
+:10215000C980DF88E88CF98C052D1A8D0E94B0406B\r
+:1021600070588F4F9F4FD1015B96ED91FC915C971A\r
+:102170005F01C12CD12CE12CF12C8701E983BA82BB\r
+:10218000CB82DC82ED82FE820F831887C12CD12C9A\r
+:10219000E12CF12C00E010E00E94493F122F3F8B10\r
+:1021A0004983B52FF62FE72FF82E092FA0E00E94C4\r
+:1021B000CE4084F421503109410951096E4F7F4FBF\r
+:1021C0008F4F9F4F122F3F8B4983B52FF62FE72F4D\r
+:1021D000F82E092F212F3F8949815B2F6F2F7E2FEA\r
+:1021E0008F2D902F01E20E9492402D8F532E498314\r
+:1021F0005F8B688F798F8A8F9C8FA0E00E94CE4082\r
+:1022000009F4C0C1D10196963C91969795962C9170\r
+:10221000932F990F990BA42CBD84CE84DB88EC8876\r
+:10222000FD880E891B8D492F592F692F792F892FF2\r
+:102230000E94493F2D873E87442E5B8B6C8B7D8BA4\r
+:102240008E8B9B8FF10134A123A1932F990F990BB2\r
+:10225000A984BA84CB84DC8473018401492F592F6B\r
+:10226000692F792F892F0E94493F01E10E9479400F\r
+:10227000AD84BE84C42CDB88EC88FD880E891B8D60\r
+:102280000E94B04059016A017B01482E192F4F85E9\r
+:10229000588969897A8934E0759567955795479586\r
+:1022A0003A95D1F780E090E0A0E1B0E0841B950B77\r
+:1022B000A60BB70B3C014D01990C6608762C430127\r
+:1022C0009C01AD01662D762D862D962D0FE10E9485\r
+:1022D0007940722E832E942E652EB62FA72F8A87D3\r
+:1022E0009B87F10132A121A1932F990F990B492FBF\r
+:1022F000592F692F792F892F03E20E947940042DED\r
+:102300000E94B04059016A017B018C01272D382DB4\r
+:10231000492D562D6B2F7A2F8A859B850E94C540AB\r
+:10232000E5E3AE2EFCE0BF2EC12CD12CE12CF12C2C\r
+:1023300000E010E00E94493FAD8CB52CC980DF88D9\r
+:10234000E88CF98C0A8D1C8D0E94A43F2C8B3B8B52\r
+:102350002A013B014C01F22E032F142FB52DF62F2D\r
+:10236000E72DD82EE92CA0E00E94CE4084F4215025\r
+:10237000304E4F4F5F4F6F4F7F4F8F4F9F4FF22E1B\r
+:10238000032F142FB52FF62FE72FD82EE92E2F2D40\r
+:10239000302F412F5B2F6F2F7E2F8D2D9E2D0DE027\r
+:1023A0000E94924029873A874B875C876F877983A1\r
+:1023B0008D879E87D1019C963C919C979B962C91F2\r
+:1023C000932F990F990BA984BA846A017B01082F76\r
+:1023D0001E85492F592F692F792F892F0E94493F38\r
+:1023E0000E94493FF22E032F142FB52FF62FE72F0F\r
+:1023F000D82EE92EA0E00E94CE4084F4215031096D\r
+:1024000041095E4F6F4F7F4F8F4F9F4FF22E032F2B\r
+:10241000142FB52FF62FE72FD82EE92E2F2D302F82\r
+:10242000412F5B2F6F2F7E2F8D2D9E2D09E10E9456\r
+:102430009240AC88BB886201730184010E94B04065\r
+:1024400029873A874B875C876F8779838D879E873B\r
+:10245000F10132A521A5932F990F990B492F592FDF\r
+:10246000692F792F892F0E94493F122F3C8B4B8B6C\r
+:10247000B52FF62FE72FF82E092FA0E00E94CE40AF\r
+:1024800084F421503109484F5F4F6F4F7F4F8F4F7A\r
+:102490009F4F122F3C8B4B8BB52FF62FE72FF82E2B\r
+:1024A000092F212F3C894B895B2F6F2F7E2F8F2D7A\r
+:1024B000902F03E10E94924059016A017B018C0137\r
+:1024C00029853A854B855C856F8579818D859E85CB\r
+:1024D0000E94B040122F39874983B52FF62FE72F7E\r
+:1024E000F82E092FA0E00E94CE4084F421503F4FE7\r
+:1024F0004F4F5F4F6F4F7F4F8F4F9F4F122F398737\r
+:102500004983B52FF62FE72FF82E092F212F398574\r
+:1025100049815B2F6F2F7E2F8F2D902F08E00E9417\r
+:1025200092402983F32F6A017B01E82F192FD101F3\r
+:1025300097968D919C919897092E000CAA0BBB0B36\r
+:102540004C015D01BB0C8808982C54019C01AD0125\r
+:10255000682D782D882D982D04E00E947940A9805F\r
+:10256000BF2E0E2F0E94B0400E94294220E030E092\r
+:1025700040E85BE30E940B4308C060E070E080EC41\r
+:102580009FE703C060E070E0CB016D960FB6F89452\r
+:10259000DEBF0FBECDBFDF91CF911F910F91FF9096\r
+:1025A000EF90DF90CF90BF90AF909F908F907F90F3\r
+:1025B0006F905F904F903F902F9008954F925F9251\r
+:1025C0006F927F928F929F92AF92BF92CF92DF9243\r
+:1025D000EF92FF92CF93DF9300D000D000D0CDB721\r
+:1025E000DEB79E838D830E94470F6DEF8D819E81A4\r
+:1025F0000E94970DA0E0B0E0811520E89207A105A8\r
+:10260000B10509F4D3C0ED81FE8185849684A78449\r
+:10261000B088FCE29F1AF1E0AF0AB1083EE0880FF3\r
+:10262000991FAA1FBB1F3A95D1F7ED81FE8141A9E1\r
+:1026300052A9052E000C660B770B24E1440F551FA1\r
+:10264000661F771F2A95D1F76C017D01C41AD50A40\r
+:10265000E60AF70AA3A9B4A9A50194010E94413F83\r
+:10266000A7019601261B370B480B590BCA01B9016C\r
+:10267000705C8F4F9F4F412C30E8532E612C712C92\r
+:10268000A30192010E94173F29833A834B835C8305\r
+:10269000ED81FE81A0A9B0E0A50194010E94363F22\r
+:1026A00020E038E040E050E00E94173F69017A01E5\r
+:1026B000F0E8DF0EE11CF11CED81FE81A5A90A2ED8\r
+:1026C000000CBB0BA50194010E94413F812C44E00A\r
+:1026D000942EA12CB12CA50194010E94173FCA0190\r
+:1026E000B901A70196010E94D93EA50194010E945B\r
+:1026F000173F405E5F4FED81FE81A6A5B7A50E9402\r
+:10270000413F705E8F4F9F4F20E030E440E050E04B\r
+:102710000E94173F69817A818B819C810E94D93EFA\r
+:102720006B017C01A30192010E94173FCA01B9010C\r
+:102730000E94D93E9B01AC0167E0559547953795BE\r
+:1027400027956A95D1F7ED81FE81A5A5B0E00E949D\r
+:10275000363F20E130E040E050E00E94173FD701D3\r
+:10276000C601821B930BA40BB50BB7FF03C080E01F\r
+:1027700090E0DC0181309105A105F9E1BF0724F06B\r
+:1027800080E090E0A0E0B9E1BC01CD012CE095959E\r
+:102790008795779567952A95D1F70E942F4220E07B\r
+:1027A00030E040E85AE30E940B4304C060E070E070\r
+:1027B00080EC9FE726960FB6F894DEBF0FBECDBF24\r
+:1027C000DF91CF91FF90EF90DF90CF90BF90AF90CF\r
+:1027D0009F908F907F906F905F904F900895CF92D1\r
+:1027E000DF92EF92FF926A017B010E94F80F20E0D6\r
+:1027F00030E048EC52E40E948141A70196010E941A\r
+:10280000814121E03EED42E45EE30E9478439B017A\r
+:10281000AC0160E070E080E89FE30E94144120E09A\r
+:102820003AE24DE257E40E940B43FF90EF90DF90B5\r
+:10283000CF900895CF92DF92EF92FF920F931F9364\r
+:10284000CB01BA016801790120E03AE24DE257E498\r
+:102850000E9481419B01AC0160E070E080E89FE351\r
+:102860000E94144126EF38E248EA50E40E9478437F\r
+:102870009B01AC01C701B6010E9481411F910F91DC\r
+:10288000FF90EF90DF90CF900895FC0161857285F5\r
+:10289000838594850895FC0121893289438954896F\r
+:1028A000A5E0B0E00E94363F672F782F892F992747\r
+:1028B00087FD9A950E94314220E030E048EC52E4D6\r
+:1028C0000E9481410895CF93DF93EC01CB01BA01BF\r
+:1028D00020E030E048EC52E40E940B430E94F341B8\r
+:1028E000982F872F762F662725E030E040E050E0D4\r
+:1028F0000E94173F298B3A8B4B8B5C8BDF91CF91DA\r
+:1029000008950F931F93CF93DF938C01EB0188E21F\r
+:10291000FB0111928A95E9F74BE050E06BE771E01B\r
+:10292000CE010E9420461B8681E090E0A0E0B0E04E\r
+:102930008C879D87AE87BF87F80180819181092EA2\r
+:10294000000CAA0BBB0B888B998BAA8BBB8B8DE0E1\r
+:1029500090E0A0E0B0E08C8B9D8BAE8BBF8B1CA277\r
+:102960001DA21EA21FA280E090E0A0E2B2EC8C8F1C\r
+:102970009D8FAE8FBF8F80E090E0AAEAB2E4888F8F\r
+:10298000998FAA8FBB8F8AE097EDA3E2BCE388A35F\r
+:1029900099A3AAA3BBA3DF91CF911F910F91089593\r
+:1029A000CF93DF93EB0124E2FB0111922A95E9F723\r
+:1029B00044E250E060E070E0488359836A837B839F\r
+:1029C000FC0180819181092E000CAA0BBB0B8C832A\r
+:1029D0009D83AE83BF838DE090E0A0E0B0E0888768\r
+:1029E0009987AA87BB870E94D60A288B398B4A8B86\r
+:1029F0005B8B8AE994E00E94470F6C8B7D8B8E8BFA\r
+:102A00009F8B81E0DF91CF9108950F931F93CF9318\r
+:102A1000DF938C01EB0188E2FB0111928A95E9F7C3\r
+:102A20004BE050E06BE771E0CE010E9420461B8630\r
+:102A300081E090E0A0E0B0E08C879D87AE87BF8703\r
+:102A4000F80180819181092E000CAA0BBB0B888BA9\r
+:102A5000998BAA8BBB8B86E090E0A0E0B0E08C8BDA\r
+:102A60009D8BAE8BBF8B1CA21DA21EA21FA280E05D\r
+:102A700090E0A6E9B3E48C8F9D8FAE8FBF8F80E08E\r
+:102A800090E8A9E8B4E4888F998FAA8FBB8F86EA73\r
+:102A90009BE9A4E4BCE388A399A3AAA3BBA3DF9109\r
+:102AA000CF911F910F910895CF93DF93EB0124E213\r
+:102AB000FB0111922A95E9F744E250E060E070E0F2\r
+:102AC000488359836A837B83FC0180819181092E2D\r
+:102AD000000CAA0BBB0B8C839D83AE83BF8386E067\r
+:102AE00090E0A0E0B0E088879987AA87BB870E9422\r
+:102AF000D60A288B398B4A8B5B8B8AE994E00E943B\r
+:102B0000F80F20E030E048EC52E40E9481416C8BE9\r
+:102B10007D8B8E8B9F8B81E0DF91CF9108950F93FA\r
+:102B20001F93CF93DF938C01EB0188E2FB0111929D\r
+:102B30008A95E9F74BE050E06BE771E0CE010E9427\r
+:102B400020461B8681E090E0A0E0B0E08C879D8766\r
+:102B5000AE87BF87F80180819181092E000CAA0BF6\r
+:102B6000BB0B888B998BAA8BBB8B8CE090E0A0E091\r
+:102B7000B0E08C8B9D8BAE8BBF8B1CA21DA21EA2C6\r
+:102B80001FA21C8E1D8E1E8E1F8E80E090E0A8EC72\r
+:102B9000B2E4888F998FAA8FBB8F80E090E0A0E489\r
+:102BA000B0E488A399A3AAA3BBA3DF91CF911F91FF\r
+:102BB0000F910895CF93DF93EB0124E2FB01119273\r
+:102BC0002A95E9F744E250E060E070E048835983D9\r
+:102BD0006A837B83FC0180819181092E000CAA0B02\r
+:102BE000BB0B8C839D83AE83BF838CE090E0A0E021\r
+:102BF000B0E088879987AA87BB870E94D60A288B6E\r
+:102C0000398B4A8B5B8B8AE994E00E94DE126C8BD5\r
+:102C10007D8B8E8B9F8B81E0DF91CF910895CF9339\r
+:102C2000DF93EC010E94E6071A828CE78CAB8AE006\r
+:102C30008DAB8EE78EAB8FEA8FAB88AF82EA89AF20\r
+:102C40001AAE80E88BAFDF91CF910895CF93DF93D9\r
+:102C500000D0CDB7DEB74A83698342E0BE016F5F23\r
+:102C60007F4F0E94C9080F900F90DF91CF91089578\r
+:102C70000F93CF93DF931F92CDB7DEB79A0169838D\r
+:102C800001E041E0BE016F5F7F4F0E9411090F908C\r
+:102C9000DF91CF910F9108950F93CF93DF931F9200\r
+:102CA000CDB7DEB79A01698302E041E0BE016F5FF4\r
+:102CB0007F4F0E9411090F90DF91CF910F910895DE\r
+:102CC0000F931F93CF93DF9300D0CDB7DEB78A0168\r
+:102CD000AE014F5F5F4F0E944C16882341F029815F\r
+:102CE0003A81322723273227F801318320830F903E\r
+:102CF0000F90DF91CF911F910F9108950F93CF9374\r
+:102D0000DF931F92CDB7DEB76983022F9E012F5F3D\r
+:102D10003F4F41E0B9010E9411090F90DF91CF911F\r
+:102D20000F91089540EF60E10E942616EFE2F5E76B\r
+:102D30003197F1F700C0000008950F931F93CF93D0\r
+:102D4000DF9300D0CDB7DEB78C01AE014F5F5F4F90\r
+:102D500060E00E944C168FE295E70197F1F700C002\r
+:102D6000000089819A818036E1E09E0721F4F80114\r
+:102D7000128281E008C08136914021F481E0F8019F\r
+:102D8000828301C080E00F900F90DF91CF911F915F\r
+:102D90000F9108950F931F93CF93DF931F92CDB799\r
+:102DA000DEB78C0140E062E10E942616811108C066\r
+:102DB0008FE295E70197F1F700C0000080E016C0B0\r
+:102DC0004CEC62E1C8010E942616882389F38FE249\r
+:102DD00095E70197F1F700C00000AE014F5F5F4F2C\r
+:102DE00060E2C8010E943816882311F30F90DF912A\r
+:102DF000CF911F910F9108950F931F93CF93DF935E\r
+:102E000000D01F92CDB7DEB78C010E94CA1688236E\r
+:102E100059F18FE295E70197F1F700C000004EE00D\r
+:102E200062E1C8010E9426168823F1F023E0AE017A\r
+:102E30004F5F5F4F6CE4C8010E947E168823A1F0AB\r
+:102E40002981F80123839A8194839B81958391E062\r
+:102E5000273008F490E0F8019283EFE2F5E731972C\r
+:102E6000F1F700C0000007C08FE295E70197F1F786\r
+:102E700000C0000080E00F900F900F90DF91CF9185\r
+:102E80001F910F910895633021F4FC0122812223C8\r
+:102E900059F0462F60E10E942616EFE2F5E73197E0\r
+:102EA000F1F700C00000089580E00895CF93DF930C\r
+:102EB000EC0163E50E94F1078FE295E70197F1F7D6\r
+:102EC00000C00000CE010E9492168823A9F0CE0116\r
+:102ED0000E949D16882381F061E0CE010E94431775\r
+:102EE000882351F0CE010E94CA16882329F0CE0112\r
+:102EF000DF91CF910C94FC1680E0DF91CF91089583\r
+:102F0000CF93DF9361157105D9F0EC017F836E8358\r
+:102F100061E00E944317882399F0CE010E94CA16EF\r
+:102F2000882371F042EC62E1CE010E9426168823CC\r
+:102F300039F0EFE2F5E73197F1F700C0000007C084\r
+:102F40008FE295E70197F1F700C0000080E0DF9184\r
+:102F5000CF9108956F927F928F929F92AF92BF927E\r
+:102F6000CF92DF92EF920F931F93CF93DF931F9235\r
+:102F7000CDB7DEB73C01CB01342FE02FAFE2B5E790\r
+:102F80001197F1F700C0000068E170E00E94033F74\r
+:102F90008B014FEF460F4295440F440F407C311197\r
+:102FA000406221114061E1114860E110446060E439\r
+:102FB000C3010E942616882309F471C0A80141505C\r
+:102FC0005109569547955695479561E4C3010E946E\r
+:102FD0002616882309F463C0A6015695479562E436\r
+:102FE000C3010E942616882309F459C0A5015695ED\r
+:102FF000479563E4C3010E942616882309F44FC055\r
+:10300000A4015695479564E4C3010E9426168111D8\r
+:1030100046C049895A895695479565E4C3010E947F\r
+:10302000261681113CC0F3014681415066E4C3017C\r
+:103030000E942616811133C0D30116968D919C9162\r
+:103040001797019711F440E801C040E067E4C3011D\r
+:103050000E942616882319F1EFE2F5E73197F1F780\r
+:1030600000C00000AE014F5F5F4F6FE4C3010E94DC\r
+:1030700038168823A1F0AFE2B5E71197F1F700C049\r
+:103080000000F30126813781B901606C498150E06D\r
+:103090006417750729F02F5F3F4F3783268380E041\r
+:1030A0000F90DF91CF911F910F91EF90DF90CF9014\r
+:1030B000BF90AF909F908F907F906F900895AB01DD\r
+:1030C00060E20C9438160F93CF93DF931F92CDB725\r
+:1030D000DEB79B0141E2498305E041E0BE016F5F3D\r
+:1030E0007F4F0E9411090F90DF91CF910F910895AA\r
+:1030F0000F931F93CF93DF93CDB7DEB729970FB60A\r
+:10310000F894DEBF0FBECDBF8C016623F1F0AE0197\r
+:10311000475F5F4F60E2C8010E9438168823E9F0DC\r
+:1031200087EB9BE00197F1F700C00000898581FFE4\r
+:10313000EECF898581FF11C027E0AE014F5F5F4F61\r
+:1031400061E2C8010E947E1608C0AE01475F5F4F72\r
+:1031500060E20E9438168111ECCF80E029960FB60C\r
+:10316000F894DEBF0FBECDBFDF91CF911F910F91BD\r
+:1031700008950F931F93CF93DF93CDB7DEB72997B1\r
+:103180000FB6F894DEBF0FBECDBF8C016623C1F031\r
+:1031900087EB9BE00197F1F700C00000AE01475FAD\r
+:1031A0005F4F60E2C8010E943816811102C080E0C2\r
+:1031B0000AC1898580FFECCF898580FFF8CF09C0DF\r
+:1031C000AE01475F5F4F60E20E9438168111F4CF75\r
+:1031D000EECF28E0AE014F5F5F4F68E4C8010E9468\r
+:1031E0007E16882321F369817A8180E090E00E9435\r
+:1031F0002F4220E030E040E05AE30E940B439B0165\r
+:10320000AC0160E070E080E090E40E9478430E94AE\r
+:10321000FA41F8016787708B818B928B6B817C817F\r
+:1032200080E090E00E942F4220E030E040E05AE34E\r
+:103230000E940B439B01AC0160E070E080E090E4F1\r
+:103240000E9478430E94FA41F801678B708F818F4A\r
+:10325000928F6D817E8180E090E00E942F4220E07D\r
+:1032600030E040E05AE30E940B439B01AC0160E078\r
+:1032700070E080E090E40E9478430E94FA41F801F7\r
+:10328000678F70A381A392A36F81788580E090E01F\r
+:103290000E942F4220E030E040E05AE30E940B43BE\r
+:1032A0009B01AC0160E070E080E090E40E94784314\r
+:1032B0000E94FA41F80167A370A781A792A728E0AE\r
+:1032C000AE014F5F5F4F68E2C8010E947E168823FF\r
+:1032D00009F46DCF69817A8180E090E00E942F42ED\r
+:1032E00020E030E040E05AE30E940B439B01AC0138\r
+:1032F00060E070E080E090E40E9478430E94FA4130\r
+:10330000F801638B748B858B968B6B817C8180E05D\r
+:1033100090E00E942F4220E030E040E05AE30E941B\r
+:103320000B439B01AC0160E070E080E090E40E9400\r
+:1033300078430E94FA41F801638F748F858F968FCE\r
+:103340006D817E8180E090E00E942F4220E030E09D\r
+:1033500040E05AE30E940B439B01AC0160E070E047\r
+:1033600080E090E40E9478430E94FA41F80163A350\r
+:1033700074A385A396A36F81788580E090E00E9476\r
+:103380002F4220E030E040E05AE30E940B439B01D3\r
+:10339000AC0160E070E080E090E40E9478430E941D\r
+:1033A000FA41F80163A774A785A796A7AE014F5FFE\r
+:1033B0005F4F68E3C8010E943816882309F4F7CEEE\r
+:1033C0009981F80193AB29960FB6F894DEBF0FBE32\r
+:1033D000CDBFDF91CF911F910F910895CF93DF93D0\r
+:1033E00000D000D0CDB7DEB769837A834B835C838E\r
+:1033F00024E0AE014F5F5F4F63E10E9474080F90BD\r
+:103400000F900F900F90DF91CF9108958F929F9220\r
+:10341000AF92BF92CF92DF92EF92FF920F931F93E2\r
+:10342000CF93DF93EC014A015B01C901B80120E0B1\r
+:1034300030E040E054E40E940B430E94FA416B01EB\r
+:103440007C0123E333E948E853E4C501B4010E9459\r
+:10345000154120E030E040E852E40E940B430E9416\r
+:10346000FA41A601CE01DF91CF911F910F91FF90FC\r
+:10347000EF90DF90CF90BF90AF909F908F900C9483\r
+:10348000EE19FC01878190858330910540F4880F07\r
+:10349000991FFC01EC59FE4F8081918108958EE1C6\r
+:1034A00095E00895289820981CBC2C9824B12F7082\r
+:1034B00024B921B12F7C21B922B12F7C22B93E98A9\r
+:1034C0004698FC011682089560E070E0CB010E94EE\r
+:1034D000AA0A0196C9F30895611102C00E94641AF4\r
+:1034E0008FEF08956EBD0DB407FEFDCF8EB5089524\r
+:1034F000289A08952898089595B181E0892785B97B\r
+:10350000089514980895149A089583B186FB882726\r
+:1035100080F9089580B185FB882780F908952AE015\r
+:10352000FC0121871E9B06C0FC0121852111FACFD9\r
+:1035300080E0089581E0089524E6FC012187059943\r
+:1035400006C0FC0121852111FACF80E0089581E0B9\r
+:10355000089524E6FC012187059B06C0FC01218516\r
+:103560002111FACF80E0089581E008950F931F9311\r
+:10357000CF93DF93EC01162F0E94811ACE010E9497\r
+:103580008F1A082F612F6F73CE010E94721ACE011D\r
+:103590000E94831A802FDF91CF911F910F91089580\r
+:1035A000FF920F931F93CF93DF93EC01062FF42E1E\r
+:1035B0000E94811ACE010E948F1A182F602FCE010F\r
+:1035C0000E94721A6F2DCE010E94721A8A838D8119\r
+:1035D00081608D83CE010E94831A8A8580FF2BC073\r
+:1035E0001F92FF921F920F9384EA94E09F938F9310\r
+:1035F0000E94C5460F900F900F900F900F900F9064\r
+:10360000112389F08D8182FF0EC08A811F928F93D2\r
+:1036100085E994E09F938F930E94C5460F900F9089\r
+:103620000F900F9008C080E994E09F938F930E94C1\r
+:10363000C5460F900F90812FDF91CF911F910F9171\r
+:10364000FF900895AF92BF92CF92DF92EF92FF92D8\r
+:103650000F931F93CF93DF93EC01B42ED52E022F3F\r
+:103660006F73162F10640E94811ACE010E948F1A68\r
+:10367000C82E612FCE010E94721AEB2CFD2C57012F\r
+:10368000D02EDD2041F0F50161915F01CE010E9455\r
+:10369000721ADA94F6CFCE010E94831A8A8581FFCE\r
+:1036A00046C01F731F921F9384E794E09F938F93EC\r
+:1036B0000E94C5460F900F900F900F90102F8CE630\r
+:1036C000A82E84E0B82E112379F0F70181917F01B3\r
+:1036D0001F928F93BF92AF920E94C54611500F90D8\r
+:1036E0000F900F900F90EFCF87E694E09F938F930A\r
+:1036F0000E94C5460F900F90CC2089F08D8182FFEB\r
+:103700000EC08A811F928F9388E594E09F938F93D8\r
+:103710000E94C5460F900F900F900F9008C083E550\r
+:1037200094E09F938F930E94C5460F900F908C2D2D\r
+:10373000DF91CF911F910F91FF90EF90DF90CF908D\r
+:10374000BF90AF900895EF92FF920F931F93CF9386\r
+:10375000DF93EC017A016F73162F10680E94811AB3\r
+:10376000CE010E948F1A082F612FCE010E94721A7B\r
+:103770008A838D8181608D8360E0CE010E94721A00\r
+:10378000F7018083CE010E94831A8A8582FF2EC0B2\r
+:103790001F731F921F9387E394E09F938F930E9460\r
+:1037A000C5460F900F900F900F900023B9F08D81B8\r
+:1037B00080FF14C08A811F928F93F70180811F922E\r
+:1037C0008F9381E294E09F938F930E94C5460F9060\r
+:1037D0000F900F900F900F900F9008C08CE194E025\r
+:1037E0009F938F930E94C5460F900F90802FDF917B\r
+:1037F000CF911F910F91FF90EF900895AF92BF92DC\r
+:10380000CF92DF92EF92FF920F931F93CF93DF93AC\r
+:103810008C01D62FB42ED52EC22F0E94811AC8013A\r
+:103820000E948F1AC82E6D2F606CC8010E94721AF8\r
+:10383000EB2CFD2C5701DC2EDD2049F060E0C801A7\r
+:103840000E94721AF50181935F01DA94F5CFC801E5\r
+:103850000E94831AF801828583FF31C01F92CF93A3\r
+:10386000DF731F92DF9385EF93E09F938F930E9406\r
+:10387000C5460F900F900F900F900F900F90CC2097\r
+:10388000B1F00DEE13E0CC2379F0F70181917F01C7\r
+:103890001F928F931F930F930E94C546C1500F90A4\r
+:1038A0000F900F900F90EFCF8BEE93E002C086EE5B\r
+:1038B00093E09F938F930E94C5460F900F908C2D9D\r
+:1038C000DF91CF911F910F91FF90EF90DF90CF90FC\r
+:1038D000BF90AF90089521E00C94FE1B9B012053F4\r
+:1038E00031092E30310510F40C946B1C80E00895E2\r
+:1038F000AF92BF92CF92DF92EF92FF920F931F93FE\r
+:10390000CF93DF93CDB7DEB762970FB6F894DEBFE3\r
+:103910000FBECDBF8C01242F8AE0F8018187AB0157\r
+:103920006FE3C8010E94221BF82EAE014E5E5F4F6E\r
+:103930006AE370E0C8010E946B1C9A899431A1F57A\r
+:103940008F2191F165E370E0C8010E94B61AF82E4C\r
+:10395000882351F1D12CE12CAE014F5E5F4F65E31E\r
+:1039600070E0C8010E946B1CF8228989D81659F0B2\r
+:10397000FFE0FE1540F0E1E0F0E0EC0FFD1FEE0D82\r
+:10398000F11D8083E394FF2049F0833129F0F80191\r
+:103990009185D82E9111E0CFFF24F39491E08331EB\r
+:1039A00009F090E0F92241F56BE370E0C8010E9454\r
+:1039B000B61A80E009C082ED93E09F938F930E9436\r
+:1039C000C5460F900F9081E0817062960FB6F89413\r
+:1039D000DEBF0FBECDBFDF91CF911F910F91FF9042\r
+:1039E000EF90DF90CF90BF90AF900895222389F0A1\r
+:1039F000F8018185882369F0AE014E5E5F4F6AE36E\r
+:103A000070E0C8010E946B1C2A898111EFCF80E011\r
+:103A100001C081E091E0211190E0892329F2AE01FB\r
+:103A20004F5E5F4F65E370E0C8010E946B1C2989FF\r
+:103A3000882339F0213039F0F80181858111EFCFE9\r
+:103A400002C080E001C081E091E0213009F090E007\r
+:103A5000892309F4B9CF8DED93E09F938F930E9452\r
+:103A6000C546CE0101965C010F900F908C0185ED4B\r
+:103A7000C82E83E0D82E802F8A198E1508F09BCF90\r
+:103A8000F80181918F011F928F93DF92CF920E9454\r
+:103A9000C5460F900F900F900F90EDCF3F924F9231\r
+:103AA0005F926F927F928F929F92AF92BF92CF92CE\r
+:103AB000DF92EF92FF920F931F93CF93DF93CDB7D7\r
+:103AC000DEB767970FB6F894DEBF0FBECDBF6C01AF\r
+:103AD000611105C046E062E00E94D01A14C1623054\r
+:103AE00008F010C18BE796E09F938F930E94C54624\r
+:103AF0000F900F9080E090E0EE24EA94FE2C512C81\r
+:103B000034E1432E4BE0642E46E0742E55E0852EC2\r
+:103B100056E0952E2FEF30E03E8B2D8B5C013FEF72\r
+:103B2000A31AB30A9F938F9389E396E09F938F9391\r
+:103B30000E94C546AE014B5E5F4F65E370E0C60173\r
+:103B40000E946B1C0F900F900F900F90811109C075\r
+:103B500026E336E03F932F930E94C5460F900F90C7\r
+:103B60000EC08E898F938D898F93EFE2F6E0FF93DD\r
+:103B7000EF930E94C5460F900F900F900F908F8982\r
+:103B800089831F925F921F924F9281E196E09F93EB\r
+:103B90008F930E94C5468E010E5F1F4F0F900F90AE\r
+:103BA0000F900F900F900F90312C832D8A0DF801FC\r
+:103BB00081938F011F928F937F926F920E94C546CF\r
+:103BC00033940F900F900F900F90F3E13F12EDCFD1\r
+:103BD0009F928F920E94C54644E1BE016F5F7F4F66\r
+:103BE000C6010E94781C0F900F90811171C084E66D\r
+:103BF00090E00E94160A82E096E09F938F930E94C5\r
+:103C0000C5460F900F902FEFE216F20609F45EC042\r
+:103C10003BE2E316F10429F08DE2E816F10431F0FD\r
+:103C20000CC091E0951558F45A940EC0552051F0EF\r
+:103C3000E9E0E51548F0539407C0512C05C0552420\r
+:103C4000539402C08AE0582EF5E05F9E8001112453\r
+:103C50000951194F41E050E0B801CE0147960E944A\r
+:103C6000FE4588E696E09F938F930E94C5460F5FBE\r
+:103C70001F4F1F930F930E94C54683E696E09F93C4\r
+:103C80008F930E94C5464F896EE3C6010E94D01AE9\r
+:103C90000F900F900F900F900F900F90882371F05E\r
+:103CA0008F891F928F9380E596E09F938F930E9458\r
+:103CB000C5460F900F900F900F9008C08AE496E0D1\r
+:103CC0009F938F930E94C5460F900F90C50122CFFE\r
+:103CD00084E690E00E942B0A60ED77E080E090E0BF\r
+:103CE0000E94C50A7C012FEF35E03F932F930E947D\r
+:103CF000C5460F900F909BE1E916F10409F083CFC0\r
+:103D000080E001C08FEF67960FB6F894DEBF0FBE5C\r
+:103D1000CDBFDF91CF911F910F91FF90EF90DF907A\r
+:103D2000CF90BF90AF909F908F907F906F905F905B\r
+:103D30004F903F9008958F929F92AF92BF92CF92F3\r
+:103D4000DF92EF92FF920F931F93CF93DF9300D0F8\r
+:103D5000CDB7DEB78C014B015A01C22EFA01108299\r
+:103D600082E3F801818785818B7F8583AE014E5F79\r
+:103D70005F4F6BE370E0C8010E946B1CF82E882334\r
+:103D800009F446C08A818F7709F446C0D82E8FEA9D\r
+:103D900094E00197F1F700C00000AE014E5F5F4F65\r
+:103DA0006BE370E0C8010E946B1C882321F09A81AC\r
+:103DB0009F77E92E01C0ED2CF801218591E02111BA\r
+:103DC00001C090E0F92EF82219F1DE1411F0DE2C7A\r
+:103DD000DECFF80185818270D82E90E044962E2D9A\r
+:103DE00030E08217930769F19F938F93F5018081EB\r
+:103DF0001F928F9387EA93E09F938F930E94C5460B\r
+:103E0000F50110820F900F900F900F900F900F9070\r
+:103E1000F12C02C0E11056C06AE370E0C8010E94B4\r
+:103E2000B61A8F210F900F90DF91CF911F910F91B4\r
+:103E3000FF90EF90DF90CF90BF90AF909F908F90CA\r
+:103E400008959F938F9380E993E09F938F930E94AF\r
+:103E5000C5460F900F900F900F90F4E1FC1518F4E9\r
+:103E60002E2D2D1901C02C2DF5012083A4016FEFFB\r
+:103E7000C8010E94FE1BF501811102C01082C8CF4B\r
+:103E80008081E81ADE1430F686E793E09F938F93E3\r
+:103E90000E94C5460F900F90AE014F5F5F4F6FEFCE\r
+:103EA000C8010E94A31BEA94DE14B0F3DD2009F4DC\r
+:103EB000AFCF22E0A8014D5F5F4F6FEFC8010E94B6\r
+:103EC000FE1BA6CF22E0A8014D5F5F4F6FEFC80138\r
+:103ED0000E94FE1BF82E882309F49ACFF8018581F1\r
+:103EE0008460858399CF3F924F925F926F927F92C9\r
+:103EF0008F929F92AF92BF92CF92DF92EF92FF92FA\r
+:103F00000F931F93CF93DF93CDB7DEB767970FB6AD\r
+:103F1000F894DEBF0FBECDBF8C01611105C046E035\r
+:103F200062E00E94D01A61C1623008F05DC180E099\r
+:103F300090E07C012FEFE21AF20A9F938F9388EEB4\r
+:103F400095E09F938F930E94C54664E370E0C8019B\r
+:103F50000E94B61A0F900F900F900F908FEF90E085\r
+:103F60009E8B8D8BAE014B5E5F4F65E370E0C801A9\r
+:103F70000E946B1C81110EC085EE95E09F938F937C\r
+:103F80000E94C5469FE7EFE4F2E19150E040F04027\r
+:103F9000E1F714C060E070E0CB010E94AA0A01962C\r
+:103FA00091F08BED95E09F938F930E94C5468FE72C\r
+:103FB0009FE4E2E181509040E040E1F700C0000062\r
+:103FC0000F900F9019C08D899E898130910571F4F1\r
+:103FD00082ED95E09F938F930E94C546FFE72FE403\r
+:103FE00082E1F15020408040E1F7E8CF8D3091052B\r
+:103FF00019F0419709F0B2CF8D899E898D309105D6\r
+:1040000021F0419711F0C70194CF81EC95E09F9387\r
+:104010008F930E94C5460F900F9082E7482E85E04F\r
+:10402000582E96E6692E95E0792E28E8C22E25E0D6\r
+:10403000D22E30E9A32E35E0B32E41EB842E45E09D\r
+:10404000942EAE014B5E5F4F65E370E0C8010E94A5\r
+:104050006B1C81110EC0EEEBF5E0FF93EF930E9415\r
+:10406000C5468FE79FE4E2E181509040E040E1F7F0\r
+:104070002EC060E070E0CB010E94AA0A019691F088\r
+:1040800084EB95E09F938F930E94C5462FE78FE4C2\r
+:1040900092E1215080409040E1F700C000000F9075\r
+:1040A0000F90A2C0AE01495E5F4F6BE370E0C801A4\r
+:1040B0000E946B1C81110EC09F928F920E94C54678\r
+:1040C000EFE7FFE422E1E150F0402040E1F700C0DB\r
+:1040D000000071C08F89843108F46FC024E1AE0103\r
+:1040E000495E5F4FBE016F5F7F4FC8010E949B1EFC\r
+:1040F000882309F462C08F89882309F45EC084E6AE\r
+:1041000090E00E942B0A8CEA95E09F938F930E9487\r
+:10411000C546F80185810F900F9082FF24C08481ED\r
+:104120008F771F928F938381282F082E000C330BDB\r
+:104130003F938F9385E995E09F938F930E94C546A7\r
+:10414000F80184810F900F900F900F900F900F90B7\r
+:1041500087FF03C0BF92AF9202C0DF92CF920E944E\r
+:10416000C5460F900F908F891F928F935F924F9249\r
+:104170000E94C5460F900F900F900F90312C8F89A1\r
+:104180003816A8F4E1E0F0E0EC0FFD1FE30DF11D9F\r
+:1041900080811F928F938CE695E09F938F930E946E\r
+:1041A000C54633940F900F900F900F90E8CF7F92F9\r
+:1041B0006F920E94C5460F900F908D899E898D3019\r
+:1041C000910509F43ECF8131910509F43ACF9F93CF\r
+:1041D0008F9382E595E09F938F930E94C5460F9041\r
+:1041E0000F900F900F900FCF8FEF67960FB6F89448\r
+:1041F000DEBF0FBECDBFDF91CF911F910F91FF901A\r
+:10420000EF90DF90CF90BF90AF909F908F907F9076\r
+:104210006F905F904F903F900895FC01268122237C\r
+:1042200089F0278130852130310531F038F0223096\r
+:10423000310541F40C94731F0C944E1D611102C0A2\r
+:104240000E94641A8FEF0895AF92BF92CF92DF92CF\r
+:10425000EF92FF920F931F93CF93DF93CDB7DEB70B\r
+:1042600029970FB6F894DEBF0FBECDBF7C0184E75F\r
+:1042700093E09F938F930E94C54688EBC82E86E0FB\r
+:10428000D82E0F900F9010E099E6A92E93E0B92E4A\r
+:1042900041E050E0B601CE0109960E94FE45AE0114\r
+:1042A0004F5F5F4F612FC7010E94A31B89859981D2\r
+:1042B000981751F01F928F93BF92AF920E94C546FC\r
+:1042C0000F900F900F900F901F5F8FEFC81AD80AB2\r
+:1042D0001F32F1F600E310E0AE014F5F5F4FB8010F\r
+:1042E000C7010E946E1C0F5F1F4F0E331105A1F70F\r
+:1042F00028E0AE014F5F5F4F6EE3C7010E94FE1BD7\r
+:1043000029960FB6F894DEBF0FBECDBFDF91CF91D7\r
+:104310001F910F91FF90EF90DF90CF90BF90AF90E3\r
+:1043200008951F93CF93DF93EC010E94811A88E2D6\r
+:104330008A95F1F7CE010E94831A88EC8A95F1F7ED\r
+:10434000CE010E94811ACE010E948F1A182F60E3BD\r
+:1043500070E0CE010E94B61A8123DF91CF911F91A8\r
+:104360000895CF92DF92EF92FF921F93CF93DF9346\r
+:104370001F92CDB7DEB76C0188EBE82E86E0F82EF1\r
+:1043800010E041E050E0B701CE0101960E94FE45E9\r
+:104390004981612FC6010E94D01A173039F49981E2\r
+:1043A00092FF04C0F6019581926095831F5F882378\r
+:1043B00031F08FEFE81AF80A1F3219F781E00F90F9\r
+:1043C000DF91CF911F91FF90EF90DF90CF900895F4\r
+:1043D0005F926F927F928F929F92AF92BF92CF9295\r
+:1043E000DF92EF92FF920F931F93CF93DF93CDB79E\r
+:1043F000DEB728970FB6F894DEBF0FBECDBF4C01D5\r
+:104400008E010F5F1F4FE12CF12C60E0702EC12E4A\r
+:1044100086E5A82E83E0B82EDD24D394D60E6E2C2C\r
+:104420005F2C85E0689FB00111246951794F41E00C\r
+:1044300050E0C8010E94FE45EAE0ED1508F4D12CD9\r
+:10444000F401828584FF10C0F80180811F928F9350\r
+:104450005F926F92BF92AF920E94C5460F900F90ED\r
+:104460000F900F900F900F90FFEFEF1AFF0A0F5F62\r
+:104470001F4F88E0E816F10411F06D2DCDCF28E034\r
+:10448000472D5C2D6EE3C4010E94221B28960FB6B7\r
+:10449000F894DEBF0FBECDBFDF91CF911F910F917A\r
+:1044A000FF90EF90DF90CF90BF90AF909F908F9054\r
+:1044B0007F906F905F900895CF93DF93EC012898E1\r
+:1044C000209A0E94781A3E9A469A8BE291E00197D0\r
+:1044D000F1F700C00000CE010E947A1A80916400BA\r
+:1044E000847080936400149A0C9A2C9A269884B154\r
+:1044F000806B84B980E58CBD159A0D988BE095E0B2\r
+:104500009F938F930E94C546CE010E9491210F90E8\r
+:104510000F90811103C085E095E01FC08EEE94E0FE\r
+:104520009F938F930E94C546CE010E94B1210F90A8\r
+:104530000F90811103C088EE94E00FC082ED94E0EB\r
+:104540009F938F930E94C546CE010E94E8210F9051\r
+:104550000F90811107C08CEC94E09F938F930E9481\r
+:10456000C5460EC089EC94E09F938F930E94C54688\r
+:1045700081E08E838FEF8A87CE010E9424211A86E4\r
+:104580000F900F90DF91CF91089524B1287F24B927\r
+:1045900025B1276025B921E0FC0122830895FC01A3\r
+:1045A000128284B1887F84B985B1887F85B90895E6\r
+:1045B000EF92FF920F931F93CF93DF9361112CC063\r
+:1045C000EC010CE217E08EE1E82E87E0F82E6AE0BD\r
+:1045D00070E080E090E00E94AA0A0196F9F41F932F\r
+:1045E0000F930E94C5468B811F928F93282F082E10\r
+:1045F000000C330B3F938F93FF92EF920E94C546BE\r
+:104600008DB79EB708960FB6F8949EBF0FBE8DBFAC\r
+:104610001A99DDCF1B82DBCF8FEF01C080E0DF91E5\r
+:10462000CF911F910F91FF90EF90089583B182FB7E\r
+:10463000882780F991E08927089583B1809581705A\r
+:10464000089583B18695817091E089270895FC01D2\r
+:104650008281811102C01382089533B191E039271C\r
+:10466000379533273795330F330B23B126952170B8\r
+:104670002927279522272795220F220B80E030FB40\r
+:1046800080F920FB81F990911F0198279370D1F454\r
+:1046900090911E0190FD0EC0982791FF0BC0938151\r
+:1046A00081FD04C09F3729F09F5F03C0903809F057\r
+:1046B0009150938380911E0130FB80F920FB81F99A\r
+:1046C00080931E0180911F0130FB80F920FB81F94E\r
+:1046D00080931F010895FC018281938183309105AD\r
+:1046E00040F4880F991FFC01E659FE4F80819181AB\r
+:1046F00008958AE991E00895E8EBF0E02DE0208349\r
+:104700002CE1208324E6208324E02093BC0020E6D3\r
+:1047100020937C0027E820937A0080579F4F21E068\r
+:10472000FC012083089580579F4FFC01108284E094\r
+:104730008093BC001092B80010927C0010927A0016\r
+:1047400008952F923F924F925F926F927F928F9235\r
+:104750009F92AF92BF92CF92DF92EF92FF920F9310\r
+:104760001F93CF93DF93CDB7DEB761970FB6F89461\r
+:10477000DEBF0FBECDBF8C016111A5C2FC018281DD\r
+:104780009381009709F0E8C182EC98E09F938F93A2\r
+:104790000E94C54698012C5F3F4F3D872C8767E7F5\r
+:1047A000C9010E94350F0F900F90811103C08FEB4C\r
+:1047B00098E08BC28FEA98E09F938F930E94C54642\r
+:1047C00058013DE3A30EB11CC5010E9456170F907E\r
+:1047D0000F90811103C08CEA98E077C262E0C501B6\r
+:1047E0000E944317811103C089EA98E06EC200E07D\r
+:1047F00010E022E832E440E050E068EC71E4C501EA\r
+:104800000E94061A811103C086EA98E05EC283EA1C\r
+:1048100098E09F938F930E94C5460F900F908FEF63\r
+:104820008F83412C512C32014E865F86688A798AAB\r
+:104830008C859D850E94F80F20E030E543EC57E41D\r
+:104840000E9481419F938F937F936F93ECE8F8E0F0\r
+:10485000FF93EF930E94C5468C859D850E94470F6C\r
+:1048600068877987382E292E9F938F9339853F93B8\r
+:1048700088858F93EFE7F8E0FF93EF930E94C5469A\r
+:104880008C859D850E94DE124B018A879B879F93B2\r
+:104890008F939F926F9383E798E09F938F930E94EB\r
+:1048A000C5460FB6F894DEBF0FBECDBF3F813F3F78\r
+:1048B00009F19A858B85282D392D492F582FFC0118\r
+:1048C000682D792D8F2F9E2F0E94C843811112C011\r
+:1048D00078856985C101272F362F492F582FDB0195\r
+:1048E000F1016B2F7A2F8F2F9E2F0E94C8438823B0\r
+:1048F00009F4FBC165E0C62ED12CE12CF12C05E0BA\r
+:1049000010E025E030E045E050E063E070E08C85A9\r
+:104910009D850E940B0D8F81803208F413C1E6E65D\r
+:10492000F8E0FF93EF930E94C5460F900F903F81F0\r
+:1049300013162CF5632F330F770B880B990B0E94FE\r
+:1049400031426B017C019B01AC01C301B2010E94A9\r
+:1049500081414B018A879B87A70196016E857F85E0\r
+:10496000888999890E94814168877987382E292E04\r
+:10497000412C512C32014E865F86688A798A9A854D\r
+:104980008B85082D192D292F382FF885E985C10130\r
+:104990004F2F5E2F692F722DC5010E94061A8111BB\r
+:1049A00005C082E698E09F938F93C7C08B858F9355\r
+:1049B0009A859F939F928F922F923F92E985EF93D2\r
+:1049C000F885FF9320E538E03F932F930E94C5467A\r
+:1049D00062E0C5010E9443170FB6F894DEBF0FBE18\r
+:1049E000CDBF811103C08DE498E093C014E687EC3D\r
+:1049F0009FEA0197F1F700C00000BE016A5F7F4F98\r
+:104A0000C5010E945F18882309F48AC08E8181FF46\r
+:104A100087C0BE016F5F7F4FC5010E946318882366\r
+:104A200009F481C089811F928F93E4E4F8E0FF9339\r
+:104A3000EF930E94C5460F900F900F900F908981C1\r
+:104A4000833091F038F4813061F0823099F485E35D\r
+:104A500098E012C0843059F0853061F48DE198E01F\r
+:104A60000BC08AE398E008C08CE298E005C087E2BA\r
+:104A700098E002C08BE198E09F938F930E94C54617\r
+:104A80000F900F908B818F938A818F938DE098E0A8\r
+:104A90009F938F930E94C5468D818F938C818F93B6\r
+:104AA00022E038E03F932F930E94C5468C819D8180\r
+:104AB0000FB6F894DEBF0FBECDBF8039F1E09F077F\r
+:104AC00018F480E098E01DC0883522E0920718F4C1\r
+:104AD00086EF97E016C0803233E0930718F481EF39\r
+:104AE00097E00FC0883EE3E09E0718F48CEE97E055\r
+:104AF00008C08C3D954018F487EE97E002C083EE25\r
+:104B000097E09F938F930E94C5460F900F9081EE80\r
+:104B100097E09F938F930E94C5460F900F9003C01C\r
+:104B2000115009F064CF61E0C5010E944317811163\r
+:104B300008C02EED37E03F932F930E94C5460F909B\r
+:104B40000F901F8268EE73E080E090E00E94AA0A56\r
+:104B5000019609F46DCEC1C08130910509F071C094\r
+:104B600007581F4F61E0C8010E94F107811103C07F\r
+:104B70008BED97E0AAC09CEB692E97E0792E22EB93\r
+:104B8000E22E27E0F22E32EAC32E37E0D32E41E99F\r
+:104B9000A42E47E0B42E5BE9852E57E0952E809138\r
+:104BA0007A00806480937A0080917A0086FDFCCF41\r
+:104BB0008091790089831F928F937F926F920E94D8\r
+:104BC000C54641E0BE016F5F7F4FC8010E94C90822\r
+:104BD0000F900F900F900F90811106C0FF92EF92EF\r
+:104BE0000E94C5460F900F90DF92CF920E94C5465B\r
+:104BF00041E0BE016F5F7F4FC8010E94A6080F9081\r
+:104C00000F90882361F089811F928F939F928F92DA\r
+:104C10000E94C5460F900F900F900F9006C0BF9254\r
+:104C2000AF920E94C5460F900F9068EE73E080E04F\r
+:104C300090E00E94AA0A019609F4B1CF0E94FB07F6\r
+:104C40004CC0029709F03FC005581F4F40E061E09B\r
+:104C5000C8010E945A09811103C08EE897E035C04F\r
+:104C600088E5C82E87E0D82EC8010E94AA097C01D9\r
+:104C70000196F1F080917A00806480937A008091AF\r
+:104C80007A0086FDFCCF60917900C8010E948A09F4\r
+:104C9000809179001F928F93FF92EF92DF92CF92D3\r
+:104CA0000E94C5460F900F900F900F900F900F909D\r
+:104CB00060E070E0CB010E94AA0A0196A9F2C80147\r
+:104CC0000E946A090AC084E597E09F938F930E942F\r
+:104CD000C5460F900F908FEF29C064EF71E080E020\r
+:104CE00090E00E94AA0A80E021C078856985C10110\r
+:104CF000272F362F492F582F6E857F8588899989D0\r
+:104D00000E9415416E877F87888B998B9A858B854A\r
+:104D1000282D392D492F582FC301B2010E9415416A\r
+:104D20002B013C018F818F5F8F83E4CD61960FB69D\r
+:104D3000F894DEBF0FBECDBFDF91CF911F910F91D1\r
+:104D4000FF90EF90DF90CF90BF90AF909F908F90AB\r
+:104D50007F906F905F904F903F902F900895FC014F\r
+:104D6000228133812230310541F4579A5F9A855868\r
+:104D70009F4F0E94AF095F9808958091BC008068A2\r
+:104D80008093BC00089520E620937C0027E82093C0\r
+:104D90007A00289A299824B1236024B95A9A22E0EB\r
+:104DA0002093C80028E92093C90026E02093CA0078\r
+:104DB0001092CD002BE92093CC0021E0FC0122834E\r
+:104DC0000895FC01128210927C0010927A001092D9\r
+:104DD000C8001092C9001092CA001092CD00109223\r
+:104DE000CC005A9884B18C7F84B985B18C7F85B909\r
+:104DF0000895CF92DF92EF92FF920F931F93CF937C\r
+:104E0000DF938C0161114EC02898299889E1E82E22\r
+:104E100089E0F82ECC24CA94DC2CCEEFD8E064EFE5\r
+:104E200071E080E090E00E94AA0A019609F044C077\r
+:104E300080917A00806480937A0080917A0086FD68\r
+:104E4000FCCF8091C80080648093C800289A299A7A\r
+:104E5000809179008093CE008091C80086FFFCCFBE\r
+:104E600029982898809179001F928F93FF92EF9252\r
+:104E70000E94C546F894F80183819481D482C3824C\r
+:104E800078940F900F900F900F9097FDC8CF9F933D\r
+:104E90008F93DF93CF930E94C5460F900F900F9092\r
+:104EA0000F90BDCF8AEF98E09F938F930E94C546E5\r
+:104EB0000F900F908FEF01C080E0DF91CF911F9195\r
+:104EC0000F91FF90EF90DF90CF90089570E0FC017C\r
+:104ED0007483638308955F9A08955F9808955E9A36\r
+:104EE00008955E980895139A0895139808958FEF82\r
+:104EF00084B9089580918804813019F48FEF84B9C2\r
+:104F0000089514B8089580918804813041F487EBA6\r
+:104F10009BE00197F1F700C0000080E0089583B1A5\r
+:104F2000089565B90895109A0895109808951F93EB\r
+:104F3000CF93DF93EC01162F0E9475278FEF84B972\r
+:104F40008A81882389F0812F807F85B9CE010E94D4\r
+:104F500073278CE38A95F1F7CE010E94752784E0D0\r
+:104F60008A95F1F71295107F15B9CE010E9473272B\r
+:104F70008CE38A95F1F7CE010E94752784E08A952B\r
+:104F8000F1F7DF91CF911F9108951F93CF93DF9396\r
+:104F9000EC01162F0E947127CE010E946D27612F10\r
+:104FA000CE01DF91CF911F910C949727EF92FF9242\r
+:104FB0000F931F93CF93DF93EC017B018B8187FDD0\r
+:104FC00059C080918804813041F487EB9BE00197C0\r
+:104FD000F1F700C0000081E04EC0CE010E947A27A8\r
+:104FE0008FEF85B9CE010E946F27CE010E946D27F9\r
+:104FF00094E09A95F1F7CE010E9473278CE38A958D\r
+:10500000F1F7CE010E948327082FCE010E94752759\r
+:1050100094E09A95F1F7CE010E9473278CE38A956C\r
+:10502000F1F7CE010E94832782958F70007F182FA1\r
+:10503000102BCE010E94752794E09A95F1F7CE01CE\r
+:105040000E947127912F90788BE0E816F10430F0E0\r
+:105050008BE0E81AF10811F09111C4CF8B818130F7\r
+:1050600021F4992311F08BEF8B8315B88FEF84B95E\r
+:1050700081E0911180E0DF91CF911F910F91FF901E\r
+:10508000EF900895CF93DF93EC0162E370E00E940C\r
+:10509000D627811102C08AEF8B83DF91CF910895CB\r
+:1050A0001F93CF93DF93EC01162F0E944228612FAC\r
+:1050B0006068CE010E94C527CE01DF91CF911F917C\r
+:1050C0000C9442281F93CF93DF93EC0115B88FEF18\r
+:1050D00084B98FE79BEB0197F1F700C000001B82BA\r
+:1050E00010E08A81882311F068E201C068E0CE01F7\r
+:1050F0000E94C527111105C087E99AE30197F1F7CE\r
+:1051000004C08BE291E00197F1F700C000001F5F3F\r
+:10511000143039F76CE0CE010E94C52762E370E0DD\r
+:10512000CE010E94D627811102C08FEF1BC06CE018\r
+:10513000CE010E94C52762E370E0CE010E94D6270F\r
+:10514000811102C08DEF0EC061E0CE010E94C52723\r
+:1051500060EB74E0CE010E94D627811102C08CEF73\r
+:1051600001C081E08B83DF91CF911F910895CF9390\r
+:10517000DF93EC0181B1896081B98FEF84B98AB185\r
+:10518000806C8AB9CE010E9462288CE599E09F93D9\r
+:105190008F930E94C5468B810F900F90813049F408\r
+:1051A00088E599E09F938F930E94C5460F900F90DA\r
+:1051B00010C0282F082E000C330B3F938F938EE4E2\r
+:1051C00099E09F938F930E94C5460F900F900F9088\r
+:1051D0000F90CE01DF91CF910C949327CF93DF9363\r
+:1051E000FC012381213061F4EC010E9442286CE033\r
+:1051F000CE010E94C527CE01DF91CF910C944228A9\r
+:10520000DF91CF910895CF93DF93FC01238121306B\r
+:1052100061F4EC010E94422868E0CE010E94C5279B\r
+:10522000CE01DF91CF910C944228DF91CF91089568\r
+:10523000CF93DF93FC012381213061F4EC010E94C4\r
+:10524000422861E0CE010E94C527CE01DF91CF91B7\r
+:105250000C944228DF91CF9108950E94182982B1C1\r
+:10526000867F82B981B1867F81B915B814B88BB1B8\r
+:105270008F738BB98AB18F738AB90895CF93DF93F7\r
+:10528000EC018B818130B9F44431A8F4613039F0FC\r
+:1052900048F0623031F0633071F44C5A03C0405C26\r
+:1052A00001C04C5E642FCE010E945028CE01DF91D8\r
+:1052B000CF910C944228DF91CF9108951F93CF9303\r
+:1052C000DF93FC0123812130A1F4162FEC010E9411\r
+:1052D0007127CE010E946B27612FCE010E94972774\r
+:1052E000CE010E946D27CE01DF91CF911F910C94CA\r
+:1052F0004228DF91CF911F910895FF920F931F9342\r
+:10530000CF93DF938C0161114FC0C0E084E1F82E90\r
+:10531000D0E2DC0F8C2F6F2D0E94E93E911105C069\r
+:1053200040E0682FC8010E943E296D2FC8010E94ED\r
+:105330005E29C8010E944228CF5FC03549F789E441\r
+:1053400099E09F938F930E94C546F80183810F9047\r
+:105350000F90813049F486E499E09F938F930E94E7\r
+:10536000C5460F900F9010C0282F082E000C330B4D\r
+:105370003F938F938CE399E09F938F930E94C54650\r
+:105380000F900F900F900F9061E070E080E090E040\r
+:105390000E94AA0A0196C1F364EF71E080E090E0F8\r
+:1053A0000E94AA0A80E009C088E399E09F938F9346\r
+:1053B0000E94C5460F900F908FEFDF91CF911F9104\r
+:1053C0000F91FF9008950F931F93CF93DF93EC01FC\r
+:1053D0008B01F80161918F01662339F08B81813057\r
+:1053E00021F4CE010E945E29F4CFDF91CF911F916D\r
+:1053F0000F9108958BB18F708BB98AB1806F8AB984\r
+:1054000008958AB18F708AB98BB18F708BB9089566\r
+:105410008130910549F030F08230910539F00397E1\r
+:1054200039F008955C9A08955D9A08955E9A0895FA\r
+:105430005F9A0895CB0141110C94082A61307105DF\r
+:1054400051F038F06230710541F06330710539F088\r
+:1054500008955C9808955D9808955E9808955F9802\r
+:1054600008956130710559F038F06230710551F0DE\r
+:105470006330710559F008959BB180E105C09BB17F\r
+:1054800080E202C09BB180E4892702C08BB18058C2\r
+:105490008BB90895CB010C94082A40E00C941A2A89\r
+:1054A000CF936031E8F5C62FC370C23091F0C3309E\r
+:1054B000B9F0C13039F063E070E00E944D2A80E01D\r
+:1054C00090E014C060E070E00E944D2A81E090E01E\r
+:1054D0000DC061E070E00E944D2A82E090E006C0BD\r
+:1054E00062E070E00E944D2A83E090E00E94082A6A\r
+:1054F0006C2F70E06F5F7F4F7F936F938BE699E027\r
+:105500009F938F930E94C54664EF71E080E090E026\r
+:105510000E94AA0A0F900F900F900F9080E001C098\r
+:105520008FEFCF9108950895FC0112821092C80068\r
+:105530001092C9001092CA001092CD001092CC00B7\r
+:105540005A9884B18C7F84B985B18C7F85B90895D0\r
+:105550002F923F924F925F926F927F928F929F9283\r
+:10556000AF92BF92CF92DF92EF92FF920F931F9371\r
+:10557000CF93DF9300D000D0CDB7DEB79C838B8371\r
+:10558000611121C0289A299884B1836084B95A9AFC\r
+:1055900082E08093C80088E98093C90086E0809308\r
+:1055A000CA001092CD008BE98093CC0081E0EB81A2\r
+:1055B000FC81828384E59AE09F938F930E94C54685\r
+:1055C0000F900F903DC18FEF860F843008F06EC0B2\r
+:1055D000633039F0643041F0623051F41EE801E08C\r
+:1055E00009C015E500E002C01AEA01E0F12C04C090\r
+:1055F00011E000E0FF24F3941F921F931F92FF928B\r
+:105600001F920F9385E39AE09F938F930E94C54664\r
+:105610000FB6F894DEBF0FBECDBFFF2011F0289A61\r
+:1056200001C02898002311F0299A01C02998EBE2C3\r
+:10563000F1E03197F1F700C00000EB81FC811382AB\r
+:105640001093CE0087EB9BE00197F1F700C00000BC\r
+:105650008381882389F084811F928F9385E29AE069\r
+:105660009F938F930E94C546EB81FC8113820F901C\r
+:105670000F900F900F9008C084E19AE09F938F9352\r
+:105680000E94C5460F900F908AEF99E09F938F93E9\r
+:105690000E94C5460F900F906FEF7FEFCB010E94E5\r
+:1056A000AA0A0196C9F32998289ACAC0653009F058\r
+:1056B000BDC08DEB99E09F938F930E94C546299AB8\r
+:1056C00028988BE291E00197F1F700C000000F905D\r
+:1056D0000F908FEA282E89E0382E97EA492E99E01C\r
+:1056E000592E29E9622E29E0722E37E9832E39E0FE\r
+:1056F000932E44E9E42E49E0F42E5CE8C52E59E0EF\r
+:10570000D52E60E8A62E69E0B62E299AEB81FC81A1\r
+:10571000138200E711E0F8018091C8008064809353\r
+:10572000C80081918093CE008091C80085FFFCCF96\r
+:1057300021E0E837F20781F78091C80086FFFCCFAF\r
+:1057400029983F922F920E94C5460F900F90F80122\r
+:1057500081918F011F928F935F924F920E94C54655\r
+:105760000F900F900F900F90F1E008371F0779F717\r
+:1057700064E670E080E090E00E94AA0A9A83898340\r
+:105780007F926F920E94C5460F900F90EB81FC8133\r
+:105790008381882311F010E01FC09F928F920E9496\r
+:1057A000C5460F900F901DC0183031F4FF92EF9254\r
+:1057B0000E94C5460F900F90EB81FC81E10FF11D17\r
+:1057C00084811F928F93DF92CF920E94C5461F5F04\r
+:1057D0000F900F900F900F90EB81FC818381181731\r
+:1057E00018F3EB81FC818381803190F0828991896B\r
+:1057F000208937853F932F939F938F93BF92AF92CA\r
+:105800000E94C5460F900F900F900F900F900F9031\r
+:1058100089819A810196A1F468EE73E080E090E0BE\r
+:105820000E94AA0A019609F470CF0AC08CE799E099\r
+:105830009F938F930E94C5460F900F908FEF07C0E4\r
+:1058400064EF71E080E090E00E94AA0A80E00F908F\r
+:105850000F900F900F90DF91CF911F910F91FF90BC\r
+:10586000EF90DF90CF90BF90AF909F908F907F9000\r
+:105870006F905F904F903F902F900895FC0123818F\r
+:10588000203130F431E0320F3383E20FF11D6483B5\r
+:105890000895579810927C0010927A0014BC15BCA1\r
+:1058A00024B1277E24B91398FC011282089580B197\r
+:1058B00083FB882780F991E0892708952C98089523\r
+:1058C0002C9A0895CF93DF93EC01579A80E680934A\r
+:1058D0007C0087E880937A0083E884BD84E085BDFE\r
+:1058E00084B1886184B9139ACE010E94602C81E052\r
+:1058F0008A83DF91CF9108952F923F924F925F92CA\r
+:105900006F927F928F929F92AF92BF92CF92DF92CF\r
+:10591000EF92FF920F931F93CF93DF936111E1C03A\r
+:10592000EC0185EE9AE09F938F930E94C5460F90FD\r
+:105930000F9085ED482E8AE0582E91EC692E9AE062\r
+:10594000792E02EB1AE028EAE22E2AE0F22E3DE957\r
+:10595000C32E3AE0D32E41E9A42E4AE0B42E50E6FD\r
+:10596000252E5AE0352E69E7862E6AE0962E6AE0EB\r
+:1059700070E080E090E00E94AA0A019609F0B3C0AE\r
+:1059800080B183FB882780F91F928F938AED9AE07C\r
+:105990009F938F930E94C5460F900F900F900F908A\r
+:1059A000CE01039905C00E945E2C5F924F9206C003\r
+:1059B0000E94602C80ED9AE09F938F930E94C546D1\r
+:1059C0000F900F9080917A00806480937A0080918C\r
+:1059D0007A0086FDFCCF809179001F928F937F9291\r
+:1059E0006F920E94C54682EE80937C008091790080\r
+:1059F00090E005970F900F900F900F9097FF02C0C7\r
+:105A000080E090E0809587BD1F928F931F930F9346\r
+:105A10000E94C54680917A00806480937A000F903E\r
+:105A20000F900F900F9080917A0086FDFCCF8091AF\r
+:105A300079001F928F93FF92EF920E94C54690E6E5\r
+:105A400090937C0083B182FB882780F91F928F930B\r
+:105A5000DF92CF920E94C54683B181701F928F93CF\r
+:105A6000BF92AF920E94C546F8946B817C81789476\r
+:105A70008DB79EB70C960FB6F8949EBF0FBE8DBF24\r
+:105A80006115710519F17F936F9380E090E00E949A\r
+:105A90002F429B01AC0160E070E080E792E40E943D\r
+:105AA000814127E137EB41ED58E30E9481410E949B\r
+:105AB000F3417F936F939F928F920E94C5460F9000\r
+:105AC0000F900F900F900F900F9051CF1F921F9239\r
+:105AD0003F922F920E94C5460F900F900F900F900B\r
+:105AE00046CF8FEF01C080E0DF91CF911F910F91E2\r
+:105AF000FF90EF90DF90CF90BF90AF909F908F90EE\r
+:105B00007F906F905F904F903F902F90089583B15A\r
+:105B100082FB882780F991E08927089583B18170FD\r
+:105B200008958BB180588BB908951F93CF93DF935D\r
+:105B3000EC0123B18091DD049091DE04122F1170ED\r
+:105B400020FD1BC02091E104222309F12091DF04F4\r
+:105B50003091E00423303105D0F0820F931F9C83F5\r
+:105B60008B831092E0041092DF041092DE041092F6\r
+:105B7000DD04CE010E94912D0AC0811520E4920718\r
+:105B800048F501969093DE048093DD040DC080916A\r
+:105B9000DF049091E004811520E49207F0F401966F\r
+:105BA0009093E0048093DF048091DD049091DE0403\r
+:105BB0008115904438F48091DF049091E0048115C0\r
+:105BC000904410F01C821B821093E104DF91CF916E\r
+:105BD0001F91089580E090E4D5CF80E090E4E0CF7D\r
+:105BE000E4E6F0E0808184708083179A0F9A2C9A03\r
+:105BF00084B1806B84B926988CB583658CBD08957B\r
+:105C0000269884B18F7584B90F9817981CBC089595\r
+:105C100017980895179A08950F931F93CF93DF93C2\r
+:105C2000EC01062F142F0E94082E80E48EBD0DB4C7\r
+:105C300007FEFDCF0EBD0DB407FEFDCF1EBD0DB49A\r
+:105C400007FEFDCFCE010E940A2E84E18A95F1F76E\r
+:105C500080E0DF91CF911F910F9108951F93CF9313\r
+:105C6000DF93EC01162F0E94082E81E48EBD0DB447\r
+:105C700007FEFDCF1EBD0DB407FEFDCF1EBC0DB44B\r
+:105C800007FEFDCFCE010E940A2E8EB5DF91CF9187\r
+:105C90001F910895CF93DF93C42FD22F1F924F935C\r
+:105CA0001F926F9388E79BE09F938F930E94C54656\r
+:105CB0000F900F900F900F900F900F90CD1769F0ED\r
+:105CC00081E79BE09F938F930E94C5460F900F90B2\r
+:105CD000CF3F59F486E59BE002C082E59BE09F93AD\r
+:105CE0008F930E94C5460F900F9080E59BE09F9395\r
+:105CF0008F930E94C5460F900F90DF91CF9108952A\r
+:105D00002F923F924F925F926F927F928F929F92CB\r
+:105D1000AF92BF92CF92DF92EF92FF920F931F93B9\r
+:105D2000CF93DF936111D8C0EC0181E4282E8BE082\r
+:105D3000382ECC24C394D12C2CE2422E2BE0522EB0\r
+:105D400037E1632E3BE0732E42E0A42E4BE0B42EED\r
+:105D50005DEE852E5AE0952E64EF71E080E090E0D4\r
+:105D60000E94AA0A019609F0B9C03F922F920E94A0\r
+:105D7000C5460F900F90E12CF12C86010E2C01C02E\r
+:105D8000000F0A94EAF7402F409560E0CE010E9490\r
+:105D90000C2E402F62E1CE010E940C2EFF92EF925A\r
+:105DA0005F924F920E94C54662E1CE010E942E2E64\r
+:105DB000202F482F62E1CE010E944A2E68EC70E04D\r
+:105DC00080E090E00E94AA0A40E062E1CE010E94D9\r
+:105DD0000C2EFF92EF927F926F920E94C54662E175\r
+:105DE000CE010E942E2E20E0482F62E1CE010E94BB\r
+:105DF0004A2E4FEF60E0CE010E940C2E68EC70E05E\r
+:105E000080E090E00E94AA0A8FEFE81AF80A8DB7A6\r
+:105E10009EB708960FB6F8949EBF0FBE8DBF98E050\r
+:105E2000E916F10409F0A9CF00E010E07601002E98\r
+:105E300001C0EE0C0A94EAF74E2D409561E0CE01C8\r
+:105E40000E940C2E4E2D63E1CE010E940C2E1F935A\r
+:105E50000F93BF92AF920E94C54663E1CE010E94AC\r
+:105E60002E2E2E2D482F63E1CE010E944A2E68EC83\r
+:105E700070E080E090E00E94AA0A40E063E1CE0179\r
+:105E80000E940C2E1F930F939F928F920E94C546E3\r
+:105E900063E1CE010E942E2E20E0482F63E1CE0167\r
+:105EA0000E944A2E4FEF61E0CE010E940C2E68EC5A\r
+:105EB00070E080E090E00E94AA0A0F5F1F4F8DB74C\r
+:105EC0009EB708960FB6F8949EBF0FBE8DBF0830E0\r
+:105ED000110509F0ABCF40CF8FEF01C080E0DF911B\r
+:105EE000CF911F910F91FF90EF90DF90CF90BF90D7\r
+:105EF000AF909F908F907F906F905F904F903F906A\r
+:105F00002F90089580E480937C0087E880937A0046\r
+:105F1000089510927C0010927A0008950F931F93B9\r
+:105F2000CF93DF9361113AC08AEB9BE09F938F93ED\r
+:105F30000E94C5460F900F9005EA1BE0C8E9DBE020\r
+:105F40006AE070E080E090E00E94AA0A019641F5C4\r
+:105F50001F930F930E94C54680917A0080648093BE\r
+:105F60007A000F900F9080917A0086FDFCCF2091EF\r
+:105F700078003091790080917800909179003F937A\r
+:105F80002F939F938F93DF93CF930E94C5460F90DB\r
+:105F90000F900F900F900F900F90D2CF8FEF01C006\r
+:105FA00080E0DF91CF911F910F91089582E480935B\r
+:105FB0007C0087E880937A00089510927C0010920C\r
+:105FC0007A000895AF92BF92CF92DF92EF92FF9244\r
+:105FD0000F931F93CF93DF9361117FC083E09CE009\r
+:105FE0009F938F930E94C5460F900F903EEEE32E35\r
+:105FF0003BE0F32E01EE1BE0C1ECDBE06AE070E079\r
+:1060000080E090E00E94AA0A019609F068C0FF9221\r
+:10601000EF920E94C54680917A00806480937A0056\r
+:106020000F900F9080917A0086FDFCCF2091780030\r
+:106030003091790080917800909179003F932F936F\r
+:106040009F938F931F930F930E94C5466091780092\r
+:106050007091790080E090E00E942F422AE939E9AE\r
+:1060600041E852E40E9481412DEC3CEC4CE05FE3BE\r
+:106070000E941541D62EC72EB82EA92EA601950135\r
+:10608000652F742F832F922F0E94FA41862F90E064\r
+:1060900061701F926F9381FB222720F91F922F932B\r
+:1060A00082FB222720F91F922F9323E09595879555\r
+:1060B0002A95E1F79F938F93AF92BF92CF92DF9291\r
+:1060C000DF93CF930E94C5468DB79EB744960FB617\r
+:1060D000F8949EBF0FBE8DBF91CF8FEF01C080E0BF\r
+:1060E000DF91CF911F910F91FF90EF90DF90CF90B4\r
+:1060F000BF90AF900895442371F06130710539F07D\r
+:1061000020F06230710529F00895289808952998A3\r
+:1061100008952A9808956130710539F020F06230B1\r
+:10612000710529F00895289A0895299A08952A9AC0\r
+:1061300008956130710541F020F06230710539F049\r
+:10614000089595B181E005C095B182E002C095B196\r
+:1061500084E0892785B9089541E00C947B3040E0C4\r
+:106160000C947B30CF93DF93EC0160E070E00E94F1\r
+:10617000AF3061E070E0CE010E94AF3062E070E0CD\r
+:10618000CE010E94AF3084B1876084B9DF91CF9196\r
+:106190000895CF93DF93EC0160E070E00E94AF3090\r
+:1061A00061E070E0CE010E94AF3062E070E0CE01AD\r
+:1061B0000E94AF3084B1887F84B9DF91CF91089578\r
+:1061C000CF93DF93EC01613009F43FC058F16230A6\r
+:1061D00009F44EC0633009F064C060E070E00E94D2\r
+:1061E000AC3061E070E0CE010E94AC3062E070E063\r
+:1061F000CE010E94AC3089E09CE09F938F930E9477\r
+:10620000C54668EB7BE080E090E00E94AA0A60E06F\r
+:1062100070E0CE010E94AF3061E070E0CE010E94DC\r
+:10622000AF3036C060E070E00E94AC3088E19CE0A6\r
+:106230009F938F930E94C54668EB7BE080E090E0DF\r
+:106240000E94AA0A60E070E025C061E070E00E9450\r
+:10625000AC3082E19CE09F938F930E94C54668EB2F\r
+:106260007BE080E090E00E94AA0A61E070E012C04A\r
+:1062700062E070E00E94AC308DE09CE09F938F93D1\r
+:106280000E94C54668EB7BE080E090E00E94AA0A8D\r
+:1062900062E070E0CE010E94AF300F900F9080E07E\r
+:1062A00001C08FEFDF91CF91089547983F9AE8EBB7\r
+:1062B000F0E02DE020832CE1208324E6208324E0FD\r
+:1062C0002093BC0021E0FC0124830895FC0114828A\r
+:1062D00084E08093BC001092B800089587EB9EE0A4\r
+:1062E0000895ECEBF0E08081806880830895862F2C\r
+:1062F0008695869586958E71982F990F990F890F9F\r
+:106300006F70860F08950F931F93CF93DF938C01C7\r
+:10631000EA019E859C7F92609E8781E0611101C0A9\r
+:1063200080E09E8580FB97F99E876F87998180FB2F\r
+:1063300090F99B7F98609983662389F01F929F93C1\r
+:106340001F926F938BEF9CE09F938F930E94C546A3\r
+:106350000F900F900F900F900F900F9008C08AEE43\r
+:106360009CE09F938F930E94C5460F900F900E5F05\r
+:106370001F4F21E0AE014F5F5F4F61E0C8010E94F7\r
+:1063800074088823A1F0AE01425F5F4F22E06EE007\r
+:10639000C8010E947408C82F882349F087EE9CE04A\r
+:1063A0009F938F930E94C5460F900F9009C081EE76\r
+:1063B0009CE09F938F930E94C5460F900F90C0E082\r
+:1063C0008C2FDF91CF911F910F910895CF92DF9283\r
+:1063D000EF92FF920F931F93CF93DF937C01EA011B\r
+:1063E000479B10C082ED9CE09F938F930E94C5460F\r
+:1063F0003F9A4798AE0160E0C7010E9483310F9039\r
+:106400000F905CC080ED9CE09F938F930E94C546E7\r
+:106410000F900F9009E010E08EE8C82E8CE0D82E87\r
+:106420001F930F93DF92CF920E94C54668EE73E0F0\r
+:1064300080E090E00E94C50A0F900F900F900F909F\r
+:106440000130110531F0015011098F3F2FEF9207F4\r
+:1064500039F34B9799F1AE016AE0C7010E9483318D\r
+:10646000898188608B7F81608983AE014F5F5F4F38\r
+:1064700021E061E0C70102960E9474088AE79CE06F\r
+:106480009F938F930E94C5463F9A479A87E99AE364\r
+:106490000197F1F700C000003F98479868E873E162\r
+:1064A00080E090E00E94C50A88E49CE09F938F936F\r
+:1064B0000E94C5460F900F900F900F9081E0DF91E2\r
+:1064C000CF911F910F91FF90EF90DF90CF900895A3\r
+:1064D0008F929F92AF92BF92CF92DF92EF92FF92F4\r
+:1064E0000F931F93CF93DF93CDB7DEB727970FB6E8\r
+:1064F000F894DEBF0FBECDBF4C01362FCA011E2D52\r
+:10650000FC2DEA2DBA01605D774051E065367105DA\r
+:1065100008F450E04E8150FB47F94E8364E670E08A\r
+:106520000E94033F6AE00E94E93E8295807F982B9B\r
+:106530009F8337FF02C0395FFCCF373014F03750EC\r
+:10654000FCCF37708D81887F382B3D83121614F075\r
+:10655000245FFCCF2D3014F02C50FCCF822F6AE04A\r
+:106560000E94F53E9F702E81207F922B80FB94F934\r
+:106570009E83101614F0015EFCCF003214F00F5110\r
+:10658000FCCF802F6AE00E94F53E9F703C81307CFA\r
+:106590008370282F2295207F832F892B822B8C8339\r
+:1065A00017FF02C0185EFCCF183114F01851FCCF51\r
+:1065B000812F6AE00E94F53E9F703B81307C8370A2\r
+:1065C000282F2295207F832F892B822B8B83F7FF07\r
+:1065D00002C0F45CFCCFFC3314F0FC53FCCF8F2FD3\r
+:1065E0006AE00E94F53E9F703A8130788770282FCC\r
+:1065F0002295207F832F892B822B8A83E7FF02C07D\r
+:10660000E45CFCCFEC3314F0EC53FCCF8E2F6AE04B\r
+:106610000E94F53E9F70398130788770282F22952F\r
+:10662000207F832F892B822B8983CE0107969F930E\r
+:106630008F9301979F938F9301979F938F930197C8\r
+:106640009F938F9301979F938F9301979F938F931E\r
+:106650008E010F5F1F4F1F930F9386E29CE09F9365\r
+:106660008F930E94C54678015E0188E0A80EB11C98\r
+:106670000FB6F894DEBF0FBECDBF80E2C82E8CE00F\r
+:10668000D82EF70181917F011F928F93DF92CF92D5\r
+:106690000E94C5460F900F900F900F90AE14BF044C\r
+:1066A00081F727E0A80162E0C40102960E94740805\r
+:1066B00027960FB6F894DEBF0FBECDBFDF91CF9106\r
+:1066C0001F910F91FF90EF90DF90CF90BF90AF9010\r
+:1066D0009F908F9008952F923F924F925F926F926A\r
+:1066E0007F928F929F92AF92BF92CF92DF92EF9262\r
+:1066F000FF920F931F93CF93DF93CDB7DEB76E97C3\r
+:106700000FB6F894DEBF0FBECDBF611166C22C017B\r
+:106710009C012E5F3F4F3D8F2C8F61E5C9010E9488\r
+:10672000F107CE0101969A8F898F80E1E98DFA8D6C\r
+:1067300011928A95E9F781EA9EE09F938F930E94D8\r
+:10674000C5468A8181608A8342E0BE016F5F7F4FC8\r
+:106750008C8D9D8D0E94C9080F900F90811103C0F0\r
+:1067600084E093E002C08FEF92E09F938F930E94AA\r
+:10677000C5460F900F9088E99EE09F938F930E94EB\r
+:10678000C54680E89EE09F938F930E94C5468EE5A4\r
+:106790009EE09F938F930E94C54688E49EE09F935E\r
+:1067A0008F930E94C5468EE29EE09F938F930E9436\r
+:1067B000C54688E19EE09F938F930E94C54681E085\r
+:1067C0009EE09F938F930E94C5468CEE9DE09F9321\r
+:1067D0008F930E94C54686ED9DE09F938F930E9404\r
+:1067E000C5468EEB9DE09F938F930E94C54685EA38\r
+:1067F0009DE09F938F930E94C5460FB6F894DEBF2D\r
+:106800000FBECDBF188E86E89DE09F938F930E94A8\r
+:10681000C54600E19E012F5F3F4F41E0BE01685E2B\r
+:106820007F4F8C8D9D8D0E9411090F900F908111CB\r
+:1068300010C084E093E09F938F930E94C54668EE5A\r
+:1068400073E080E090E00E94C50A4C010F900F9029\r
+:10685000BDC127E030E047E050E0BE016D5F7F4FF3\r
+:10686000CE0141960E9412469E012F5F3F4F790153\r
+:1068700010E0812F837041F484E89DE09F938F9313\r
+:106880000E94C5460F900F90F70181917F011F92E2\r
+:106890008F932EE73DE03F932F930E94C5461F5FE5\r
+:1068A0000F900F900F900F90103119F78E8987FD80\r
+:1068B00003C040ED57E002C044E358E08F89982FB1\r
+:1068C0009695969596959E71292F220F220F920FDD\r
+:1068D0008F70890F1A01280E311C8E89982F96957A\r
+:1068E000969596959E71792E770C770C790E8F7010\r
+:1068F000780E672C8C89982F9695969596959E7113\r
+:10690000B92EBB0CBB0CB90E8F70B80EBB8E8B8929\r
+:10691000982F9695969596959E71D92EDD0CDD0C47\r
+:10692000D90E8F70D80EED2C8A89982F9695969552\r
+:1069300096959E71F92EFF0CFF0CF90E8F70F80ED4\r
+:10694000CF2C8989182F1695169516951E71912FA3\r
+:10695000990F990F190F8F70180FA12E0D890E8F97\r
+:10696000073048F4E3E00E02C00111249C012054DA\r
+:10697000314F490104C03BE7832E3DE0932E84E76D\r
+:106980009DE09F938F930E94C5469F928F920E9495\r
+:10699000C546812F012E000C990B9F931F938F2DBD\r
+:1069A0000F2C000C990B9F93FF928D2D0D2C000C3A\r
+:1069B000990B9F93DF928B2D0B2C000C990B9F93BF\r
+:1069C000BF92872D072C000C990B9F937F923F92CB\r
+:1069D0002F92802F002E000C990B9F930F9321E58F\r
+:1069E0003DE03F932F930E94C54688891F928F9365\r
+:1069F000E1E4FDE0FF93EF930E94C54668EE73E08B\r
+:106A000080E090E00E94C50A4C010FB6F894DEBF0A\r
+:106A10000FBECDBF94E68916910409F490C0F4F539\r
+:106A2000FEE48F16910409F494C08CF438E48316C4\r
+:106A3000910409F487C08DE48816910409F47BC0A1\r
+:106A400094E48916910409F0C1C0BA9479C0E7E5CD\r
+:106A50008E16910409F485C044F423E5821691044E\r
+:106A600009F0B4C0AA24AA9478C039E58316910429\r
+:106A700009F45AC083E68816910409F0A7C08AE099\r
+:106A8000A82E9CE0C92E21E1E22E00E128E048EE8C\r
+:106A900057E065E0C2010E94683298C090E789160D\r
+:106AA0009104D1F194F4FDE68F16910409F440C0ED\r
+:106AB0002EE68216910409F449C038E68316910443\r
+:106AC00009F084C0EE24E3943FC084E78816910463\r
+:106AD000B1F044F4E3E78E16910409F077C0AA24DC\r
+:106AE000A3943BC0F7E78F169104C9F129E78216FA\r
+:106AF000910409F06BC03FEF231A330A34C08F852D\r
+:106B000087FD02C06AE001C060E0AE014F5F5F4FE9\r
+:106B1000C2010E9483315AC0AE014F5F5F4F6AE0ED\r
+:106B2000C2010E94E63152C081E0281A31081BC020\r
+:106B30006624639402C066246A94670C14C0B394FC\r
+:106B4000BB8E11C0EE24EA94ED0C0DC0CC24C3948E\r
+:106B500002C0CC24CA94CF0C06C0A10E04C00F5FA3\r
+:106B600001C001500E8F8A2D0A2C000C990B9F93A7\r
+:106B7000AF928C2D0C2C000C990B9F93CF928E2DE5\r
+:106B80000E2C000C990B9F93EF92EB8D8E2F0E2EF7\r
+:106B9000000C990B9F93EF93862D062C000C990BFC\r
+:106BA0009F936F923F922F922CE13DE03F932F9362\r
+:106BB0000E94C5460B8D262DA1016E8DC2010E943B\r
+:106BC00068320FB6F894DEBF0FBECDBF9BE18916C9\r
+:106BD000910409F017CE80E001C08FEF6E960FB6DA\r
+:106BE000F894DEBF0FBECDBFDF91CF911F910F9103\r
+:106BF000FF90EF90DF90CF90BF90AF909F908F90DD\r
+:106C00007F906F905F904F903F902F90089560FF1E\r
+:106C100002C0289A01C0289861FF02C0299A01C0C9\r
+:106C2000299862FF02C02A9A01C02A9863FF02C015\r
+:106C30002B9A01C02B9864FF02C02C9A01C02C989B\r
+:106C400065FF02C02D9A01C02D9866FF02C02E9AE2\r
+:106C500001C02E9867FF02C02F9A01C02F98809123\r
+:106C60008804813019F0823061F0089570FF02C00D\r
+:106C70005E9A01C05E9871FF02C05F9A08955F98A6\r
+:106C8000089570FF02C0129A01C0129871FF02C0ED\r
+:106C9000139A08951398089580918804813019F00B\r
+:106CA0008230B1F0089560FF02C0109A01C01098C0\r
+:106CB00061FF02C0119A01C0119862FF02C0129ACE\r
+:106CC00001C0129863FF02C0139A089513980895A3\r
+:106CD00060FF02C05C9A01C05C9861FF02C05D9ACF\r
+:106CE00001C05D9862FF02C05E9A01C05E9863FFBA\r
+:106CF00002C05F9A08955F980895CF93DF93EC01E7\r
+:106D000060E070E00E94073660E0CE010E944C36E1\r
+:106D10008FEF84B980918804813041F0823061F432\r
+:106D200081B18E6081B98AB1806F05C081B18F60F9\r
+:106D300081B98AB1806E8AB9DF91CF910895CF93DE\r
+:106D4000DF93EC0160E070E00E94073660E0CE0166\r
+:106D50000E944C3614B880918804813041F0823012\r
+:106D600061F481B1817F81B98AB18F7005C081B131\r
+:106D7000807F81B98AB18F718AB9DF91CF910895EF\r
+:106D800080918804813019F0823039F008956623AB\r
+:106D900011F05D9808955D9A0895662311F0119899\r
+:106DA0000895119A0895CF92DF92EF92FF920F9378\r
+:106DB0001F93CF93DF937C01611117C06FE00E9496\r
+:106DC0004C366FEF73E0C7010E94073661E0C701E0\r
+:106DD0000E94C03681E09FE09F938F930E94C5463A\r
+:106DE00060ED77E080E090E028C0613069F48DEFDD\r
+:106DF0009EE09F938F930E94C54668EE73E080E00B\r
+:106E000090E00E94AA0A20C0623039F460E071E08C\r
+:106E10000E94073684EF9EE008C06330C1F460E052\r
+:106E200072E00E9407368BEE9EE09F938F930E9444\r
+:106E3000C54668EE73E080E090E00E94AA0A60E038\r
+:106E400070E0C7010E9407360F900F9044C0643273\r
+:106E500008F043C0C62FD0E024978E0183E015953B\r
+:106E600007958A95E1F7C770DD27CC24C394D12C10\r
+:106E7000B601002E01C0660F0A94EAF7C7010E940E\r
+:106E80004C360C2E02C0CC0CDD1C0A94E2F7B60185\r
+:106E9000C7010E940736DF92CF92CC0FDD1FC05E84\r
+:106EA000DE4F89818F9388818F931F930F9386ED97\r
+:106EB0009EE09F938F930E94C54660E971E080E059\r
+:106EC00090E00E94AA0A8DB79EB708960FB6F89474\r
+:106ED0009EBF0FBE8DBF80E001C08FEFDF91CF91CD\r
+:106EE0001F910F91FF90EF90DF90CF90089581B1A7\r
+:106EF000807F81B982B18F6082B9089582B1807F2D\r
+:106F000082B981B1807F81B908956130710581F0C6\r
+:106F100058F06230710581F063307105A1F480B1E1\r
+:106F200083FB882780F90CC080B18095817008951B\r
+:106F300080B18695817004C080B182FB882780F97A\r
+:106F400091E08927089580E008950F931F93CF93D0\r
+:106F5000DF93603108F04EC08C01C62FC695C695F0\r
+:106F6000D0E06370613021F0633009F44BC021C080\r
+:106F7000BE010E948537811145C0CE0101969F93C5\r
+:106F80008F9387E19FE09F938F930E94C5460F9058\r
+:106F90000F900F900F90BE01C8010E94853781119C\r
+:106FA0002BC060E070E0CB010E94AA0A019621F597\r
+:106FB000F2CFBE010E948537882321F1CE010196D0\r
+:106FC0009F938F9389E09FE09F938F930E94C54684\r
+:106FD0000F900F900F900F90BE01C8010E9485374F\r
+:106FE000882351F060E070E0CB010E94AA0A01966C\r
+:106FF00019F4F2CF8FEF07C06AE070E080E090E014\r
+:107000000E94AA0A80E0DF91CF911F910F9108950D\r
+:10701000CF93C82F8A3019F48DE00E9408388091F0\r
+:10702000C80085FFFCCFC093CE0080E090E0CF91F8\r
+:1070300008955A9A22E02093C80028E92093C900B5\r
+:1070400026E02093CA001092CD002CE02093CC00C3\r
+:1070500020E331E03093E7042093E60421E0FC01D3\r
+:1070600022830895FC0112821092C8001092C90078\r
+:107070001092CA001092CD001092CC001092E7043A\r
+:107080001092E60408950F931F93CF93DF9361113D\r
+:1070900022C009E41FE0C9E2DFE01F930F930E94C2\r
+:1070A000C546DF93CF938091E7048F938091E604E8\r
+:1070B0008F930E946C4668E873E180E090E00E9444\r
+:1070C000AA0A0F900F900F900F900F900F900196BB\r
+:1070D00021F380E001C08FEFDF91CF911F910F91DD\r
+:1070E0000895862F6091E6047091E7040C940838A7\r
+:1070F0002F923F924F925F926F927F928F929F92C8\r
+:10710000AF92BF92CF92DF92EF92FF920F931F93B5\r
+:10711000CF93DF93CDB7DEB760970FB6F894DEBF9D\r
+:107120000FBECDBF7C011B016A01FC0117821682D4\r
+:10713000838181FF44C39E012F5F3F4F3901F701D7\r
+:107140009381F10193FD859193FF81911F01882324\r
+:1071500009F431C3853239F493FD859193FF819110\r
+:107160001F01853239F4B70190E00E94894656012B\r
+:107170006501E5CF10E0512C912CFFE1F915D8F015\r
+:107180008B3279F038F4803279F08332A1F4F92D22\r
+:10719000F0612EC08D3261F0803369F4292D2160B9\r
+:1071A0002DC0392D3260932E892D8460982E2AC0EF\r
+:1071B000E92DE86015C097FC2DC020ED280F2A307E\r
+:1071C00088F496FE06C03AE0139F200D1124122F7A\r
+:1071D00019C08AE0589E200D1124522EE92DE0623C\r
+:1071E0009E2E10C08E3231F496FCE5C2F92DF0646B\r
+:1071F0009F2E08C08C3621F4292D2068922E02C0C3\r
+:10720000883641F4F10193FD859193FF81911F012F\r
+:107210008111B3CF9BEB980F933020F4992D90619F\r
+:10722000805E07C09BE9980F933008F066C1992DE6\r
+:107230009F7E96FF16E09F73992E853619F4906411\r
+:10724000992E08C0863621F4392F3068932E02C05B\r
+:107250001111115097FE07C01C3350F4442443947D\r
+:10726000410E27E00BC0183038F027E017E005C0CA\r
+:1072700027E09CE3492E02C0212F412C560184E0D7\r
+:10728000A80EB11CF6016081718182819381042D69\r
+:10729000A3010E9426456C01F981FC87F0FF02C022\r
+:1072A000F3FF06C091FC06C092FE06C000E205C0D6\r
+:1072B0000DE203C00BE201C000E08C858C7019F078\r
+:1072C00001115AC29BC297FE10C04C0CFC85F4FF02\r
+:1072D00004C08A81813309F44A94141474F528E0B7\r
+:1072E000241578F588E0482E2CC096FC2AC0812F02\r
+:1072F00090E08C159D059CF03CEFC3163FEFD30644\r
+:1073000074F0892D8068982E0AC0E2E0F0E0EC0F5E\r
+:10731000FD1FE10FF11D8081803319F4115011110F\r
+:10732000F4CF97FE0EC044244394410E812F90E089\r
+:10733000C816D9062CF41C1904C04424439401C077\r
+:1073400010E097FE06C01C141D0434F4C60101961B\r
+:1073500005C085E090E002C081E090E00111019657\r
+:10736000112331F0212F30E02F5F3F4F820F931F09\r
+:10737000252D30E08217930714F4581A01C0512CC0\r
+:10738000892D897049F4552039F0B70180E290E0E9\r
+:107390000E9489465A94F7CF002329F0B701802F25\r
+:1073A00090E00E94894693FC09C0552039F0B7014E\r
+:1073B00080E390E00E9489465A94F7CF97FE4CC034\r
+:1073C0004601D7FE02C0812C912CC601881999096B\r
+:1073D000F301E80FF91FFE87ED87960124193109A3\r
+:1073E000388B2F87012F10E01195019511093FEF80\r
+:1073F0008316930629F4B7018EE290E00E94894635\r
+:10740000C814D9044CF08F8598898815990524F4FF\r
+:10741000ED85FE85818101C080E3F1E08F1A91083E\r
+:107420002D853E852F5F3F4F3E872D878016910625\r
+:107430002CF0B70190E00E948946D9CFC814D90436\r
+:1074400041F49A81963320F4953319F43C8534FF46\r
+:1074500081E3B70190E04EC08A81813319F09C85A9\r
+:107460009F7E9C87B70190E00E948946111105C05C\r
+:1074700094FC18C085E690E017C0B7018EE290E05A\r
+:107480000E9489461E5F82E001E0080FF301E80FC9\r
+:10749000F11D8081B70190E00E948946802F011381\r
+:1074A000F3CFE6CF85E490E0B7010E948946D7FC90\r
+:1074B00006C0C114D10441F4EC85E4FF05C0D194A9\r
+:1074C000C194D1088DE201C08BE2B70190E00E9427\r
+:1074D000894680E32AE0C216D1042CF08F5FFAE0DF\r
+:1074E000CF1AD108F7CFB70190E00E948946B701C3\r
+:1074F000C601C0960E94894654C1833631F0833755\r
+:1075000079F0833509F056C020C0560132E0A30E51\r
+:10751000B11CF6018081898301E010E0630112C093\r
+:107520005601F2E0AF0EB11CF601C080D18096FE8C\r
+:1075300003C0612F70E002C06FEF7FEFC6010E94B1\r
+:107540002F468C01F92DFF7714C0560122E0A20EC0\r
+:10755000B11CF601C080D18096FE03C0612F70E09F\r
+:1075600002C06FEF7FEFC6010E9407468C01F92D24\r
+:10757000F0689F2EF3FD1AC0852D90E008171907BB\r
+:10758000A8F4B70180E290E00E9489465A94F4CFB3\r
+:10759000F60197FC859197FE81916F01B70190E00C\r
+:1075A0000E94894651105A94015011090115110584\r
+:1075B00079F7F7C0843611F0893661F5560197FEE8\r
+:1075C00009C024E0A20EB11CF601608171818281A4\r
+:1075D00093810AC0F2E0AF0EB11CF60160817181A7\r
+:1075E000072E000C880B990BF92DFF769F2E97FF25\r
+:1075F00009C090958095709561957F4F8F4F9F4FF3\r
+:10760000F0689F2E2AE030E0A3010E940F47C82EA9\r
+:10761000C6183FC0092D853721F40F7E2AE030E0DF\r
+:107620001DC0097F8F3691F018F4883559F0C3C01A\r
+:10763000803719F0883711F0BEC0006104FF09C01F\r
+:10764000046007C094FE08C0066006C028E030E071\r
+:1076500005C020E130E002C020E132E0560107FF22\r
+:1076600009C084E0A80EB11CF6016081718182819D\r
+:10767000938108C0F2E0AF0EB11CF6016081718108\r
+:1076800080E090E0A3010E940F47C82EC6180F7734\r
+:10769000902E96FE0BC0092D0E7FC11650F494FE5D\r
+:1076A0000AC092FC08C0092D0E7E05C0DC2C092DF5\r
+:1076B00003C0DC2C01C0D12E04FF0DC0FE01EC0D77\r
+:1076C000F11D8081803311F4097E09C002FF06C0DC\r
+:1076D000D394D39404C0802F867809F0D39403FD0B\r
+:1076E00011C000FF06C01C2DD51480F4150D1D1906\r
+:1076F0000DC0D51458F4B70180E290E00E9489468D\r
+:10770000D394F7CFD51410F45D1801C0512C04FFA9\r
+:1077100010C0B70180E390E00E94894602FF17C0C5\r
+:1077200001FD03C088E790E002C088E590E0B70162\r
+:107730000CC0802F867859F001FF02C08BE201C097\r
+:1077400080E207FD8DE2B70190E00E948946C116F4\r
+:1077500038F4B70180E390E00E9489461150F7CFDA\r
+:10776000CA94F301EC0DF11D8081B70190E00E94F5\r
+:107770008946C110F5CF15C0F4E0F51560F584E039\r
+:10778000581A93FE1FC0011127C02C8523FF2AC061\r
+:107790000EE011E0392D3071932EF80184918111A2\r
+:1077A00024C0552009F4E4CCB70180E290E00E94A7\r
+:1077B00089465A94F6CFF7018681978126C08FEFCC\r
+:1077C0009FEF23C0B70180E290E00E9489465A945F\r
+:1077D0005110F8CFD8CF512CB701802F90E00E94E4\r
+:1077E0008946D3CF02E111E0D5CF91108052B70185\r
+:1077F00090E00E9489460F5F1F4FCFCF23E02515F1\r
+:1078000010F483E0BDCF512CC0CF60960FB6F89432\r
+:10781000DEBF0FBECDBFDF91CF911F910F91FF90C3\r
+:10782000EF90DF90CF90BF90AF909F908F907F9020\r
+:107830006F905F904F903F902F9008950F931F93FC\r
+:10784000CF93DF93EC018B0180EA91E099838883E9\r
+:10785000CE0104960E94C60CCE01CD960E940F1652\r
+:10786000CE0187589F4F0E94E607CE0185589F4F53\r
+:107870000E944C09FE01E057FF4F10821B830A83D0\r
+:10788000DF91CF911F910F910895CF93DF93CDB7E3\r
+:10789000DEB7AE970FB6F894DEBF0FBECDBF87B18F\r
+:1078A0008C6987B988B1837688B93D98459A82E01A\r
+:1078B0008093C00098E99093C10096E09093C20035\r
+:1078C0001092C5009CE09093C4008093B000809318\r
+:1078D000B10096E99093B3008093700080E191E04D\r
+:1078E0009093E5048093E40482E091E09093E304B4\r
+:1078F0008093E20478940E944D0A86E2EEE3F1E080\r
+:10790000DE01119601900D928A95E1F7809188042D\r
+:10791000811102C087E001C083E1FAE0CF2EF3E0DD\r
+:10792000DF2EACE0AA2EA3E0BA2E682E712C4E01F9\r
+:1079300027E2820E911CCE018B969EA78DA762E84E\r
+:10794000262E62E0362E7AE4472E73E0572EEEE7BD\r
+:10795000EE2EE2E0FE2EDF92CF920E94C546BF924D\r
+:10796000AF920E94C546A5E3B3E0BF93AF930E94D8\r
+:10797000C5463F922F920E94C5465F924F920E9449\r
+:10798000C546FF92EF920E94C54681E493E09F9323\r
+:107990008F930E94C546BF92AF920E94C5468091C8\r
+:1079A00088049FEF980F0FB6F894DEBF0FBECDBFCF\r
+:1079B000923078F40E94400A9F938F938EE692E073\r
+:1079C0009F938F930E94C5460F900F900F900F903A\r
+:1079D00008C086E592E09F938F930E94C5460F9062\r
+:1079E0000F90BF92AF920E94C546DF92CF920E9445\r
+:1079F000C54683E492E09F938F930E94C5461CA6E0\r
+:107A00001BA60F900F900F900F900F900F908BA5CB\r
+:107A10009CA58615970570F5FC01EE0FFF1F21E070\r
+:107A200030E02C0F3D1FE20FF31F008111819F9367\r
+:107A30008F938AE392E09F938F930E94C546D8016B\r
+:107A4000ED91FC910680F781E02DC80109959F9387\r
+:107A50008F930E94C546DF92CF920E94C5468BA5A8\r
+:107A60009CA501969CA78BA70FB6F894DEBF0FBE0E\r
+:107A7000CDBFCDCF8BE292E09F938F930E94C546FE\r
+:107A800010925F0410925E044091E2045091E3046E\r
+:107A900064E070E0C4010E943A463EA53F938DA584\r
+:107AA0008F9388E791E09F938F939F928F920E948C\r
+:107AB000ED460FB6F894DEBF0FBECDBF019709F0BB\r
+:107AC0004ACF8BA59CA58615970508F044CF880F53\r
+:107AD000991FE1E0F0E0EC0FFD1FE80FF91F0081B6\r
+:107AE000118187E292E09F938F930E94C546D8014F\r
+:107AF000ED91FC910680F781E02DC80109959F93D7\r
+:107B00008F930E94C54683E292E09F938F930E94D9\r
+:107B1000C5468FEF9FEF9093010180930001D8013C\r
+:107B2000ED91FC910280F381E02DC80109950F9041\r
+:107B30000F900F900F900F900F90E12CF12C3CE1E3\r
+:107B4000432E32E0532E22242A94322CFF92EF92BD\r
+:107B50005F924F920E94C546D801ED91FC91019031\r
+:107B6000F081E02D6E2DC80109950F900F900F90B8\r
+:107B70000F9087FD18C080910001909101014B97F3\r
+:107B800039F48FEF9FEF90930101809300010BC0B8\r
+:107B90003092010120920001BFEFEB1AFB0A2FEF98\r
+:107BA000E216F10499F6D801ED91FC910480F5817B\r
+:107BB000E02DC8010995C3CE84EC91E090935D045B\r
+:107BC00080935C0481E492E090935B0480935A0478\r
+:107BD0008CE092E0909359048093580484E292E000\r
+:107BE00090935604809355041092570484EF91E0CB\r
+:107BF000909354048093530482E991E0909350044D\r
+:107C000080934F04109252041092510480E092E04D\r
+:107C100090934E0480934D048CED91E09093490431\r
+:107C20008093480410924A0410924C0410924B0422\r
+:107C300088EE91E0909347048093460488EB91E0AE\r
+:107C4000909343048093420481E0909188049130A2\r
+:107C500009F480E080934404109245048DE492E09E\r
+:107C60009093400480933F041092410480ED91E092\r
+:107C700090932C0480932B0410922D0410922E04C8\r
+:107C80008CEA91E0909327048093260410922804B4\r
+:107C90008FEF9FEF90932A048093290460E070E0B7\r
+:107CA00085E993E00E941E3C61E070E084E093E08F\r
+:107CB0000E941E3C62E070E083E792E00E941E3C5E\r
+:107CC00088E192E090936D0280936C028EE692E0E0\r
+:107CD0000E94E607109270021092720210927102D6\r
+:107CE00086E891E0909362028093610210926A02AA\r
+:107CF00021E030E030936902209368021092630221\r
+:107D0000109264021092650210926602109267024D\r
+:107D1000909357028093560210925F0282E090E0A7\r
+:107D200090935E0280935D02109258021092590265\r
+:107D300010925A0210925B0210925C0208958AE936\r
+:107D400094E00E94C60C88E191E09093990480939E\r
+:107D5000980490939704809396049093950480934D\r
+:107D6000940408958CE497E0089580E399E00895E1\r
+:107D700087E699E0089588E799E0089589E59AE013\r
+:107D8000089587EE9AE0089580E99BE008958CEBD2\r
+:107D90009BE0089585E09CE008958CE19CE00895C7\r
+:107DA00084E09FE0089582E29FE0089589E69FE0E5\r
+:107DB0000895DB018F939F930E94363FBF91AF914F\r
+:107DC000A29F800D911DA39F900DB29F900D112435\r
+:107DD0000895991B79E004C0991F961708F0961B27\r
+:107DE000881F7A95C9F78095089587FB082E062687\r
+:107DF00087FD819567FD61950E94E93E0EF491959E\r
+:107E000007FC81950895AA1BBB1B51E107C0AA1F5F\r
+:107E1000BB1FA617B70710F0A61BB70B881F991F2B\r
+:107E20005A95A9F780959095BC01CD010895052E2E\r
+:107E300097FB1EF400940E942E3F57FD07D00E942E\r
+:107E4000DA4007FC03D04EF40C942E3F5095409539\r
+:107E5000309521953F4F4F4F5F4F089590958095F6\r
+:107E6000709561957F4F8F4F9F4F08950E940541F8\r
+:107E7000A59F900DB49F900DA49F800D911D11247E\r
+:107E80000895B7FF0C94363F0E94363F821B930B38\r
+:107E90000895DF93CF931F930F939A9DF02D219F09\r
+:107EA000F00D8B9DF00D8A9DE02DF10D039FF00DDF\r
+:107EB000029FE00DF11D4E9DE00DF11D5E9DF00D48\r
+:107EC0004F9DF00D7F936F93BF92AF925F934F934F\r
+:107ED000D5010E9405418B01AC01D7010E940541EB\r
+:107EE000EB01E80FF91FD6010E94993F2F913F91B6\r
+:107EF000D6010E940541C60FD71FE81FF91FAF9199\r
+:107F0000BF910E94993F2F913F910E940541C60F5A\r
+:107F1000D71FE81FF91FD6010E940541E60FF71F82\r
+:107F20009801BE01CF0111240F911F91CF91DF91D4\r
+:107F300008950E940541460F571FC81FD91F08F416\r
+:107F400031960895689401C0E894F92FF12B12F04E\r
+:107F50000C94D63FA0E0B0E0E0EBFFE30C94484087\r
+:107F6000092E059422F40E943240112392F4F0E885\r
+:107F70000F26FFEFE094F09400951095B094C09414\r
+:107F8000D094A194BF0ACF0ADF0AEF0AFF0A0F0BB1\r
+:107F90001F0B0E94E13F07FC0E943240CDB7DEB7C5\r
+:107FA000ECE00C946440689401C0E8948F929F9236\r
+:107FB000CF93DF930E94E13FDF91CF919F908F900D\r
+:107FC000089588249924F401E401B0E49F93AA273A\r
+:107FD0009A158B049C04ED05FE05CF05D007A1077B\r
+:107FE00098F4AD2FDC2FCF2FFE2FE92D982C892E62\r
+:107FF000982F872F762F652F542F432F322F22272C\r
+:10800000B85031F7BF9127C01B2EBF91BB27220F5D\r
+:10801000331F441F551F661F771F881F991F881C19\r
+:10802000991CEE1FFF1FCC1FDD1FAA1FBB1F8A1448\r
+:108030009B04EC05FD05CE05DF05A007B10748F060\r
+:108040008A189B08EC09FD09CE09DF09A00BB10BCA\r
+:1080500021601A94E1F62EF49401AF01BE01CD0126\r
+:10806000000C089560957095809590953095409599\r
+:10807000509521953F4F4F4F5F4F6F4F7F4F8F4F21\r
+:108080009F4F08952F923F924F925F926F927F92EF\r
+:108090008F929F92AF92BF92CF92DF92EF92FF9218\r
+:1080A0000F931F93CF93DF93CDB7DEB7CA1BDB0BC4\r
+:1080B0000FB6F894DEBF0FBECDBF09942A88398869\r
+:1080C00048885F846E847D848C849B84AA84B98470\r
+:1080D000C884DF80EE80FD800C811B81AA81B9817C\r
+:1080E000CE0FD11D0FB6F894DEBF0FBECDBFED0190\r
+:1080F00008950F93083090F0982F872F762F652FD3\r
+:10810000542F432F322F22270850F4CF220F331F32\r
+:10811000441F551F661F771F881F991F0A95B2F7C6\r
+:108120000F91089597FB10F8169400080F930830EC\r
+:1081300098F00850232F342F452F562F672F782F74\r
+:10814000892F902DF4CF059497958795779567950E\r
+:1081500057954795379527950A95AAF70F91089552\r
+:108160002A0D3B1D4C1D5D1D6E1D7F1D801F911F27\r
+:1081700008950024A7FD00942A0F301D401D501DB6\r
+:10818000601D701D801D901D08952A193B094C0922\r
+:108190005D096E097F09800B910B08950024A7FDEE\r
+:1081A00000942A17300540055005600570058005CC\r
+:1081B00090050895A1E21A2EAA1BBB1BFD010DC05C\r
+:1081C000AA1FBB1FEE1FFF1FA217B307E407F50787\r
+:1081D00020F0A21BB30BE40BF50B661F771F881F63\r
+:1081E000991F1A9469F760957095809590959B01F9\r
+:1081F000AC01BD01CF010895EE0FFF1F0024001C4C\r
+:108200000BBE0790F691E02D0994A29FB001B39F99\r
+:10821000C001A39F700D811D1124911DB29F700D8F\r
+:10822000811D1124911D08955058BB27AA270E9433\r
+:108230002C410C94D1420E94C34238F00E94CA42A1\r
+:1082400020F039F49F3F19F426F40C94B0420EF458\r
+:10825000E095E7FB0C94AA42E92F0E94E24258F312\r
+:10826000BA17620773078407950720F079F4A6F51B\r
+:108270000C9404430EF4E0950B2EBA2FA02D0B01A5\r
+:10828000B90190010C01CA01A0011124FF27591B5B\r
+:1082900099F0593F50F4503E68F11A16F040A22F61\r
+:1082A000232F342F4427585FF3CF469537952795D2\r
+:1082B000A795F0405395C9F77EF41F16BA0B620BD1\r
+:1082C000730B840BBAF09150A1F0FF0FBB1F661F18\r
+:1082D000771F881FC2F70EC0BA0F621F731F841F5B\r
+:1082E00048F4879577956795B795F7959E3F08F081\r
+:1082F000B0CF9395880F08F09927EE0F9795879543\r
+:1083000008950E9495410C94D1420E94CA4258F0AF\r
+:108310000E94C34240F029F45F3F29F00C94AA4226\r
+:1083200051110C9405430C94B0420E94E24268F350\r
+:108330009923B1F3552391F3951B550BBB27AA271E\r
+:1083400062177307840738F09F5F5F4F220F331F58\r
+:10835000441FAA1FA9F335D00E2E3AF0E0E832D020\r
+:1083600091505040E695001CCAF72BD0FE2F29D023\r
+:10837000660F771F881FBB1F261737074807AB07F5\r
+:10838000B0E809F0BB0B802DBF01FF2793585F4F6A\r
+:108390003AF09E3F510578F00C94AA420C940543A4\r
+:1083A0005F3FE4F3983ED4F3869577956795B7954C\r
+:1083B000F7959F5FC9F7880F911D9695879597F957\r
+:1083C0000895E1E0660F771F881FBB1F62177307D0\r
+:1083D0008407BA0720F0621B730B840BBA0BEE1FE5\r
+:1083E00088F7E09508950E94FA416894B1110C94C1\r
+:1083F000054308950E94EA4288F09F5798F0B92FEC\r
+:108400009927B751B0F0E1F0660F771F881F991FC9\r
+:108410001AF0BA95C9F714C0B13091F00E94044324\r
+:10842000B1E008950C940443672F782F8827B85F34\r
+:1084300039F0B93FCCF3869577956795B395D9F721\r
+:108440003EF490958095709561957F4F8F4F9F4F2B\r
+:10845000089597FB16F40E94B3420C946D42E89481\r
+:1084600009C097FB3EF490958095709561957F4F7C\r
+:108470008F4F9F4F9923A9F0F92F96E9BB2793952A\r
+:10848000F695879577956795B795F111F8CFFAF43A\r
+:10849000BB0F11F460FF1BC06F5F7F4F8F4F9F4F6B\r
+:1084A00016C0882311F096E911C0772321F09EE8C9\r
+:1084B000872F762F05C0662371F096E8862F70E02F\r
+:1084C00060E02AF09A95660F771F881FDAF7880F09\r
+:1084D0009695879597F90895E894F92F96EBFF23E1\r
+:1084E00081F0121613061406440B9395F6958795A2\r
+:1084F0007795679557954040FF23B9F71BC099279B\r
+:108500000895882351F49850D2F7872B762F652F42\r
+:10851000542F432F322F20E0B1F312161306140606\r
+:10852000440B88233AF09A95440F551F661F771F16\r
+:10853000881FCAF755234AF4440F551F11F460FFF2\r
+:1085400004C06F5F7F4F8F4F9F4F880F9695879521\r
+:1085500097F9089597F99F6780E870E060E00895C3\r
+:108560009FEF80EC0895909580957095609550955B\r
+:108570004095309521953F4F4F4F5F4F6F4F7F4F45\r
+:108580008F4F9F4F089500240A9416161706180659\r
+:108590000906089500240A94121613061406050607\r
+:1085A0000895092E0394000C11F4882352F0BB0F98\r
+:1085B00040F4BF2B11F460FF04C06F5F7F4F8F4FFB\r
+:1085C0009F4F089557FD9058440F551F59F05F3F36\r
+:1085D00071F04795880F97FB991F61F09F3F79F0E5\r
+:1085E00087950895121613061406551FF2CF469567\r
+:1085F000F1DF08C0161617061806991FF1CF8695E9\r
+:108600007105610508940895E894BB2766277727CC\r
+:10861000CB0197F908950E941E430C94D1420E9409\r
+:10862000C34238F00E94CA4220F0952311F00C9406\r
+:10863000AA420C94B04211240C9405430E94E242D9\r
+:1086400070F3959FC1F3950F50E0551F629FF001A5\r
+:10865000729FBB27F00DB11D639FAA27F00DB11DBE\r
+:10866000AA1F649F6627B00DA11D661F829F222747\r
+:10867000B00DA11D621F739FB00DA11D621F839FCE\r
+:10868000A00D611D221F749F3327A00D611D231FA4\r
+:10869000849F600D211D822F762F6A2F11249F57F2\r
+:1086A00050409AF0F1F088234AF0EE0FFF1FBB1FF5\r
+:1086B000661F771F881F91505040A9F79E3F5105B4\r
+:1086C00080F00C94AA420C9405435F3FE4F3983E7B\r
+:1086D000D4F3869577956795B795F795E7959F5F5E\r
+:1086E000C1F7FE2B880F911D9695879597F90895F0\r
+:1086F000FA01EE0FFF1F309621053105A1F161153A\r
+:10870000710561F48038BFE39B0749F168949038A4\r
+:10871000810561F08038BFEF9B0741F099234AF54E\r
+:10872000FF3FE1053105210519F1E8940894E7952B\r
+:10873000D901AA2329F4AB2FBE2FF85FD0F310C0C4\r
+:10874000FF5F70F4A695E0F7F73950F019F0FF3AA3\r
+:1087500038F49F779F930DD00F9007FC90580895A1\r
+:1087600046F00C94B04260E070E080E89FE308952A\r
+:108770004FE79F775F934F933F932F930E949C44C3\r
+:108780002F913F914F915F910E940B430C94D543E1\r
+:108790000E940744880B990B089529F416F00C9455\r
+:1087A000AA420C9404430C94B0420E94EA42A8F3FB\r
+:1087B0009638A0F707F80F92E8942BE33AEA48EBD3\r
+:1087C0005FE70E9421430F920F920F924DB75EB761\r
+:1087D0000F920E94E444ECE8F0E00E942B444F9199\r
+:1087E0005F91EF91FF91E595EE1FFF1F49F0FE5756\r
+:1087F000E0684427EE0F441FFA95E1F74195550BC9\r
+:108800000E945E440F9007FE0C9452440895990F05\r
+:108810000008550FAA0BE0E8FEEF16161706E8074A\r
+:10882000F907C0F012161306E407F50798F0621B6B\r
+:10883000730B840B950B39F40A2661F0232B242B40\r
+:10884000252B21F408950A2609F4A140A6958FEF5F\r
+:10885000811D811D0895DF93CF931F930F93FF9286\r
+:10886000EF92DF927B018C01689406C0DA2EEF0153\r
+:108870000E941E43FE01E894A591259135914591F2\r
+:108880005591A6F3EF010E942C41FE019701A8012A\r
+:10889000DA9469F7DF90EF90FF900F911F91CF91DD\r
+:1088A000DF9108959B01AC0160E070E080E89FE3F8\r
+:1088B0000C9481410C94AA420C9418450E94EA42FF\r
+:1088C000D8F39923C9F3940F511DA3F3915050404D\r
+:1088D00094F059F0882332F0660F771F881F91506B\r
+:1088E0005040C1F79E3F51052CF7880F911D96957A\r
+:1088F000879597F908955F3FACF0983E9CF0BB27B1\r
+:10890000869577956795B79508F4B1609395C1F70B\r
+:10891000BB0F58F711F460FFE8CF6F5F7F4F8F4FA9\r
+:108920009F4FE3CF0C94054316F00C9418450C941C\r
+:10893000B04268940C94AA420E94EA42A8F3992398\r
+:10894000C1F3AEF3DF93CF931F930F93FF92C92F21\r
+:10895000DD2788232AF02197660F771F881FDAF713\r
+:1089600020E030E040E85FEB9FE3883920F0803E74\r
+:1089700038F021968F770E941541E4EBF0E004C0B7\r
+:108980000E941541E1EEF0E00E942B448B01BE01F4\r
+:10899000EC01FB2E6F5771097595771F880B990BAA\r
+:1089A0000E94314228E132E741E35FE30E941E4327\r
+:1089B000AF2D9801AE01FF900F911F91CF91DF91E4\r
+:1089C0000E942C410C94D142FA01DC01AA0FBB1F7A\r
+:1089D0009B01AC01BF5728F4222733274427507846\r
+:1089E00020C0B75190F4AB2F0024469537952795BA\r
+:1089F000011CA395D2F3002071F0220F331F441FF6\r
+:108A0000B395DAF30ED00C94144161307105A0E8EF\r
+:108A10008A07B94630F49B01AC016627772788277F\r
+:108A20009078309621F020833183428353830895D8\r
+:108A30009F3F31F0915020F4879577956795B795D2\r
+:108A4000880F911D9695879597F90895283008F01D\r
+:108A500027E03327DA01990F311D87FD91600096D9\r
+:108A60006105710539F432602E5F3D9330E32A953C\r
+:108A7000E1F708959F3F30F080387105610509F0F6\r
+:108A80003C5F3C5F3D93913008F08068911DDF931F\r
+:108A9000CF931F930F93FF92EF92192F987F969584\r
+:108AA000E92F96959695E90FFF27E059FE4F9927F4\r
+:108AB0003327EE24FF24A701E701059008940794CB\r
+:108AC00028F4360FE71EF81E491F511D660F771F49\r
+:108AD000881F991F0694A1F70590079428F4E70EC4\r
+:108AE000F81E491F561FC11D770F881F991F661F4B\r
+:108AF0000694A1F70590079428F4F80E491F561F15\r
+:108B0000C71FD11D880F991F661F771F0694A1F7F5\r
+:108B10000590079420F4490F561FC71FD81F990FBF\r
+:108B2000661F771F881F0694A9F784911095177008\r
+:108B300041F0D695C79557954795F794E7941A95C0\r
+:108B4000C1F7E6E1F1E068941590159135916591D2\r
+:108B5000959105907FE27395E118F10A430B560B4E\r
+:108B6000C90BD009C0F7E10CF11E431F561FC91FE6\r
+:108B7000D01D7EF4703311F48A95E6CFE89401504D\r
+:108B800030F0080F0AF40027021708F4202F23956D\r
+:108B9000022F7A3328F079E37D932A95E9F710C004\r
+:108BA0007D932A9589F6069497956795379517953D\r
+:108BB0001794E118F10A430B560BC90BD00998F032\r
+:108BC00023957E9173957A3308F070E37C9320139C\r
+:108BD000B8F77E9170617D9330F0839571E37D935A\r
+:108BE00070E32A95E1F71124EF90FF900F911F9108\r
+:108BF000CF91DF91992787FD90950895FB01DC01C6\r
+:108C000002C005900D9241505040D8F70895FC01E4\r
+:108C10000590615070400110D8F7809590958E0FA7\r
+:108C20009F1F0895FB01DC012150304030F001907E\r
+:108C30000D920416C9F7CD01089588279927089544\r
+:108C4000FB01DC014150504048F001900D920020A2\r
+:108C5000C9F701C01D9241505040E0F70895FC0152\r
+:108C60006150704001900110D8F7809590958E0F5B\r
+:108C70009F1F0895CF92DF92EF92FF920F931F9361\r
+:108C8000CF93DF93FA01238120FD03C080E090E0C1\r
+:108C90001AC016161706D4F77A018C01EB016C0185\r
+:108CA000C130D10569F0C7010E94654A8F3FFFEFCF\r
+:108CB0009F0761F3F60181936F0121970A9781F76E\r
+:108CC000F6011082C801DF91CF911F910F91FF90A3\r
+:108CD000EF90DF90CF9008950F931F93CF93DF9382\r
+:108CE000CDB7DEB70F811885F80183818860838353\r
+:108CF000AE01455F5F4F69857A85C8010E9478386B\r
+:108D0000F8012381277F2383DF91CF911F910F915A\r
+:108D100008950F931F93CF93DF93FB01238121FDD0\r
+:108D200003C08FEF9FEF2CC022FF16C046815781F2\r
+:108D3000248135814217530744F4A081B1819D01FC\r
+:108D40002F5F3F4F318320838C93268137812F5FA4\r
+:108D50003F4F3783268314C08B01EC01FB01008455\r
+:108D6000F185E02D0995892BE1F6D80116968D91B4\r
+:108D70009C911797019617969C938E931697CE0108\r
+:108D8000DF91CF911F910F9108950F931F93CF9370\r
+:108D9000DF93CDB7DEB7AE01495F5F4FDA016D916A\r
+:108DA0007D91AD0102EE14E0F80182819381DC0136\r
+:108DB00013962C911397286013962C930E94783861\r
+:108DC000D8011296ED91FC9113972381277F23837D\r
+:108DD000DF91CF911F910F910895CF93DF93CDB77E\r
+:108DE000DEB72E970FB6F894DEBF0FBECDBF85E07D\r
+:108DF0008C838B899C899A838983AE01495E5F4FFE\r
+:108E00006D897E89CE0101960E942C492E960FB65F\r
+:108E1000F894DEBF0FBECDBFDF91CF910895FA0168\r
+:108E2000AA27283051F1203181F1E8946F936E7FA9\r
+:108E30006E5F7F4F8F4F9F4FAF4FB1E03ED0B4E09A\r
+:108E40003CD0670F781F891F9A1FA11D680F791FDB\r
+:108E50008A1F911DA11D6A0F711D811D911DA11DEC\r
+:108E600020D009F468943F912AE0269F11243019FC\r
+:108E7000305D3193DEF6CF010895462F4770405D97\r
+:108E80004193B3E00FD0C9F7F6CF462F4F70405D46\r
+:108E90004A3318F0495D31FD4052419302D0A9F7A1\r
+:108EA000EACFB4E0A6959795879577956795BA959B\r
+:108EB000C9F700976105710508959B01AC010A2E61\r
+:108EC00006945795479537952795BA95C9F7620F38\r
+:108ED000731F841F951FA01D089520FD09C0FC016C\r
+:108EE00023FD05C022FF02C0738362835183408348\r
+:108EF000089544FD17C046FD17C0AB01BC01DA015F\r
+:108F0000FB01AA0FBB1FEE1FFF1F1094D1F74A0FE2\r
+:108F10005B1F6E1F7F1FCB01BA01660F771F881F73\r
+:108F2000991F09C033E001C034E0660F771F881F26\r
+:108F3000991F3150D1F7620F711D811D911D089548\r
+:108F40000F931F93CF93DF938C01C8010E94654A52\r
+:108F5000EC0197FD08C00E94514A892BB1F7B80176\r
+:108F6000CE010E94A34ACE01DF91CF911F910F91B4\r
+:108F700008958F929F92AF92BF92EF92FF920F93BC\r
+:108F80001F93CF93DF938C01D62F7A01B22E0E94CC\r
+:108F9000654A9C0133272B32310531F02D323105E2\r
+:108FA00061F48B2D8068B82ED15011F480E068C038\r
+:108FB000C8010E94654A97FDF9CFCB2DCD7F2B2D9F\r
+:108FC000207309F58033F9F4AA24AA94AD0E09F4AC\r
+:108FD00043C0C8010E94654A97FD3EC09C012F7D99\r
+:108FE00033272835310549F4C264D250A9F1C801AC\r
+:108FF0000E94654A97FF07C02FC0B6FE02C0C2603C\r
+:1090000001C0C261DA2D812C912C540120ED280F72\r
+:10901000283080F0C4FF04C0B8010E94A34A19C0E0\r
+:109020002A3040F0C6FFF8CF2F7D3FEE320F3630AA\r
+:1090300098F727504C2FC501B4010E9479474B0186\r
+:109040005C01C260D15059F0C8010E94654A97FF87\r
+:10905000DDCFC1FD04C0AACF812C912C5401C7FFE4\r
+:1090600008C0B094A09490948094811C911CA11C81\r
+:10907000B11C2C2FB501A401C7010E946D4781E0EE\r
+:10908000DF91CF911F910F91FF90EF90BF90AF9024\r
+:109090009F908F9008955F926F927F928F929F9290\r
+:1090A000AF92BF92CF92DF92EF92FF920F931F93F6\r
+:1090B000CF93DF93CDB7DEB7A0970FB6F894DEBF9E\r
+:1090C0000FBECDBF5C01962E7A01F9018E010F5FB4\r
+:1090D0001F4F680180E2D8011D928A95E9F7D501FA\r
+:1090E00013968C9080E090E0612C712C30E061E070\r
+:1090F00070E083FC259183FE21918F01522E211176\r
+:1091000003C080E090E092C02E3511F4009751F139\r
+:10911000432F50E0481759073CF42D3559F12D32B3\r
+:1091200019F4772009F103C0772009F46AC0452DAE\r
+:10913000469546954695D601A40FB11D452D47701D\r
+:109140008B0102C0000F111F4A95E2F7A8015C9144\r
+:10915000452B4C93651459F0561410F45394E7CFF3\r
+:109160005A94E5CF31E004C07724739401C0712C88\r
+:109170000196BFCF772019F08E8180628E833111E6\r
+:1091800003C08824839417C0F6019E012F5D3F4FD2\r
+:109190008081809581932E173F07D1F7F2CFE1149C\r
+:1091A000F10429F0D7018C93F70131967F019A944D\r
+:1091B000812C9920F9F0C5010E94654A97FD18C0DD\r
+:1091C000FC01FF2723E0F595E7952A95E1F7EC0DE3\r
+:1091D000FD1D208130E0AC014770552702C0359558\r
+:1091E00027954A95E2F720FDDACFB5010E94A34A00\r
+:1091F000811087CFE114F10411F0D7011C92C8014E\r
+:1092000015C0422F469546954695D601A40FB11D2F\r
+:10921000422F47708B0102C0000F111F4A95E2F7E1\r
+:10922000A8015C91452B4C93622EA2CFA0960FB65D\r
+:10923000F894DEBF0FBECDBFDF91CF911F910F918C\r
+:10924000FF90EF90DF90CF90BF90AF909F908F9066\r
+:109250007F906F905F9008955F926F927F928F9250\r
+:109260009F92AF92BF92CF92DF92EF92FF920F93B5\r
+:109270001F93CF93DF936C01EB015A01FC0117821E\r
+:109280001682512CF601E380FE01E3FC8591E3FE9A\r
+:109290008191182FEF01882309F4EEC090E00E941D\r
+:1092A000514A892B21F0C6010E94A047EBCF15320D\r
+:1092B00041F4FE01E3FC1591E3FE1191EF0115323B\r
+:1092C00081F4C6010E94654A97FDD4C0412F50E049\r
+:1092D0009C01332724173507A9F2B6010E94A34A3F\r
+:1092E000CBC01A3239F4E3FC1591E3FE1191EF0182\r
+:1092F00001E001C000E0F12C20ED210F2A3080F4C4\r
+:1093000002606F2D70E080E090E040E20E947947BB\r
+:10931000F62EFE01E3FC1591E3FE1191EF01ECCF77\r
+:1093200001FF03C0F11003C0A7C0FF24FA94183650\r
+:1093300019F01C3651F010C0FE01E3FC1591E3FE5C\r
+:109340001191EF01183641F408600460FE01E3FC5E\r
+:109350001591E3FE1191EF01112309F48DC0612FE6\r
+:1093600070E080E192E00E945A4A892B09F484C09F\r
+:1093700000FD07C0F50180809180C50102965C0167\r
+:1093800002C0812C912C1E3651F4F6014681578182\r
+:1093900060E070E0202FC4010E946D4773CF133648\r
+:1093A000A9F401FD02C0FF24F394C6010E94654A9E\r
+:1093B00097FD60C08114910429F0F4018083C401F9\r
+:1093C00001964C01FA94F110F0CF50C01B3559F4BE\r
+:1093D0009E01A4016F2DC6010E944B48EC01892B10\r
+:1093E00009F044C03EC0C6010E94A04797FD42C09C\r
+:1093F0001F3661F128F4143639F1193651F128C0BD\r
+:10940000133771F0153701F123C08114910429F04D\r
+:10941000F4016082C40101964C01FA94FF2071F0BE\r
+:10942000C6010E94654A3C0197FD08C00E94514A4E\r
+:10943000892B59F3B601C3010E94A34A81149104F8\r
+:10944000A9F0F401108212C0006203C0006101C0E3\r
+:109450000064202FA4016F2DC6010E94B94781111D\r
+:1094600005C0F6018381807329F406C000FD0ACF90\r
+:10947000539408CF552019F0852D90E002C08FEF4E\r
+:109480009FEFDF91CF911F910F91FF90EF90DF90B1\r
+:10949000CF90BF90AF909F908F907F906F905F9094\r
+:1094A000089591110C94BC4A803219F0895085506E\r
+:1094B000C8F70895FC010590061621F00020D9F7A1\r
+:1094C000C00108953197CF010895CF93DF93EC0148\r
+:1094D0002B8120FF33C026FF0AC02F7B2B838E8178\r
+:1094E0009F8101969F838E838A8190E029C022FF0D\r
+:1094F0000FC0E881F9818081082E000C990B00973C\r
+:1095000019F420622B831AC03196F983E8830EC0C8\r
+:10951000EA85FB85099597FF09C02B81019611F01B\r
+:1095200080E201C080E1822B8B8308C02E813F81C5\r
+:109530002F5F3F4F3F832E83992702C08FEF9FEF0E\r
+:10954000DF91CF910895FB01238120FF12C026FDFA\r
+:1095500010C08F3F3FEF930761F082832F7D20641F\r
+:109560002383268137812150310937832683992728\r
+:1095700008958FEF9FEF0895992788270895F8940D\r
+:02958000FFCF1B\r
+:10958200FFFF00000001000000000000CE09000003\r
+:109592000000000200000000EF09000000000303C9\r
+:1095A2002C022E02300232023402360238023A0211\r
+:1095B20000000002000000000838000000003F0424\r
+:1095C2000403730295036C02610256025C045A049E\r
+:1095D2005804550453044F044D04480446044204FD\r
+:1095E2002B042604280545053505E308D808CE08CE\r
+:1095F20001040000000271CB257800424D4532384B\r
+:109602003000000000000D215C22521A411A0000B5\r
+:109612000000D822C522CF22B23E3F000000000047\r
+:10962200A1237C2393236B2300000000F926C32689\r
+:10963200E126B53E000000007D29B7282D29B83E5D\r
+:1096420000000000502AFA29012ABB3E0000000057\r
+:10965200A82A932A942ABE3E000000007C2C622C89\r
+:10966200492CC13E00000000802EF02D002EC43E89\r
+:10967200000000008E2F822F892FC73E00000000BD\r
+:10968200E22FD62FDD2FCA3E00000000E030B230BC\r
+:10969200C930CD3E000000006B33553166316E316A\r
+:1096A20000000000D3367D369F36D03E4100420096\r
+:1096B20043004400450046004700445000000000BB\r
+:1096C20000A53777377E37D33E00000000433819B4\r
+:0696D200383238D63E00DC\r
+:00000001FF\r
diff --git a/software/deye-sun-12k/nano-1284/src b/software/deye-sun-12k/nano-1284/src
new file mode 120000 (symlink)
index 0000000..5cd551c
--- /dev/null
@@ -0,0 +1 @@
+../src
\ No newline at end of file
diff --git a/software/deye-sun-12k/nano-644/Makefile b/software/deye-sun-12k/nano-644/Makefile
new file mode 100644 (file)
index 0000000..7b20d98
--- /dev/null
@@ -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_deye-sun-12k_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,--section-start=.text=$(START_ADDRESS) -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,--section-start=.text=$(START_ADDRESS) -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/deye-sun-12k/nano-644/release/v2024-11-08_181803/nano-x-base_test-software_nano-m644p_12mhz.bin b/software/deye-sun-12k/nano-644/release/v2024-11-08_181803/nano-x-base_test-software_nano-m644p_12mhz.bin
new file mode 100755 (executable)
index 0000000..0c7d86e
Binary files /dev/null and b/software/deye-sun-12k/nano-644/release/v2024-11-08_181803/nano-x-base_test-software_nano-m644p_12mhz.bin differ
diff --git a/software/deye-sun-12k/nano-644/release/v2024-11-08_181803/nano-x-base_test-software_nano-m644p_12mhz.elf b/software/deye-sun-12k/nano-644/release/v2024-11-08_181803/nano-x-base_test-software_nano-m644p_12mhz.elf
new file mode 100755 (executable)
index 0000000..7d33607
Binary files /dev/null and b/software/deye-sun-12k/nano-644/release/v2024-11-08_181803/nano-x-base_test-software_nano-m644p_12mhz.elf differ
diff --git a/software/deye-sun-12k/nano-644/release/v2024-11-08_181803/nano-x-base_test-software_nano-m644p_12mhz.hex b/software/deye-sun-12k/nano-644/release/v2024-11-08_181803/nano-x-base_test-software_nano-m644p_12mhz.hex
new file mode 100644 (file)
index 0000000..e37ec65
--- /dev/null
@@ -0,0 +1,2396 @@
+:100000000C94B1070C94D9070C94D9070C94D90718\r
+:100010000C94D9070C94D9070C94D9070C94D907E0\r
+:100020000C94D9070C94C90B0C94D9070C94D907DC\r
+:100030000C94D9070C94D9070C94D9070C94D907C0\r
+:100040000C94D9070C94D9070C94D9070C94D907B0\r
+:100050000C94190B0C94D9070C94D9070C94D9075C\r
+:100060000C94D9070C94D9070C948D0B0C94D907D8\r
+:100070000C944C0B0C94D9070C94D90707634236A7\r
+:10008000B79BD8A71A39685618AEBAAB558C1D3C29\r
+:10009000B7CC5763BD6DEDFD753EF6177231BF00ED\r
+:1000A0000000803F08000000BE922449123EABAA27\r
+:1000B000AA2ABECDCCCC4C3E00000080BEABAAAA82\r
+:1000C000AA3E00000000BF000000803F00000000CA\r
+:1000D00000084178D3BB4387D1133D190E3CC3BD03\r
+:1000E0004282AD2B3E68EC8276BED98FE1A93E4CB0\r
+:1000F00080EFFFBE01C4FF7F3F00000000006E6183\r
+:100100006E00696E660000407A10F35A00A0724ECD\r
+:1001100018090010A5D4E80000E87648170000E4AC\r
+:100120000B54020000CA9A3B000000E1F5050000F4\r
+:1001300080969800000040420F000000A086010059\r
+:100140000000102700000000E80300000000640029\r
+:10015000000000000A000000000001000000000094\r
+:100160002C76D888DC674F0823DFC1DFAE59E1B1B8\r
+:10017000B796E5E3E453C63AE651997696E8E6C2C7\r
+:100180008426EB898C9B62ED407C6FFCEFBC9C9FCE\r
+:1001900040F2BAA56FA5F490055A2AF75C936B6CF0\r
+:1001A000F9676DC11BFCE0E40D47FEF520E6B500E4\r
+:1001B000D0ED902E0300943577050080841E080052\r
+:1001C00000204E0A000000C80C333333330F986E02\r
+:1001D00012831141EF8D2114893BE65516CFFEE6BF\r
+:1001E000DB18D1844B381BF77C1D901DA4BBE42485\r
+:1001F000203284725E228100C9F124ECA1E53D2702\r
+:100200006364696E6F70737578585B000A25346497\r
+:100210003A20005D3A20000A0A5B000A53656C65CB\r
+:10022000637420756E69743A2000253378202E2E71\r
+:100230002E2000417661696C61626C6520756E6983\r
+:1002400074733A0A0A004E6F204E616E6F2D582D5E\r
+:1002500042617365206465746563746564004E6112\r
+:100260006E6F2D582D426173653A20255300202F63\r
+:100270002000202F20000A0A4861726477617265AD\r
+:1002800020255320646574656374656420284144A7\r
+:100290004337483D30782530325829000A496E7678\r
+:1002A000616C6964204E616E6F2D582D42617365DB\r
+:1002B0002048617264776172652D56657273696F4B\r
+:1002C0006E3A204144433748203D20256420284190\r
+:1002D000546D656761363434502C20332E335629E3\r
+:1002E0000A00563F3F005632610056316100446FAC\r
+:1002F0006E65004552524F52000A000A3D3D3D3D99\r
+:100300003D3D3D3D3D3D3D3D3D3D3D3D3D3D3D3D1D\r
+:100310003D3D3D3D3D3D3D3D3D3D3D3D3D3D3D3D0D\r
+:100320003D0A200041546D65676136343450003118\r
+:10033000383A31383A3033004E6F76202038203248\r
+:10034000303234000A505441424C452025643A2052\r
+:100350003078253032780020213D20307825303229\r
+:1003600078000A00205B5741524E3A20627566665B\r
+:10037000657220746F20736D616C6C5D2000204F7E\r
+:100380004B5B7265636569766520256420627974CC\r
+:1003900065735D2000204552524F525B7265636564\r
+:1003A0006976652025642062797465732C206578F0\r
+:1003B000706563742025642062797465735D200024\r
+:1003C0005D2000203078253032580020537461744D\r
+:1003D00065735B004552525D005D0020307825302A\r
+:1003E0003278000A205B72656164526567697374D4\r
+:1003F000657273283078253032782C202E2E2E2CE2\r
+:10040000202564295D202D3E20004552525D00309C\r
+:1004100078253032782C7374617475733D3078258B\r
+:100420003032785D000A205B7265616452656769ED\r
+:10043000737465722830782530327829202D3E205B\r
+:10044000004552525D007374617475733D307825B8\r
+:100450003032785D00202D3E20002030782530326B\r
+:1004600078000A205B7772697465526567697374F6\r
+:1004700065727328307825303278293A2000455249\r
+:10048000525D007374617475733D30782530327835\r
+:100490005D000A205B7772697465526567697374E1\r
+:1004A0006572283078253032782C2030782530322B\r
+:1004B0007829202D3E20004F4B006661696C730047\r
+:1004C0004F4B2C20696E69742050415441424C4579\r
+:1004D000202E2E2E20006661696C73004F4B2C205D\r
+:1004E000696E6974207265676973746572202E2E57\r
+:1004F0002E20006661696C7300207265736574203C\r
+:10050000434331313031202E2E2E200043432D31F4\r
+:100510003130312D3F0043432D313130312D546581\r
+:1005200073740043432D313130312D526563656959\r
+:1005300076650043432D313130312D53656E6400B3\r
+:10054000646F6E65202873746174653D3078253062\r
+:1005500032782900202E2E2E2000202530325800FF\r
+:100560002564206461746120627974657320284871\r
+:100570004558293A20004552524F522C20004F4BEB\r
+:100580002C200020525353493D25642C204C5149C6\r
+:100590003D25642C204352432000202D3E20004561\r
+:1005A000320063616E63656C6C6564004532004FB8\r
+:1005B0004B2C2072656365697665202E2E2E2000F7\r
+:1005C0003F202849444C45290063616E63656C6C8B\r
+:1005D0006564004531000A205B253034785D203D9C\r
+:1005E0003E207374617274202E2E2E20004F4B001B\r
+:1005F0004531005D202D3E2000202530325800205E\r
+:100600002D2D3E2073656E6420256420627974650B\r
+:100610007320284845583A20253032580030782534\r
+:10062000303278004531000A205B253034785D3A5D\r
+:100630002073746174653D006661696C73002850B5\r
+:10064000415441424C45203D2030782530325829D4\r
+:100650000064426D20000A2073776974636820701B\r
+:100660006F77657220746F200020757365202B20D2\r
+:10067000616E64202D20666F7220706F7765722026\r
+:100680006368616E676520286F74686572206B65AA\r
+:1006900079202D3E206261636B20746F2064656653\r
+:1006A00061756C742900292E06477A0E1404040023\r
+:1006B000000600216276CAF81622F84007301816A4\r
+:1006C0006C434991876BFB5610E92A001F41005982\r
+:1006D0007F3F813509C6392E3600C031310000C553\r
+:1006E00031300000CD37000000863500000050306A\r
+:1006F000000000372D360000262D3130001D2D3131\r
+:100700003500172D323000032D333000253564209D\r
+:10071000283078253032782920000D20203D3E20D9\r
+:10072000456E636F64657220287075736820746FFE\r
+:1007300020636C656172293A2000456E636F6465C1\r
+:100740007200656E64000A2049324320534C4156C2\r
+:10075000453A2066726F6D206D61737465723A2040\r
+:10076000307825303278202D3E20746F206D6173F3\r
+:100770007465723A20307825303278004531002097\r
+:100780002D3E204552524F520030782530327800AD\r
+:100790002C202066726F6D20736C6176653A2000A4\r
+:1007A000202D3E204552524F52000A204932432DFF\r
+:1007B0004D41535445523A20746F20736C617665F5\r
+:1007C0003A20307825303278004531004533002911\r
+:1007D0000062616400706F6F720066616972006729\r
+:1007E0006F6F6400657863656C6C656E74003F00C4\r
+:1007F0002C2065636F323D25642800292C207476F7\r
+:100800006F633D2564707062003F00756E686561BE\r
+:100810006C74687900706F6F72006D6F64657261DF\r
+:10082000746500676F6F6400657863656C6C656EF6\r
+:100830007400206171693D25642800453200252E31\r
+:100840003166C2B0432F252E31662525293A200076\r
+:100850004531290020207C20454E53313630202858\r
+:10086000002C20483D20252E32662525002C2054C2\r
+:100870003D20252E3266C2B043000A203D3E204274\r
+:100880004D3238303A20503D20252E336662617259\r
+:10089000004F4B004534004533004532004F4B2C90\r
+:1008A00020454E53313630202E2E2E20004531006B\r
+:1008B00020424D323830202E2E2E20004932432D3A\r
+:1008C000536C617665004932432D4D6173746572D6\r
+:1008D000004932432D537061726B66756E20456E10\r
+:1008E000762D436F6D626F00656E64000A20203DB7\r
+:1008F0003E207265636569766520427974653A20A9\r
+:10090000307825303278000A20203D3E2073656E15\r
+:10091000642042797465203078253032780049456A\r
+:10092000454534383500656E64004552524F5228B3\r
+:10093000256429004F4B004C434420004552524F40\r
+:100940005220256429004F4B2900696E6974204CA0\r
+:1009500043442028004C63640054657374204C4564\r
+:100960004420442564004C656400656E6400202DBD\r
+:100970003E2025342E3866560A0020307825303245\r
+:1009800078002020003F000A202020202020205234\r
+:100990007844313A0020307825303278000A203D02\r
+:1009A0003E2053656E64696E673A004D6F646275F0\r
+:1009B000733A206C657365205370616E6E756E6757\r
+:1009C00020766F6E2045617374726F6E2053444DB4\r
+:1009D0002D323330202845696E70686173656E7AF8\r
+:1009E000C3A4686C65722900202E2E2E20707265BB\r
+:1009F0007373206B657920746F2070726F63656507\r
+:100A000064006E6F20627974652072656365697633\r
+:100A100065640030782530327820726563656976C8\r
+:100A20006564002044453D25752C206E52453D25CA\r
+:100A3000752073656E64203078253032782E2E2E26\r
+:100A40002000696E6974004D6F6462757300202028\r
+:100A50006E6F20726F746174696F6E2028543D252B\r
+:100A60003034782920200020206E3D202535642058\r
+:100A7000552F6D696E2028543D253034782900208B\r
+:100A800053454E534F523D25642000206E4641553C\r
+:100A90004C543D25640020414443323D25336400DD\r
+:100AA000202050574D2F4F4330413D253364000DDA\r
+:100AB00020203D3E20414443303D25336400454ED7\r
+:100AC0003D3100454E3D30000D205357333D2564E8\r
+:100AD0002D3E000A004D6F746F72000A20204261A3\r
+:100AE0006E6B30202D204750422564203D20300081\r
+:100AF0000A202042616E6B30202D20475042256431\r
+:100B0000203D2031000A202042616E6B30202D20D4\r
+:100B10004750412564203D2030000A202042616E6C\r
+:100B20006B30202D204750412564203D2031000AA4\r
+:100B3000203D3E207374617274202E2E2E002900F9\r
+:100B4000204F4B00204A5033392E322F33206A7504\r
+:100B50006D706572656420286C656674293F00209D\r
+:100B60004552524F5200202872656164203078252A\r
+:100B7000303278202D3E2030782530327800506F8A\r
+:100B8000727445787000253464202830782530331D\r
+:100B90007829000D20203D3E204D656173757265FA\r
+:100BA00020414443303A20000A00506F746900200D\r
+:100BB00025332E3166203D3E205357393A36203DAD\r
+:100BC000202564202564252064202564202000251C\r
+:100BD0003464202830782530337829000D20203DDA\r
+:100BE0003E204D65617375726520414443323A2061\r
+:100BF000000A0052325200416C6C00426C75650074\r
+:100C0000477265656E005265640052676200202578\r
+:100C1000303278000A20257020257020257020258C\r
+:100C200070202570202570202570202D3E207772A1\r
+:100C30006974653A2000706F776572206F66662070\r
+:100C40006661696C732C204920616D207374696C36\r
+:100C50006C20616C697665203A2D29202E2E2E207D\r
+:100C600070726F63656564000A20706F776572202B\r
+:100C70006F6666206E6F77202E2E2E000D2070720C\r
+:100C80006573732045534320746F2061626F7274E3\r
+:100C90002C20706F776572206F666620696E202544\r
+:100CA000647320287072657373206B657920746F8C\r
+:100CB00020736B69702074696D65722920000A00C9\r
+:100CC0000A20706F776572206F6E202E2E2E0066C0\r
+:100CD00061696C73004F4B000A2054696D65722086\r
+:100CE0006F6666202E2E2E20000A2054696D6572D4\r
+:100CF0002073657420746F202564732028313A2591\r
+:100D000030325829202E2E2E20000A207365743A86\r
+:100D100020253034642D253032642D253032642076\r
+:100D2000253032643A253032643A2530326400206E\r
+:100D30002D2054696D65723D307825303278002C55\r
+:100D400020256420253034642D253032642D253053\r
+:100D5000326420253032643A253032643A2530320C\r
+:100D6000640020202D2D3E20003F3F002025303202\r
+:100D7000580020000A203D3E2072656164207265A3\r
+:100D800067697374657220302D3135202868657865\r
+:100D9000293A000A202020732F53202E2E2073651D\r
+:100DA000636F6E6420282B2F2D290A000A20202033\r
+:100DB0006E2F4E202E2E206D696E75746520282BA7\r
+:100DC0002F2D29000A202020682F48202E2E206851\r
+:100DD0006F757220282B2F2D29000A202020642FC8\r
+:100DE00044202E2E2064617920282B2F2D29000AE3\r
+:100DF0002020206D2F4D202E2E206D6F6E746820C8\r
+:100E0000282B2F2D29000A202020792F59202E2E23\r
+:100E1000207965617220282B2F2D29000A2020209F\r
+:100E2000772F57202E2E207765656B6461792028F7\r
+:100E30002B2F2D290A000A20202063202E2E2E2E53\r
+:100E400020696E697420636C6F636B000A20202038\r
+:100E500070202E2E2E2E20706F776572206F6E2FD1\r
+:100E60006F666620285043372D3E513129000A20F5\r
+:100E7000202074202E2E2E2E2074696D6572206F16\r
+:100E80006E2F6F6666000A2070726573733A000AEF\r
+:100E9000203D3E20636F6E6669672038353633200B\r
+:100EA0002E2E2E20005254432D3835363300536FEA\r
+:100EB000004D6F004469004D6900446F00467200A8\r
+:100EC0005361000043686172202564202D20257342\r
+:100ED000202D3E2025303278004C312F4C32204FCF\r
+:100EE0004E004C312F4C32204F4E004F4646004FA3\r
+:100EF0004E00536567370052656C6561736520531A\r
+:100F00005725642000507265737320535725640081\r
+:100F10005377697463680048656C6C6F2055415263\r
+:100F200054312C204543484F2D4D6F64757320611B\r
+:100F300063746976650A000A203D3E2073656E641D\r
+:100F400020746578742076696120554152543120AF\r
+:100F50006E6F772E2E2E0055617274310000893D20\r
+:100F60004C3E11241FBECFEFD0E1DEBFCDBF12E05B\r
+:100F7000A0E0B1E0E2E4F4E902C005900D92A635EC\r
+:100F8000B107D9F724E0A6E5B2E001C01D92A83E62\r
+:100F9000B207E1F717E0C1EBD7E004C02197FE01EB\r
+:100FA0000E94A940CF3AD107C9F70E94F23B0C94A6\r
+:100FB0001F4A0C940000FC01108211820895FC016C\r
+:100FC0009181992311F0915091830895FC016083E0\r
+:100FD00084E68093B80084E08093BC0081E00895AB\r
+:100FE00084E08093BC001092B80008954150FB014A\r
+:100FF00094E824EC4F3FD1F0442319F02093BC0037\r
+:1010000002C09093BC008091BC0087FFFCCF809110\r
+:10101000B900887F442319F0803519F009C088355C\r
+:1010200039F48091BB0081934150E4CF81E0089571\r
+:1010300080E00895DC01FB0184E835E0442389F079\r
+:10104000222311F0949101C090819093BB00809372\r
+:10105000BC0011963C9311979091BC0097FFFCCF78\r
+:1010600002C081E008959091B90041503196987F77\r
+:10107000983221F380E00895FC0184EA8093BC005B\r
+:1010800085E081838091BC0087FFFCCF9091B900FF\r
+:10109000987F983011F09031B1F49081990F962B90\r
+:1010A0009093BB0084E88093BC0085E081838091AD\r
+:1010B000BC0087FFFCCF9091B900987F611105C0FB\r
+:1010C00081E0983129F080E0089581E09034D9F7EB\r
+:1010D00008950F931F93CF93DF93D62F8A01C22FCA\r
+:1010E00060E00E943C08811102C080E016C0F80157\r
+:1010F00024E8D093BB002093BC009091BC0097FFE4\r
+:10110000FCCF9091B900987F983279F7D1919FEFF9\r
+:101110009C0FCC2311F0C92FECCFDF91CF911F9101\r
+:101120000F91089584E98093BC008091BC0084FDF8\r
+:10113000FCCF81E00895FF920F931F93CF93DF932D\r
+:10114000EC018B01F42E61E00E943C08882379F0C9\r
+:101150004F2DB801CE010E94F607882341F0CE0141\r
+:10116000DF91CF911F910F91FF900C94920880E036\r
+:10117000DF91CF911F910F91FF900895FF920F93F0\r
+:101180001F93CF93DF93EC018B01F42E60E00E945C\r
+:101190003C08882381F020E04F2DB801CE010E9449\r
+:1011A0001A08882341F0CE01DF91CF911F910F9152\r
+:1011B000FF900C94920880E0DF91CF911F910F91E6\r
+:1011C000FF900895FF920F931F93CF93DF93EC014D\r
+:1011D0008B01F42E60E00E943C08882381F021E01E\r
+:1011E0004F2DB801CE010E941A08882341F0CE018C\r
+:1011F000DF91CF911F910F91FF900C94920880E0A6\r
+:10120000DF91CF911F910F91FF900895CF92DF92C0\r
+:10121000EF92FF920F931F93CF93DF93EC016B013B\r
+:10122000142F790160E00E943C08882301F120E03E\r
+:10123000412FB601CE010E941A088823C1F061E057\r
+:10124000CE010E943C08882391F0402FB701CE01C7\r
+:101250000E94F607882359F0CE01DF91CF911F91AC\r
+:101260000F91FF90EF90DF90CF900C94920880E068\r
+:10127000DF91CF911F910F91FF90EF90DF90CF9072\r
+:101280000895FC011082118212821386148608953B\r
+:10129000FC019081992311F091509083089567FD8E\r
+:1012A0000CC0660F642B6093BA0084E68093B8008C\r
+:1012B00085E48093BC0081E0089580E0089584E097\r
+:1012C0008093BC001092B8000895FB012FB7F894EA\r
+:1012D000918181E0890F8183DB01A90FB11D1296F5\r
+:1012E0004C93883008F0118281819081891305C068\r
+:1012F0008F5F8083883008F010822FBF0895462FBB\r
+:10130000BC01655F7F4F0C946509FB019FB7F894A2\r
+:1013100080812181821304C09FBF8FEF9FEF0895CA\r
+:1013200021E0280F2083DB01A80FB11D12968C91BC\r
+:10133000283018F49FBF90E008951082FBCFBC01C5\r
+:101340006F5F7F4F0C9485092091B900287F20386A\r
+:1013500019F0283A49F013C04091BB00BC016F5FFF\r
+:101360007F4F0E94650909C0BC01655F7F4F0E94E5\r
+:10137000850997FD80E08093BB0085E801C085EC7E\r
+:101380008093BC000895CF93DF9390915F04809188\r
+:101390005E049817D1F3E0915F0481E08E0F809393\r
+:1013A0005F04F0E0E05AFB4FC081CD3009F4CAE0A1\r
+:1013B000D0E06091E4047091E504CE010E942B46D8\r
+:1013C000CE01DF91CF9108950F931F93CF93C82F34\r
+:1013D0008B018A3019F48DE00E94E4098091E404C5\r
+:1013E0009091E5040817190731F48091C00085FF3A\r
+:1013F000FCCFC093C60080E090E0CF911F910F9189\r
+:101400000895089580E090E008950895089508955E\r
+:101410000895089508952FB7F8944091900450913D\r
+:101420009104452B59F4429A80383FEF930710F40A\r
+:1014300080589F4F90939104809390042FBF0895FC\r
+:101440002FB7F8944091920450919304452B59F48E\r
+:10145000449A80383FEF930710F480589F4F909341\r
+:101460009304809392042FBF0895813041F082301D\r
+:1014700019F486EE92E0089582EE92E008958AEEE5\r
+:1014800092E00895CF9387E680937C0087E880936D\r
+:101490007A0080917A00806480937A0080917A004B\r
+:1014A00086FDFCCF1092880480917900843F10F073\r
+:1014B00081E005C080917900803E18F082E0809341\r
+:1014C0008804809188049FEF980F923088F0809173\r
+:1014D00079001F928F938CE992E09F938F930E94E3\r
+:1014E0006746109288040F900F900F900F9014C0D1\r
+:1014F000C09179000E94350A1F92CF939F938F93DA\r
+:1015000086E792E09F938F930E9467460F900F901B\r
+:101510000F900F900F900F9010927C0010927A0015\r
+:1015200080918804CF910895F89460938C0470930F\r
+:101530008D0480938E0490938F04789408950E9474\r
+:10154000940AF89480918C0490918D04A0918E045B\r
+:10155000B0918F047894892B8A2B8B2B31F080915A\r
+:10156000000190910101019661F380910001909139\r
+:1015700001010895CF93DF93CFEFDFEFD093010107\r
+:10158000C09300010E949F0AD0930101C093000103\r
+:10159000DF91CF910895CF93DF93CDB7DEB7289732\r
+:1015A0000FB6F894DEBF0FBECDBF7091800460917E\r
+:1015B00081045091820440918304309184042091ED\r
+:1015C0008504909186048091870479836A835B8384\r
+:1015D0004C833D832E839F8388878FB7F894E09157\r
+:1015E0008004709181046091820450918304409141\r
+:1015F0008404309185042091860490918704E983C6\r
+:101600007A836B835C834D833E832F8398878FBF60\r
+:1016100029813A814B815C816D817E818F819885A2\r
+:1016200028960FB6F894DEBF0FBECDBFDF91CF91E5\r
+:1016300008951F920F920FB60F9211242F933F938C\r
+:101640008F939F93EF93FF938091C600282F30E0F4\r
+:101650003093010120930001E0915E0491E09E0F20\r
+:1016600090935E04F0E0E05AFB4F808390915E041B\r
+:1016700080915F04981305C080915F048F5F809311\r
+:101680005F04FF91EF919F918F913F912F910F9068\r
+:101690000FBE0F901F9018951F920F920FB60F92CA\r
+:1016A00011242F933F934F935F936F937F938F9367\r
+:1016B0009F93AF93BF93CF93EF93FF93C091CE00CF\r
+:1016C00080912D04882329F06C2F8BE294E00E94F6\r
+:1016D000142C80914104882329F06C2F8FE394E02F\r
+:1016E0000E94473880912804882329F06C2F86E2D5\r
+:1016F00094E00E943C27FF91EF91CF91BF91AF9171\r
+:101700009F918F917F916F915F914F913F912F9119\r
+:101710000F900FBE0F901F9018951F920F920FB64B\r
+:101720000F9211242F933F934F935F936F937F9367\r
+:101730008F939F93AF93BF93EF93FF938091940305\r
+:10174000882319F084E093E00DC08091030388237F\r
+:1017500019F083E792E006C080912504882329F0E0\r
+:1017600085E993E00E94852603C080E88093BC0051\r
+:10177000FF91EF91BF91AF919F918F917F916F9169\r
+:101780005F914F913F912F910F900FBE0F901F903F\r
+:1017900018951F920F920FB60F9211242F933F931B\r
+:1017A0004F935F936F937F938F939F93AF93BF9369\r
+:1017B000EF93FF9380915104882321F08FE494E00C\r
+:1017C0000E94FD2280914A04882321F088E494E05D\r
+:1017D0000E946B2D80918B048F5F8A3018F4809368\r
+:1017E0008B0494C010928B0480918C0490918D0492\r
+:1017F000A0918E04B0918F04892B8A2B8B2B99F0AA\r
+:1018000080918C0490918D04A0918E04B0918F04EE\r
+:101810000197A109B10980938C0490938D04A09342\r
+:101820008E04B0938F042091800430918104409104\r
+:1018300082045091830460918404709185048091A6\r
+:10184000860490918704A1E00E9466402093800462\r
+:101850003093810440938204509383046093840402\r
+:101860007093850480938604909387048DE793E0BA\r
+:101870000E94DF078FE793E00E9448098CEE92E018\r
+:101880000E94DF078EEE92E00E9448098EE094E00D\r
+:101890000E94DF0780E194E00E94480980916A027B\r
+:1018A000882329F080916A02815080936A02809196\r
+:1018B0005F02882329F080915F02815080935F024C\r
+:1018C0008091900490919104892B69F0809190040B\r
+:1018D00090919104019790939104809390048038A3\r
+:1018E000910508F442988091920490919304892B79\r
+:1018F00069F08091920490919304019790939304DE\r
+:10190000809392048038910508F44498809189046A\r
+:1019100090918A04019690938A0480938904883870\r
+:10192000934140F098B188E0892788B910928A04E1\r
+:1019300010928904FF91EF91BF91AF919F918F9188\r
+:101940007F916F915F914F913F912F910F900FBEBB\r
+:101950000F901F901895CF93DF93EC011982188296\r
+:101960008091D50481110EC085ED94E00E94020A99\r
+:10197000892B41F083ED94E00E94DB0785ED94E034\r
+:101980000E94050A198A1A8A1B8A1C8A88E994E02F\r
+:101990009B838A8386E994E09D838C8384E994E029\r
+:1019A0009F838E8383ED94E099838883DF91CF9129\r
+:1019B0000895CF93DF9300D0CDB7DEB74A83FC0103\r
+:1019C00080819181009739F0698342E0BE016F5FA9\r
+:1019D0007F4F0E94BE080F900F90DF91CF91089526\r
+:1019E000CF92EF920F93CF93DF93EC016295660F46\r
+:1019F000660F607C47702770822F880F880F880FD2\r
+:101A0000262F242B282B2FAB0295000F007E88ADAC\r
+:101A10008F71082B08AF8E2D8770880F880F880F65\r
+:101A20009EA9292F207C9C2D9770E22EE82AE92A76\r
+:101A3000E894E7F8EEAA40E064EFCE010E94D90CEA\r
+:101A400048AD42954695477062EFCE010E94D90C91\r
+:101A50009EA9492F477060E2469F90011124892F6B\r
+:101A6000869586958695877064E0869FA0011124EF\r
+:101A7000422B532B97FB992790F9492B65EFCE0109\r
+:101A80000E94D90C9FA9492F477080E2489F90017E\r
+:101A90001124892F869586958695877064E0869FA8\r
+:101AA000A0011124422B532B9295969596959370F5\r
+:101AB000492B64EFCE01DF91CF910F91EF90CF9042\r
+:101AC0000C94D90C0F93CF93DF931F92CDB7DEB751\r
+:101AD000FC0180819181009749F0698301E09E01BA\r
+:101AE0002F5F3F4F41E0B9010E94060989810F90A5\r
+:101AF000DF91CF910F9108950F93CF93DF9300D093\r
+:101B0000CDB7DEB7FC0180819181009749F06983F0\r
+:101B100002E09E012F5F3F4F41E0B9010E9406099C\r
+:101B200089819A819827892798270F900F90DF91B4\r
+:101B3000CF910F9108950E947C0D982789279827AF\r
+:101B400008950C947C0D0C949B0D0F93CF93DF9311\r
+:101B500000D01F92CDB7DEB7FC0180819181009744\r
+:101B600049F0698303E09E012F5F3F4F41E0B901D7\r
+:101B70000E94060929816A81862F90E0A0E0B0E0EA\r
+:101B8000BA2FA92F982F8827A22B2B81BC01CD011A\r
+:101B9000622B0F900F900F90DF91CF910F910895CE\r
+:101BA0006F927F928F929F92AF92BF92CF92DF926D\r
+:101BB000EF92FF920F931F93CF93DF93EC019FA9B6\r
+:101BC000892F807C803409F043C0492F477060E240\r
+:101BD000469F90011124892F86958695869587705A\r
+:101BE000E4E08E9FA0011124422B532B92959695F1\r
+:101BF00096959370492B64EFCE010E94D90C0E94F8\r
+:101C0000CB0A922E832E742E652E63EFCE010E9496\r
+:101C1000620D83FF1FC00E94CB0AA92CB82CC72CD1\r
+:101C2000D62CE12CF12C00E010E00E947240203D07\r
+:101C3000374041055105610571058105910509F0A0\r
+:101C400038F487EB9BE00197F1F700C00000DDCF8F\r
+:101C500080E001C081E0DF91CF911F910F91FF9053\r
+:101C6000EF90DF90CF90BF90AF909F908F907F903C\r
+:101C70006F9008951F93CF93DF93EC0168E80E9463\r
+:101C80009B0D9E8B8D8B6AE8CE010E949B0D988FD9\r
+:101C90008F8B6CE8CE010E949B0D9A8F898F6EE826\r
+:101CA000CE010E949B0D9C8F8B8F60E9CE010E941C\r
+:101CB0009B0D9E8F8D8F62E9CE010E949B0D98A394\r
+:101CC0008F8F64E9CE010E949B0D9AA389A366E9D8\r
+:101CD000CE010E949B0D9CA38BA368E9CE010E94BC\r
+:101CE0009B0D9EA38DA36AE9CE010E949B0D98A730\r
+:101CF0008FA36CE9CE010E949B0D9AA789A76EE97C\r
+:101D0000CE010E949B0D9CA78BA761EACE010E9489\r
+:101D1000620D8DA761EECE010E949B0D9FA78EA73D\r
+:101D200063EECE010E94620D88AB64EECE010E948C\r
+:101D3000620D182F65EECE010E94620D90E119022E\r
+:101D4000900111248F70282B3AAB29AB66EECE019F\r
+:101D50000E94620D182F65EECE010E94620D90E187\r
+:101D600019029001112490E044E0959587954A95D9\r
+:101D7000E1F7822B932B9CAB8BAB67EECE010E94DD\r
+:101D8000620D8DABDF91CF911F91089563EF0E949B\r
+:101D9000620D81700895CF92DF92EF92FF920F93C0\r
+:101DA0001F93CF93DF93EC0160ED0E94620D90E0F2\r
+:101DB000A0E0B0E089879A87AB87BC878036910521\r
+:101DC000A105B10569F546EB60EECE010E94D90C84\r
+:101DD0008FE295E70197F1F700C00000CE010E9465\r
+:101DE000C60E8111F5CFCE010E943A0EC12CD12C26\r
+:101DF000E12CF12C05E010E025E030E045E050E07A\r
+:101E000063E070E0CE010E94F00C9FE729EA83E0D6\r
+:101E1000915020408040E1F700C0000081E001C007\r
+:101E200080E0DF91CF911F910F91FF90EF90DF90B5\r
+:101E3000CF900895CF93DF93EC01888199810E9420\r
+:101E4000E607882329F0CE01DF91CF910C94CB0EC9\r
+:101E500080E0DF91CF9108954F925F926F927F92D1\r
+:101E60008F929F92AF92BF92CF92DF92EF92FF92AA\r
+:101E7000CF93DF93EC016AEF0E94A50D6115710508\r
+:101E800020E88207910509F485C06B017C0184E09C\r
+:101E9000F594E794D794C7948A95D1F74D885E88D6\r
+:101EA000C701B60128E030E040E050E00E94C43EA7\r
+:101EB000612C712CD301C201880F991FAA1FBB1F6F\r
+:101EC000281B390B4A0B5B0BAF89B88D0E94EE3E85\r
+:101ED0004B015C01C701B60120E130E040E050E079\r
+:101EE0000E94C43ECA01B90164197509860997099F\r
+:101EF0009B01AC010E94863E9B01AC017CE05595A4\r
+:101F00004795379527957A95D1F7A98DBA8D0E9477\r
+:101F1000EE3E2B013C01C501B40120E038E040E079\r
+:101F200050E00E94C43E69017A01C301B20120E081\r
+:101F300030E440E050E00E94C43EBA01A9014C0DDB\r
+:101F40005D1D6E1D7F1D89899A89AB89BC899A01A7\r
+:101F5000AB01280F391F4A1F5B1F2D873E874F8714\r
+:101F6000588BA5E0B0E00E94E33E60587F4F8F4F52\r
+:101F70009F4F20E031E040E050E00E94C43ECA01A3\r
+:101F8000B9010E94DB4120E030E048EC52E40E94BD\r
+:101F90002B4104C060E070E080EC9FE7DF91CF91BF\r
+:101FA000FF90EF90DF90CF90BF90AF909F908F9079\r
+:101FB0007F906F905F904F9008952F923F924F9235\r
+:101FC0005F926F927F928F929F92AF92BF92CF92C9\r
+:101FD000DF92EF92FF920F931F93CF93DF93CDB7D2\r
+:101FE000DEB76D970FB6F894DEBF0FBECDBF1C01F4\r
+:101FF0000E942C0F67EFC1010E94A50D6F87788B9F\r
+:10200000898B9A8B611571058048910509F49AC2F4\r
+:10201000F10185859685A785B0896C017D01FF0C4E\r
+:10202000CC08DC2C76019C01AD016C2D7C2D8C2D17\r
+:102030009C2D345F41405109610971098109910961\r
+:1020400029873A874B875C873B014C0159016A011C\r
+:102050007B018C010E94F63E422E3D874E875B8BB2\r
+:102060006C8B7D8B8E8B9B8FD1015E963C915E97A6\r
+:102070005D962C91932F990F990B492F592F692F0A\r
+:10208000792F892F0E94F63E0CE00E9426402C8F6B\r
+:102090003D8F49835F8B688F798F582E9A8FF1011E\r
+:1020A00030A1278D932F990F990BA42CBD84CE843A\r
+:1020B000DB88EC88FD880E891B8D492F592F692FED\r
+:1020C000792F892F0E94F63EF22E032F142FB52F61\r
+:1020D000F62FE72FD82EE92EA0E00E947B4084F453\r
+:1020E00021503F4F4F4F5F4F6F4F7F4F8F4F9F4F4D\r
+:1020F000F22E032F142FB52FF62FE72FD82EE92E0F\r
+:102100002F2D302F412F5B2F6F2F7E2F8D2D9E2D4A\r
+:1021100008E00E943F40AC8CBD8CC980DF88E88C11\r
+:10212000F98C052D1A8D0E945D4070588F4F9F4F7E\r
+:10213000D1015B96ED91FC915C975F01C12CD12C94\r
+:10214000E12CF12C8701E983BA82CB82DC82ED821B\r
+:10215000FE820F831887C12CD12CE12CF12C00E0DA\r
+:1021600010E00E94F63E122F3F8B4983B52FF62FC9\r
+:10217000E72FF82E092FA0E00E947B4084F4215025\r
+:102180003109410951096E4F7F4F8F4F9F4F122FD9\r
+:102190003F8B4983B52FF62FE72FF82E092F212FDC\r
+:1021A0003F8949815B2F6F2F7E2F8F2D902F01E26A\r
+:1021B0000E943F402D8F532E49835F8B688F798F0C\r
+:1021C0008A8F9C8FA0E00E947B4009F4C0C1D1019E\r
+:1021D00096963C91969795962C91932F990F990BE3\r
+:1021E000A42CBD84CE84DB88EC88FD880E891B8DF1\r
+:1021F000492F592F692F792F892F0E94F63E2D875D\r
+:102200003E87442E5B8B6C8B7D8B8E8B9B8FF1017D\r
+:1022100034A123A1932F990F990BA984BA84CB845D\r
+:10222000DC8473018401492F592F692F792F892F5D\r
+:102230000E94F63E01E10E942640AD84BE84C42C7B\r
+:10224000DB88EC88FD880E891B8D0E945D4059015A\r
+:102250006A017B01482E192F4F85588969897A892F\r
+:1022600034E075956795579547953A95D1F780E095\r
+:1022700090E0A0E1B0E0841B950BA60BB70B3C01EE\r
+:102280004D01990C6608762C43019C01AD01662D29\r
+:10229000762D862D962D0FE10E942640722E832EDC\r
+:1022A000942E652EB62FA72F8A879B87F10132A126\r
+:1022B00021A1932F990F990B492F592F692F792F0E\r
+:1022C000892F03E20E942640042D0E945D4059019F\r
+:1022D0006A017B018C01272D382D492D562D6B2F3E\r
+:1022E0007A2F8A859B850E947240E5E3AE2EFCE042\r
+:1022F000BF2EC12CD12CE12CF12C00E010E00E946B\r
+:10230000F63EAD8CB52CC980DF88E88CF98C0A8D3F\r
+:102310001C8D0E94513F2C8B3B8B2A013B014C01B1\r
+:10232000F22E032F142FB52DF62FE72DD82EE92CE2\r
+:10233000A0E00E947B4084F42150304E4F4F5F4F0D\r
+:102340006F4F7F4F8F4F9F4FF22E032F142FB52FBC\r
+:10235000F62FE72FD82EE92E2F2D302F412F5B2F70\r
+:102360006F2F7E2F8D2D9E2D0DE00E943F402987DF\r
+:102370003A874B875C876F8779838D879E87D101EA\r
+:102380009C963C919C979B962C91932F990F990B1F\r
+:10239000A984BA846A017B01082F1E85492F592F11\r
+:1023A000692F792F892F0E94F63E0E94F63EF22E69\r
+:1023B000032F142FB52FF62FE72FD82EE92EA0E0EC\r
+:1023C0000E947B4084F42150310941095E4F6F4FD8\r
+:1023D0007F4F8F4F9F4FF22E032F142FB52FF62FC5\r
+:1023E000E72FD82EE92E2F2D302F412F5B2F6F2F67\r
+:1023F0007E2F8D2D9E2D09E10E943F40AC88BB8829\r
+:102400006201730184010E945D4029873A874B87EE\r
+:102410005C876F8779838D879E87F10132A521A51F\r
+:10242000932F990F990B492F592F692F792F892FA6\r
+:102430000E94F63E122F3C8B4B8BB52FF62FE72FC9\r
+:10244000F82E092FA0E00E947B4084F4215031092E\r
+:10245000484F5F4F6F4F7F4F8F4F9F4F122F3C8BD7\r
+:102460004B8BB52FF62FE72FF82E092F212F3C8904\r
+:102470004B895B2F6F2F7E2F8F2D902F03E10E94B2\r
+:102480003F4059016A017B018C0129853A854B85C2\r
+:102490005C856F8579818D859E850E945D40122FB8\r
+:1024A00039874983B52FF62FE72FF82E092FA0E0A3\r
+:1024B0000E947B4084F421503F4F4F4F5F4F6F4F3E\r
+:1024C0007F4F8F4F9F4F122F39874983B52FF62F9C\r
+:1024D000E72FF82E092F212F398549815B2F6F2F88\r
+:1024E0007E2F8F2D902F08E00E943F402983F32FED\r
+:1024F0006A017B01E82F192FD10197968D919C914C\r
+:102500009897092E000CAA0BBB0B4C015D01BB0C6C\r
+:102510008808982C54019C01AD01682D782D882DD8\r
+:10252000982D04E00E942640A980BF2E0E2F0E9405\r
+:102530005D400E94D34120E030E040E85BE30E9430\r
+:10254000B54208C060E070E080EC9FE703C060E047\r
+:1025500070E0CB016D960FB6F894DEBF0FBECDBF15\r
+:10256000DF91CF911F910F91FF90EF90DF90CF906F\r
+:10257000BF90AF909F908F907F906F905F904F90A3\r
+:102580003F902F9008954F925F926F927F928F921B\r
+:102590009F92AF92BF92CF92DF92EF92FF92CF9332\r
+:1025A000DF9300D000D000D0CDB7DEB79E838D83FF\r
+:1025B0000E942C0F6DEF8D819E810E947C0DA0E00A\r
+:1025C000B0E0811520E89207A105B10509F4D3C058\r
+:1025D000ED81FE8185849684A784B088FCE29F1AF1\r
+:1025E000F1E0AF0AB1083EE0880F991FAA1FBB1F98\r
+:1025F0003A95D1F7ED81FE8141A952A9052E000C33\r
+:10260000660B770B24E1440F551F661F771F2A9531\r
+:10261000D1F76C017D01C41AD50AE60AF70AA3A90D\r
+:10262000B4A9A50194010E94EE3EA7019601261BC4\r
+:10263000370B480B590BCA01B901705C8F4F9F4F84\r
+:10264000412C30E8532E612C712CA30192010E9481\r
+:10265000C43E29833A834B835C83ED81FE81A0A92C\r
+:10266000B0E0A50194010E94E33E20E038E040E0A4\r
+:1026700050E00E94C43E69017A01F0E8DF0EE11CDF\r
+:10268000F11CED81FE81A5A90A2E000CBB0BA50152\r
+:1026900094010E94EE3E812C44E0942EA12CB12C9A\r
+:1026A000A50194010E94C43ECA01B901A701960187\r
+:1026B0000E94863EA50194010E94C43E405E5F4F89\r
+:1026C000ED81FE81A6A5B7A50E94EE3E705E8F4FFC\r
+:1026D0009F4F20E030E440E050E00E94C43E69811A\r
+:1026E0007A818B819C810E94863E6B017C01A301D3\r
+:1026F00092010E94C43ECA01B9010E94863E9B011C\r
+:10270000AC0167E055954795379527956A95D1F7C0\r
+:10271000ED81FE81A5A5B0E00E94E33E20E130E01E\r
+:1027200040E050E00E94C43ED701C601821B930BDB\r
+:10273000A40BB50BB7FF03C080E090E0DC01813053\r
+:102740009105A105F9E1BF0724F080E090E0A0E049\r
+:10275000B9E1BC01CD012CE09595879577956795FA\r
+:102760002A95D1F70E94D94120E030E040E85AE3B1\r
+:102770000E94B54204C060E070E080EC9FE72696BE\r
+:102780000FB6F894DEBF0FBECDBFDF91CF91FF90A3\r
+:10279000EF90DF90CF90BF90AF909F908F907F9001\r
+:1027A0006F905F904F900895CF92DF92EF92FF92DB\r
+:1027B0006A017B010E94DD0F20E030E048EC52E42A\r
+:1027C0000E942B41A70196010E942B4121E03EED82\r
+:1027D00042E45EE30E9422439B01AC0160E070E0B2\r
+:1027E00080E89FE30E94BE4020E03AE24DE257E4D9\r
+:1027F0000E94B542FF90EF90DF90CF900895CF9266\r
+:10280000DF92EF92FF920F931F93CB01BA01680101\r
+:10281000790120E03AE24DE257E40E942B419B010E\r
+:10282000AC0160E070E080E89FE30E94BE4026EFCC\r
+:1028300038E248EA50E40E9422439B01AC01C70100\r
+:10284000B6010E942B411F910F91FF90EF90DF90F6\r
+:10285000CF900895FC0161857285838594850895E4\r
+:10286000FC012189328943895489A5E0B0E00E94A6\r
+:10287000E33E672F782F892F992787FD9A950E942D\r
+:10288000DB4120E030E048EC52E40E942B41089507\r
+:10289000CF93DF93EC01CB01BA0120E030E048ECAC\r
+:1028A00052E40E94B5420E949D41982F872F762FB7\r
+:1028B000662725E030E040E050E00E94C43E298BCE\r
+:1028C0003A8B4B8B5C8BDF91CF9108950F931F93C5\r
+:1028D000CF93DF938C01EB0188E2FB0111928A9583\r
+:1028E000E9F74BE050E06BE771E0CE010E94CA458A\r
+:1028F0001B8681E090E0A0E0B0E08C879D87AE87EA\r
+:10290000BF87F80180819181092E000CAA0BBB0BB7\r
+:10291000888B998BAA8BBB8B8DE090E0A0E0B0E018\r
+:102920008C8B9D8BAE8BBF8B1CA21DA21EA21FA2E7\r
+:1029300080E090E0A0E2B2EC8C8F9D8FAE8FBF8FD5\r
+:1029400080E090E0AAEAB2E4888F998FAA8FBB8FCB\r
+:102950008AE097EDA3E2BCE388A399A3AAA3BBA353\r
+:10296000DF91CF911F910F910895CF93DF93EB01EA\r
+:1029700024E2FB0111922A95E9F744E250E060E07D\r
+:1029800070E0488359836A837B83FC018081918155\r
+:10299000092E000CAA0BBB0B8C839D83AE83BF83D7\r
+:1029A0008DE090E0A0E0B0E088879987AA87BB8798\r
+:1029B0000E94CB0A288B398B4A8B5B8B8AE994E087\r
+:1029C0000E942C0F6C8B7D8B8E8B9F8B81E0DF9117\r
+:1029D000CF9108950F931F93CF93DF938C01EB0159\r
+:1029E00088E2FB0111928A95E9F74BE050E06BE732\r
+:1029F00071E0CE010E94CA451B8681E090E0A0E014\r
+:102A0000B0E08C879D87AE87BF87F8018081918178\r
+:102A1000092E000CAA0BBB0B888B998BAA8BBB8B46\r
+:102A200086E090E0A0E0B0E08C8B9D8BAE8BBF8BFE\r
+:102A30001CA21DA21EA21FA280E090E0A6E9B3E4A2\r
+:102A40008C8F9D8FAE8FBF8F80E090E8A9E8B4E4B3\r
+:102A5000888F998FAA8FBB8F86EA9BE9A4E4BCE399\r
+:102A600088A399A3AAA3BBA3DF91CF911F910F9134\r
+:102A70000895CF93DF93EB0124E2FB0111922A9595\r
+:102A8000E9F744E250E060E070E0488359836A83EC\r
+:102A90007B83FC0180819181092E000CAA0BBB0B6A\r
+:102AA0008C839D83AE83BF8386E090E0A0E0B0E09E\r
+:102AB00088879987AA87BB870E94CB0A288B398B86\r
+:102AC0004A8B5B8B8AE994E00E94DD0F20E030E0C6\r
+:102AD00048EC52E40E942B416C8B7D8B8E8B9F8B3C\r
+:102AE00081E0DF91CF9108950F931F93CF93DF93F0\r
+:102AF0008C01EB0188E2FB0111928A95E9F74BE02A\r
+:102B000050E06BE771E0CE010E94CA451B8681E070\r
+:102B100090E0A0E0B0E08C879D87AE87BF87F8018A\r
+:102B200080819181092E000CAA0BBB0B888B998B9D\r
+:102B3000AA8BBB8B8CE090E0A0E0B0E08C8B9D8BEF\r
+:102B4000AE8BBF8B1CA21DA21EA21FA21C8E1D8EAF\r
+:102B50001E8E1F8E80E090E0A8ECB2E4888F998FE3\r
+:102B6000AA8FBB8F80E090E0A0E4B0E488A399A393\r
+:102B7000AAA3BBA3DF91CF911F910F910895CF938B\r
+:102B8000DF93EB0124E2FB0111922A95E9F744E27D\r
+:102B900050E060E070E0488359836A837B83FC01E6\r
+:102BA00080819181092E000CAA0BBB0B8C839D8325\r
+:102BB000AE83BF838CE090E0A0E0B0E08887998787\r
+:102BC000AA87BB870E94CB0A288B398B4A8B5B8BE9\r
+:102BD0008AE994E00E94C3126C8B7D8B8E8B9F8B55\r
+:102BE00081E0DF91CF910895CF93DF93EC010E94B4\r
+:102BF000DB071A828CE78CAB8AE08DAB8EE78EAB5D\r
+:102C00008FEA8FAB88AF82EA89AF1AAE80E88BAFCC\r
+:102C1000DF91CF910895CF93DF9300D0CDB7DEB78A\r
+:102C20004A83698342E0BE016F5F7F4F0E94BE0806\r
+:102C30000F900F90DF91CF9108950F93CF93DF9373\r
+:102C40001F92CDB7DEB79A01698301E041E0BE0172\r
+:102C50006F5F7F4F0E9406090F90DF91CF910F9118\r
+:102C600008950F93CF93DF931F92CDB7DEB79A01EC\r
+:102C7000698302E041E0BE016F5F7F4F0E94060959\r
+:102C80000F90DF91CF910F9108950F931F93CF93E2\r
+:102C9000DF9300D0CDB7DEB78A01AE014F5F5F4F43\r
+:102CA0000E943116882341F029813A813227232757\r
+:102CB0003227F801318320830F900F90DF91CF915D\r
+:102CC0001F910F9108950F93CF93DF931F92CDB76C\r
+:102CD000DEB76983022F9E012F5F3F4F41E0B901AC\r
+:102CE0000E9406090F90DF91CF910F91089540EF58\r
+:102CF00060E10E940B16EFE2F5E73197F1F700C0B3\r
+:102D0000000008950F931F93CF93DF9300D0CDB7AA\r
+:102D1000DEB78C01AE014F5F5F4F60E00E9431165D\r
+:102D20008FE295E70197F1F700C0000089819A8151\r
+:102D30008036E1E09E0721F4F801128281E008C0AC\r
+:102D40008136914021F481E0F801828301C080E066\r
+:102D50000F900F90DF91CF911F910F9108950F93D6\r
+:102D60001F93CF93DF931F92CDB7DEB78C0140E066\r
+:102D700062E10E940B16811108C08FE295E701976E\r
+:102D8000F1F700C0000080E016C04CEC62E1C80121\r
+:102D90000E940B16882389F38FE295E70197F1F7DC\r
+:102DA00000C00000AE014F5F5F4F60E2C8010E94AB\r
+:102DB0001D16882311F30F90DF91CF911F910F9172\r
+:102DC00008950F931F93CF93DF9300D01F92CDB739\r
+:102DD000DEB78C010E94AF16882359F18FE295E788\r
+:102DE0000197F1F700C000004EE062E1C8010E94C7\r
+:102DF0000B168823F1F023E0AE014F5F5F4F6CE4C8\r
+:102E0000C8010E9463168823A1F02981F801238359\r
+:102E10009A8194839B81958391E0273008F490E018\r
+:102E2000F8019283EFE2F5E73197F1F700C0000077\r
+:102E300007C08FE295E70197F1F700C0000080E03E\r
+:102E40000F900F900F90DF91CF911F910F910895E8\r
+:102E5000633021F4FC012281222359F0462F60E1E6\r
+:102E60000E940B16EFE2F5E73197F1F700C0000082\r
+:102E7000089580E00895CF93DF93EC0163E50E940D\r
+:102E8000E6078FE295E70197F1F700C00000CE0159\r
+:102E90000E9477168823A9F0CE010E94821688230B\r
+:102EA00081F061E0CE010E942817882351F0CE0105\r
+:102EB0000E94AF16882329F0CE01DF91CF910C94A8\r
+:102EC000E11680E0DF91CF910895CF93DF936115F4\r
+:102ED0007105D9F0EC017F836E8361E00E942817B1\r
+:102EE000882399F0CE010E94AF16882371F042EC3E\r
+:102EF00062E1CE010E940B16882339F0EFE2F5E77C\r
+:102F00003197F1F700C0000007C08FE295E7019705\r
+:102F1000F1F700C0000080E0DF91CF9108956F923B\r
+:102F20007F928F929F92AF92BF92CF92DF92EF9259\r
+:102F30000F931F93CF93DF931F92CDB7DEB73C0162\r
+:102F4000CB01342FE02FAFE2B5E71197F1F700C0C6\r
+:102F5000000068E170E00E94B03E8B014FEF460F29\r
+:102F60004295440F440F407C311140622111406171\r
+:102F7000E1114860E110446060E4C3010E940B1657\r
+:102F8000882309F471C0A80141505109569547950D\r
+:102F90005695479561E4C3010E940B16882309F4F6\r
+:102FA00063C0A6015695479562E4C3010E940B16C3\r
+:102FB000882309F459C0A5015695479563E4C301D8\r
+:102FC0000E940B16882309F44FC0A401569547951B\r
+:102FD00064E4C3010E940B16811146C049895A89D5\r
+:102FE0005695479565E4C3010E940B1681113CC0BC\r
+:102FF000F3014681415066E4C3010E940B16811122\r
+:1030000033C0D30116968D919C911797019711F4B7\r
+:1030100040E801C040E067E4C3010E940B1688232A\r
+:1030200019F1EFE2F5E73197F1F700C00000AE01CA\r
+:103030004F5F5F4F6FE4C3010E941D168823A1F00C\r
+:10304000AFE2B5E71197F1F700C00000F301268168\r
+:103050003781B901606C498150E06417750729F028\r
+:103060002F5F3F4F3783268380E00F90DF91CF9112\r
+:103070001F910F91EF90DF90CF90BF90AF909F90F6\r
+:103080008F907F906F900895AB0160E20C941D16B5\r
+:103090000F93CF93DF931F92CDB7DEB79B0141E231\r
+:1030A000498305E041E0BE016F5F7F4F0E94060942\r
+:1030B0000F90DF91CF910F9108950F931F93CF93AE\r
+:1030C000DF93CDB7DEB729970FB6F894DEBF0FBEFA\r
+:1030D000CDBF8C016623F1F0AE01475F5F4F60E228\r
+:1030E000C8010E941D168823E9F087EB9BE0019739\r
+:1030F000F1F700C00000898581FFEECF898581FF4F\r
+:1031000011C027E0AE014F5F5F4F61E2C8010E942E\r
+:10311000631608C0AE01475F5F4F60E20E941D1654\r
+:103120008111ECCF80E029960FB6F894DEBF0FBE78\r
+:10313000CDBFDF91CF911F910F9108950F931F93F2\r
+:10314000CF93DF93CDB7DEB729970FB6F894DEBFE4\r
+:103150000FBECDBF8C016623C1F087EB9BE00197CA\r
+:10316000F1F700C00000AE01475F5F4F60E2C801A9\r
+:103170000E941D16811102C080E00AC1898580FF6E\r
+:10318000ECCF898580FFF8CF09C0AE01475F5F4F64\r
+:1031900060E20E941D168111F4CFEECF28E0AE014F\r
+:1031A0004F5F5F4F68E4C8010E946316882321F3D4\r
+:1031B00069817A8180E090E00E94D94120E030E08E\r
+:1031C00040E05AE30E94B5429B01AC0160E070E030\r
+:1031D00080E090E40E9422430E94A441F8016787A6\r
+:1031E000708B818B928B6B817C8180E090E00E9460\r
+:1031F000D94120E030E040E05AE30E94B5429B0113\r
+:10320000AC0160E070E080E090E40E9422430E9404\r
+:10321000A441F801678B708F818F928F6D817E81C1\r
+:1032200080E090E00E94D94120E030E040E05AE3A5\r
+:103230000E94B5429B01AC0160E070E080E090E448\r
+:103240000E9422430E94A441F801678F70A381A3CA\r
+:1032500092A36F81788580E090E00E94D94120E0C0\r
+:1032600030E040E05AE30E94B5429B01AC0160E0CF\r
+:1032700070E080E090E40E9422430E94A441F801A3\r
+:1032800067A370A781A792A728E0AE014F5F5F4FA9\r
+:1032900068E2C8010E946316882309F46DCF698132\r
+:1032A0007A8180E090E00E94D94120E030E040E067\r
+:1032B0005AE30E94B5429B01AC0160E070E080E0FF\r
+:1032C00090E40E9422430E94A441F801638B748B16\r
+:1032D000858B968B6B817C8180E090E00E94D94148\r
+:1032E00020E030E040E05AE30E94B5429B01AC018F\r
+:1032F00060E070E080E090E40E9422430E94A441DC\r
+:10330000F801638F748F858F968F6D817E8180E049\r
+:1033100090E00E94D94120E030E040E05AE30E9472\r
+:10332000B5429B01AC0160E070E080E090E40E9457\r
+:1033300022430E94A441F80163A374A385A396A32A\r
+:103340006F81788580E090E00E94D94120E030E0F4\r
+:1033500040E05AE30E94B5429B01AC0160E070E09E\r
+:1033600080E090E40E9422430E94A441F80163A7F8\r
+:1033700074A785A796A7AE014F5F5F4F68E3C801AA\r
+:103380000E941D16882309F4F7CE9981F80193ABAA\r
+:1033900029960FB6F894DEBF0FBECDBFDF91CF9157\r
+:1033A0001F910F910895CF93DF9300D000D0CDB738\r
+:1033B000DEB769837A834B835C8324E0AE014F5F81\r
+:1033C0005F4F63E10E9469080F900F900F900F907C\r
+:1033D000DF91CF9108958F929F92AF92BF92CF923B\r
+:1033E000DF92EF92FF920F931F93CF93DF93EC0145\r
+:1033F0004A015B01C901B80120E030E040E054E43B\r
+:103400000E94B5420E94A4416B017C0123E333E991\r
+:1034100048E853E4C501B4010E94BF4020E030E019\r
+:1034200040E852E40E94B5420E94A441A601CE01A8\r
+:10343000DF91CF911F910F91FF90EF90DF90CF9090\r
+:10344000BF90AF909F908F900C94D319FC0187810F\r
+:1034500090858330910540F4880F991FFC01EC5949\r
+:10346000FE4F8081918108958CE095E00895289821\r
+:1034700020981CBC2C9824B12F7024B921B12F7C2A\r
+:1034800021B922B12F7C22B9FC011682089560E097\r
+:1034900070E0CB010E949F0A0196C9F30895611163\r
+:1034A00002C00E94471A8FEF08956EBD0DB407FE4B\r
+:1034B000FDCF8EB50895289A08952898089595B15E\r
+:1034C00081E0892785B9089514980895149A08957C\r
+:1034D00083B186FB882780F9089580B185FB882712\r
+:1034E00080F908952AE0FC0121871E9B06C0FC019B\r
+:1034F00021852111FACF80E0089581E0089524E626\r
+:10350000FC012187059906C0FC0121852111FACF14\r
+:1035100080E0089581E0089524E6FC012187059B61\r
+:1035200006C0FC0121852111FACF80E0089581E0D9\r
+:1035300008950F931F93CF93DF93EC01162F0E94F2\r
+:10354000641ACE010E94721A082F612F6F73CE0188\r
+:103550000E94551ACE010E94661A802FDF91CF91EA\r
+:103560001F910F910895FF920F931F93CF93DF93B5\r
+:10357000EC01062FF42E0E94641ACE010E94721AEA\r
+:10358000182F602FCE010E94551A6F2DCE010E9478\r
+:10359000551A8A838D8181608D83CE010E94661ABF\r
+:1035A0008A8580FF2BC01F92FF921F920F9382E9A2\r
+:1035B00094E09F938F930E9467460F900F900F9017\r
+:1035C0000F900F900F90112389F08D8182FF0EC014\r
+:1035D0008A811F928F9383E894E09F938F930E9438\r
+:1035E00067460F900F900F900F9008C08EE794E001\r
+:1035F0009F938F930E9467460F900F90812FDF91CA\r
+:10360000CF911F910F91FF900895AF92BF92CF92EB\r
+:10361000DF92EF92FF920F931F93CF93DF93EC0112\r
+:10362000B42ED52E022F6F73162F10640E94641AC9\r
+:10363000CE010E94721AC82E612FCE010E94551A27\r
+:10364000EB2CFD2C5701D02EDD2041F0F5016191CE\r
+:103650005F01CE010E94551ADA94F6CFCE010E9486\r
+:10366000661A8A8581FF46C01F731F921F9382E6E8\r
+:1036700094E09F938F930E9467460F900F900F9056\r
+:103680000F90102F8AE5A82E84E0B82E112379F030\r
+:10369000F70181917F011F928F93BF92AF920E9499\r
+:1036A000674611500F900F900F900F90EFCF85E568\r
+:1036B00094E09F938F930E9467460F900F90CC20C9\r
+:1036C00089F08D8182FF0EC08A811F928F9386E4DC\r
+:1036D00094E09F938F930E9467460F900F900F90F6\r
+:1036E0000F9008C081E494E09F938F930E946746F7\r
+:1036F0000F900F908C2DDF91CF911F910F91FF9024\r
+:10370000EF90DF90CF90BF90AF900895EF92FF922F\r
+:103710000F931F93CF93DF93EC017A016F73162FF2\r
+:1037200010680E94641ACE010E94721A082F612F3D\r
+:10373000CE010E94551A8A838D8181608D8360E05D\r
+:10374000CE010E94551AF7018083CE010E94661AAD\r
+:103750008A8582FF2EC01F731F921F9385E294E01B\r
+:103760009F938F930E9467460F900F900F900F903A\r
+:103770000023B9F08D8180FF14C08A811F928F933E\r
+:10378000F70180811F928F938FE094E09F938F9336\r
+:103790000E9467460F900F900F900F900F900F9020\r
+:1037A00008C08AE094E09F938F930E9467460F9031\r
+:1037B0000F90802FDF91CF911F910F91FF90EF908D\r
+:1037C0000895AF92BF92CF92DF92EF92FF920F9344\r
+:1037D0001F93CF93DF938C01D62FB42ED52EC22FFB\r
+:1037E0000E94641AC8010E94721AC82E6D2F606C64\r
+:1037F000C8010E94551AEB2CFD2C5701DC2EDD2050\r
+:1038000049F060E0C8010E94551AF50181935F01FB\r
+:10381000DA94F5CFC8010E94661AF801828583FF09\r
+:1038200031C01F92CF93DF731F92DF9383EE93E03B\r
+:103830009F938F930E9467460F900F900F900F9069\r
+:103840000F900F90CC20B1F00BED13E0CC2379F06A\r
+:10385000F70181917F011F928F931F930F930E9415\r
+:103860006746C1500F900F900F900F90EFCF89EDEA\r
+:1038700093E002C084ED93E09F938F930E9467468C\r
+:103880000F900F908C2DDF91CF911F910F91FF9092\r
+:10389000EF90DF90CF90BF90AF90089521E00C940F\r
+:1038A000E11B9B01205331092E30310510F40C949B\r
+:1038B0004E1C80E00895AF92BF92CF92DF92EF92BC\r
+:1038C000FF920F931F93CF93DF93CDB7DEB762972D\r
+:1038D0000FB6F894DEBF0FBECDBF8C01242F8AE057\r
+:1038E000F8018187AB016FE3C8010E94051BF82E28\r
+:1038F000AE014E5E5F4F6AE370E0C8010E944E1C4D\r
+:103900009A899431A1F58F2191F165E370E0C801A6\r
+:103910000E94991AF82E882351F1D12CE12CAE0186\r
+:103920004F5E5F4F65E370E0C8010E944E1CF822B5\r
+:103930008989D81659F0FFE0FE1540F0E1E0F0E08B\r
+:10394000EC0FFD1FEE0DF11D8083E394FF2049F085\r
+:10395000833129F0F8019185D82E9111E0CFFF2411\r
+:10396000F39491E0833109F090E0F92241F56BE3A3\r
+:1039700070E0C8010E94991A80E009C080EC93E0D1\r
+:103980009F938F930E9467460F900F9081E0817004\r
+:1039900062960FB6F894DEBF0FBECDBFDF91CF9118\r
+:1039A0001F910F91FF90EF90DF90CF90BF90AF905D\r
+:1039B0000895222389F0F8018185882369F0AE01FA\r
+:1039C0004E5E5F4F6AE370E0C8010E944E1C2A8978\r
+:1039D0008111EFCF80E001C081E091E0211190E002\r
+:1039E000892329F2AE014F5E5F4F65E370E0C801A5\r
+:1039F0000E944E1C2989882339F0213039F0F801C2\r
+:103A000081858111EFCF02C080E001C081E091E0AB\r
+:103A1000213009F090E0892309F4B9CF8BEC93E0D1\r
+:103A20009F938F930E946746CE0101965C010F9091\r
+:103A30000F908C0183ECC82E83E0D82E802F8A193A\r
+:103A40008E1508F09BCFF80181918F011F928F9303\r
+:103A5000DF92CF920E9467460F900F900F900F90C9\r
+:103A6000EDCF3F924F925F926F927F928F929F9293\r
+:103A7000AF92BF92CF92DF92EF92FF920F931F937C\r
+:103A8000CF93DF93CDB7DEB767970FB6F894DEBF5D\r
+:103A90000FBECDBF6C01611105C046E062E00E941F\r
+:103AA000B31A14C1623008F010C189E696E09F9302\r
+:103AB0008F930E9467460F900F9080E090E0EE2475\r
+:103AC000EA94FE2C512C34E1432E49EF642E45E05C\r
+:103AD000742E53EF852E55E0952E2FEF30E03E8B60\r
+:103AE0002D8B5C013FEFA31AB30A9F938F9387E25C\r
+:103AF00096E09F938F930E946746AE014B5E5F4FA7\r
+:103B000065E370E0C6010E944E1C0F900F900F906D\r
+:103B10000F90811109C024E236E03F932F930E9459\r
+:103B200067460F900F900EC08E898F938D898F936B\r
+:103B3000EDE1F6E0FF93EF930E9467460F900F9040\r
+:103B40000F900F908F8989831F925F921F924F92DF\r
+:103B50008FEF95E09F938F930E9467468E010E5FD3\r
+:103B60001F4F0F900F900F900F900F900F90312CD0\r
+:103B7000832D8A0DF80181938F011F928F937F927D\r
+:103B80006F920E94674633940F900F900F900F90A2\r
+:103B9000F3E13F12EDCF9F928F920E94674644E17E\r
+:103BA000BE016F5F7F4FC6010E945B1C0F900F909C\r
+:103BB000811171C084E690E00E940B0A80EF95E0CD\r
+:103BC0009F938F930E9467460F900F902FEFE216FE\r
+:103BD000F20609F45EC03BE2E316F10429F08DE23F\r
+:103BE000E816F10431F00CC091E0951558F45A94A0\r
+:103BF0000EC0552051F0E9E0E51548F0539407C098\r
+:103C0000512C05C05524539402C08AE0582EF5E08B\r
+:103C10005F9E800111240B52194F41E050E0B80122\r
+:103C2000CE0147960E94A84586E596E09F938F9324\r
+:103C30000E9467460F5F1F4F1F930F930E946746B6\r
+:103C400081E596E09F938F930E9467464F896EE3CC\r
+:103C5000C6010E94B31A0F900F900F900F900F9013\r
+:103C60000F90882371F08F891F928F938EE396E0D7\r
+:103C70009F938F930E9467460F900F900F900F9025\r
+:103C800008C088E396E09F938F930E9467460F9049\r
+:103C90000F90C50122CF84E690E00E94200A60EDDB\r
+:103CA00077E080E090E00E94BA0A7C012DEE35E0DA\r
+:103CB0003F932F930E9467460F900F909BE1E91668\r
+:103CC000F10409F083CF80E001C08FEF67960FB653\r
+:103CD000F894DEBF0FBECDBFDF91CF911F910F9142\r
+:103CE000FF90EF90DF90CF90BF90AF909F908F901C\r
+:103CF0007F906F905F904F903F9008958F929F922A\r
+:103D0000AF92BF92CF92DF92EF92FF920F931F93E9\r
+:103D1000CF93DF9300D0CDB7DEB78C014B015A01B2\r
+:103D2000C22EFA01108282E3F801818785818B7FA0\r
+:103D30008583AE014E5F5F4F6BE370E0C8010E9468\r
+:103D40004E1CF82E882309F446C08A818F7709F427\r
+:103D500046C0D82E8FEA94E00197F1F700C000002A\r
+:103D6000AE014E5F5F4F6BE370E0C8010E944E1CD6\r
+:103D7000882321F09A819F77E92E01C0ED2CF8016C\r
+:103D8000218591E0211101C090E0F92EF82219F16E\r
+:103D9000DE1411F0DE2CDECFF80185818270D82E82\r
+:103DA00090E044962E2D30E08217930769F19F939F\r
+:103DB0008F93F50180811F928F9385E993E09F9304\r
+:103DC0008F930E946746F50110820F900F900F901D\r
+:103DD0000F900F900F90F12C02C0E11056C06AE3D3\r
+:103DE00070E0C8010E94991A8F210F900F90DF9107\r
+:103DF000CF911F910F91FF90EF90DF90CF90BF90E8\r
+:103E0000AF909F908F9008959F938F938EE793E04C\r
+:103E10009F938F930E9467460F900F900F900F9083\r
+:103E2000F4E1FC1518F42E2D2D1901C02C2DF501EF\r
+:103E30002083A4016FEFC8010E94E11BF5018111ED\r
+:103E400002C01082C8CF8081E81ADE1430F684E602\r
+:103E500093E09F938F930E9467460F900F90AE015F\r
+:103E60004F5F5F4F6FEFC8010E94861BEA94DE141C\r
+:103E7000B0F3DD2009F4AFCF22E0A8014D5F5F4F22\r
+:103E80006FEFC8010E94E11BA6CF22E0A8014D5FA1\r
+:103E90005F4F6FEFC8010E94E11BF82E882309F4E1\r
+:103EA0009ACFF80185818460858399CF3F924F92A4\r
+:103EB0005F926F927F928F929F92AF92BF92CF92BA\r
+:103EC000DF92EF92FF920F931F93CF93DF93CDB7C3\r
+:103ED000DEB767970FB6F894DEBF0FBECDBF8C017B\r
+:103EE000611105C046E062E00E94B31A61C1623010\r
+:103EF00008F05DC180E090E07C012FEFE21AF20A49\r
+:103F00009F938F9386ED95E09F938F930E946746D2\r
+:103F100064E370E0C8010E94991A0F900F900F900F\r
+:103F20000F908FEF90E09E8B8D8BAE014B5E5F4FBD\r
+:103F300065E370E0C8010E944E1C81110EC083ED44\r
+:103F400095E09F938F930E9467469FE7EFE4F2E12D\r
+:103F50009150E040F040E1F714C060E070E0CB0128\r
+:103F60000E949F0A019691F089EC95E09F938F93B0\r
+:103F70000E9467468FE79FE4E2E181509040E04075\r
+:103F8000E1F700C000000F900F9019C08D899E8945\r
+:103F90008130910571F480EC95E09F938F930E949E\r
+:103FA0006746FFE72FE482E1F15020408040E1F7CF\r
+:103FB000E8CF8D30910519F0419709F0B2CF8D8986\r
+:103FC0009E898D30910521F0419711F0C70194CF62\r
+:103FD0008FEA95E09F938F930E9467460F900F9012\r
+:103FE00080E6482E85E0582E94E5692E95E0792EDE\r
+:103FF00026E7C22E25E0D22E3EE7A32E35E0B32ED3\r
+:104000004FE9842E45E0942EAE014B5E5F4F65E391\r
+:1040100070E0C8010E944E1C81110EC0ECEAF5E070\r
+:10402000FF93EF930E9467468FE79FE4E2E18150A0\r
+:104030009040E040E1F72EC060E070E0CB010E94CC\r
+:104040009F0A019691F082EA95E09F938F930E94D8\r
+:1040500067462FE78FE492E1215080409040E1F7DE\r
+:1040600000C000000F900F90A2C0AE01495E5F4FEC\r
+:104070006BE370E0C8010E944E1C81110EC09F923C\r
+:104080008F920E946746EFE7FFE422E1E150F040A3\r
+:104090002040E1F700C0000071C08F89843108F42E\r
+:1040A0006FC024E1AE01495E5F4FBE016F5F7F4F7D\r
+:1040B000C8010E947E1E882309F462C08F8988236C\r
+:1040C00009F45EC084E690E00E94200A8AE995E047\r
+:1040D0009F938F930E946746F80185810F900F9000\r
+:1040E00082FF24C084818F771F928F938381282F32\r
+:1040F000082E000C330B3F938F9383E895E09F933A\r
+:104100008F930E946746F80184810F900F900F9063\r
+:104110000F900F900F9087FF03C0BF92AF9202C025\r
+:10412000DF92CF920E9467460F900F908F891F9267\r
+:104130008F935F924F920E9467460F900F900F905F\r
+:104140000F90312C8F893816A8F4E1E0F0E0EC0FE5\r
+:10415000FD1FE30DF11D80811F928F938AE595E08D\r
+:104160009F938F930E94674633940F900F900F9008\r
+:104170000F90E8CF7F926F920E9467460F900F904A\r
+:104180008D899E898D30910509F43ECF813191054D\r
+:1041900009F43ACF9F938F9380E495E09F938F9398\r
+:1041A0000E9467460F900F900F900F900FCF8FEFE8\r
+:1041B00067960FB6F894DEBF0FBECDBFDF91CF91EB\r
+:1041C0001F910F91FF90EF90DF90CF90BF90AF9035\r
+:1041D0009F908F907F906F905F904F903F90089549\r
+:1041E000FC012681222389F0278130852130310589\r
+:1041F00031F038F02230310541F40C94561F0C9404\r
+:10420000311D611102C00E94471A8FEF0895AF92CD\r
+:10421000BF92CF92DF92EF92FF920F931F93CF93B3\r
+:10422000DF93CDB7DEB729970FB6F894DEBF0FBE88\r
+:10423000CDBF7C0182E693E09F938F930E946746F7\r
+:1042400086EAC82E86E0D82E0F900F9010E097E5F2\r
+:10425000A92E93E0B92E41E050E0B601CE010996B7\r
+:104260000E94A845AE014F5F5F4F612FC7010E94BA\r
+:10427000861B89859981981751F01F928F93BF9261\r
+:10428000AF920E9467460F900F900F900F901F5FA4\r
+:104290008FEFC81AD80A1F32F1F600E310E0AE0122\r
+:1042A0004F5F5F4FB801C7010E94511C0F5F1F4F46\r
+:1042B0000E331105A1F728E0AE014F5F5F4F6EE3AB\r
+:1042C000C7010E94E11B29960FB6F894DEBF0FBE0E\r
+:1042D000CDBFDF91CF911F910F91FF90EF90DF90B5\r
+:1042E000CF90BF90AF9008951F93CF93DF93EC01D1\r
+:1042F0000E94641A88E28A95F1F7CE010E94661A3C\r
+:1043000088EC8A95F1F7CE010E94641ACE010E94D2\r
+:10431000721A182F60E370E0CE010E94991A81236F\r
+:10432000DF91CF911F910895CF92DF92EF92FF928C\r
+:104330001F93CF93DF931F92CDB7DEB76C0186EA50\r
+:10434000E82E86E0F82E10E041E050E0B701CE0103\r
+:1043500001960E94A8454981612FC6010E94B31AA7\r
+:10436000173039F4998192FF04C0F601958192606B\r
+:1043700095831F5F882331F08FEFE81AF80A1F3208\r
+:1043800019F781E00F90DF91CF911F91FF90EF908F\r
+:10439000DF90CF9008955F926F927F928F929F925D\r
+:1043A000AF92BF92CF92DF92EF92FF920F931F9343\r
+:1043B000CF93DF93CDB7DEB728970FB6F894DEBF63\r
+:1043C0000FBECDBF4C018E010F5F1F4FE12CF12CB2\r
+:1043D00060E0702EC12E84E4A82E83E0B82EDD2488\r
+:1043E000D394D60E6E2C5F2C85E0689FB00111240B\r
+:1043F0006B52794F41E050E0C8010E94A845EAE0C5\r
+:10440000ED1508F4D12CF401828584FF10C0F80169\r
+:1044100080811F928F935F926F92BF92AF920E94A2\r
+:1044200067460F900F900F900F900F900F90FFEF37\r
+:10443000EF1AFF0A0F5F1F4F88E0E816F10411F032\r
+:104440006D2DCDCF28E0472D5C2D6EE3C4010E9479\r
+:10445000051B28960FB6F894DEBF0FBECDBFDF91C7\r
+:10446000CF911F910F91FF90EF90DF90CF90BF9071\r
+:10447000AF909F908F907F906F905F900895CF93B3\r
+:10448000DF93EC012898209A8091640084708093D7\r
+:104490006400149A0C9A2C9A269884B1806B84B983\r
+:1044A00080E58CBD159A0D9889EF94E09F938F93CA\r
+:1044B0000E946746CE010E9474210F900F908111D7\r
+:1044C00003C083EF94E01FC08CED94E09F938F9323\r
+:1044D0000E946746CE010E9494210F900F90811197\r
+:1044E00003C086ED94E00FC080EC94E09F938F931F\r
+:1044F0000E946746CE010E94CB210F900F90811140\r
+:1045000007C08AEB94E09F938F930E9467460EC08A\r
+:1045100087EB94E09F938F930E94674681E08E83A0\r
+:104520008FEF8A87CE010E9407211A860F900F9085\r
+:10453000DF91CF91089524B1287F24B925B1276058\r
+:1045400025B921E0FC0122830895FC01128284B187\r
+:10455000887F84B985B1887F85B90895EF92FF92ED\r
+:104560000F931F93CF93DF9361112CC0EC010AE1ED\r
+:1045700017E08CE0E82E87E0F82E6AE070E080E03B\r
+:1045800090E00E949F0A0196F9F41F930F930E94F6\r
+:1045900067468B811F928F93282F082E000C330BB8\r
+:1045A0003F938F93FF92EF920E9467468DB79EB71D\r
+:1045B00008960FB6F8949EBF0FBE8DBF1A99DDCF37\r
+:1045C0001B82DBCF8FEF01C080E0DF91CF911F9185\r
+:1045D0000F91FF90EF90089583B182FB882780F9B7\r
+:1045E00091E08927089583B180958170089583B102\r
+:1045F0008695817091E089270895FC01828181115F\r
+:1046000002C01382089533B191E0392737953327DB\r
+:104610003795330F330B23B1269521702927279522\r
+:1046200022272795220F220B80E030FB80F920FB08\r
+:1046300081F990911F0198279370D1F490911E01F8\r
+:1046400090FD0EC0982791FF0BC0938181FD04C09F\r
+:104650009F3729F09F5F03C0903809F091509383F2\r
+:1046600080911E0130FB80F920FB81F980931E01AF\r
+:1046700080911F0130FB80F920FB81F980931F019D\r
+:104680000895FC01828193818330910540F4880F65\r
+:10469000991FFC01E659FE4F8081918108958AE9B6\r
+:1046A00091E00895E8EBF0E02DE020832CE12083F9\r
+:1046B00024E6208324E02093BC0020E620937C00A5\r
+:1046C00027E820937A0080579F4F21E0FC01208348\r
+:1046D000089580579F4FFC01108284E08093BC00B6\r
+:1046E0001092B80010927C0010927A0008952F92D8\r
+:1046F0003F924F925F926F927F928F929F92AF9272\r
+:10470000BF92CF92DF92EF92FF920F931F93CF93BE\r
+:10471000DF93CDB7DEB761970FB6F894DEBF0FBE5B\r
+:10472000CDBF8C016111A5C2FC01828193810097EC\r
+:1047300009F0E8C180EB98E09F938F930E94674651\r
+:1047400098012C5F3F4F3D872C8767E7C9010E9486\r
+:104750001A0F0F900F90811103C08DEA98E08BC261\r
+:104760008DE998E09F938F930E94674658013DE33F\r
+:10477000A30EB11CC5010E943B170F900F90811131\r
+:1047800003C08AE998E077C262E0C5010E94281759\r
+:10479000811103C087E998E06EC200E010E022E8D2\r
+:1047A00032E440E050E068EC71E4C5010E94EB198E\r
+:1047B000811103C084E998E05EC281E998E09F938B\r
+:1047C0008F930E9467460F900F908FEF8F83412C3D\r
+:1047D000512C32014E865F86688A798A8C859D8548\r
+:1047E0000E94DD0F20E030E543EC57E40E942B41AE\r
+:1047F0009F938F937F936F93EAE7F8E0FF93EF9394\r
+:104800000E9467468C859D850E942C0F688779875A\r
+:10481000382E292E9F938F9339853F9388858F93C8\r
+:10482000EDE6F8E0FF93EF930E9467468C859D8547\r
+:104830000E94C3124B018A879B879F938F939F92FD\r
+:104840006F9381E698E09F938F930E9467460FB61F\r
+:10485000F894DEBF0FBECDBF3F813F3F09F19A857F\r
+:104860008B85282D392D492F582FFC01682D792D46\r
+:104870008F2F9E2F0E947243811112C07885698507\r
+:10488000C101272F362F492F582FDB01F1016B2F44\r
+:104890007A2F8F2F9E2F0E947243882309F4FBC129\r
+:1048A00065E0C62ED12CE12CF12C05E010E025E0CE\r
+:1048B00030E045E050E063E070E08C859D850E942B\r
+:1048C000F00C8F81803208F413C1E4E5F8E0FF9327\r
+:1048D000EF930E9467460F900F903F8113162CF5BF\r
+:1048E000632F330F770B880B990B0E94DB416B0111\r
+:1048F0007C019B01AC01C301B2010E942B414B0121\r
+:104900008A879B87A70196016E857F85888999890B\r
+:104910000E942B4168877987382E292E412C512CF3\r
+:1049200032014E865F86688A798A9A858B85082D42\r
+:10493000192D292F382FF885E985C1014F2F5E2FBA\r
+:10494000692F722DC5010E94EB19811105C080E508\r
+:1049500098E09F938F93C7C08B858F939A859F9381\r
+:104960009F928F922F923F92E985EF93F885FF9364\r
+:104970002EE338E03F932F930E94674662E0C50123\r
+:104980000E9428170FB6F894DEBF0FBECDBF81116D\r
+:1049900003C08BE398E093C014E687EC9FEA01978D\r
+:1049A000F1F700C00000BE016A5F7F4FC5010E94A1\r
+:1049B0004418882309F48AC08E8181FF87C0BE0114\r
+:1049C0006F5F7F4FC5010E944818882309F481C09A\r
+:1049D00089811F928F93E2E3F8E0FF93EF930E94A7\r
+:1049E00067460F900F900F900F908981833091F060\r
+:1049F00038F4813061F0823099F483E298E012C09B\r
+:104A0000843059F0853061F48BE098E00BC088E287\r
+:104A100098E008C08AE198E005C085E198E002C00E\r
+:104A200089E098E09F938F930E9467460F900F90C4\r
+:104A30008B818F938A818F938BEF97E09F938F93D6\r
+:104A40000E9467468D818F938C818F9320EF37E092\r
+:104A50003F932F930E9467468C819D810FB6F894F7\r
+:104A6000DEBF0FBECDBF8039F1E09F0718F48EEE98\r
+:104A700097E01DC0883522E0920718F484EE97E095\r
+:104A800016C0803233E0930718F48FED97E00FC023\r
+:104A9000883EE3E09E0718F48AED97E008C08C3D5D\r
+:104AA000954018F485ED97E002C081ED97E09F9363\r
+:104AB0008F930E9467460F900F908FEC97E09F9323\r
+:104AC0008F930E9467460F900F9003C0115009F01A\r
+:104AD00064CF61E0C5010E942817811108C02CEC49\r
+:104AE00037E03F932F930E9467460F900F901F82ED\r
+:104AF00068EE73E080E090E00E949F0A019609F45E\r
+:104B00006DCEC1C08130910509F071C007581F4FAB\r
+:104B100061E0C8010E94E607811103C089EC97E0BB\r
+:104B2000AAC09AEA692E97E0792E20EAE22E27E0C1\r
+:104B3000F22E30E9C32E37E0D32E4FE7A42E47E004\r
+:104B4000B42E59E8852E57E0952E80917A00806426\r
+:104B500080937A0080917A0086FDFCCF8091790065\r
+:104B600089831F928F937F926F920E94674641E0E4\r
+:104B7000BE016F5F7F4FC8010E94BE080F900F906B\r
+:104B80000F900F90811106C0FF92EF920E9467462E\r
+:104B90000F900F90DF92CF920E94674641E0BE01D6\r
+:104BA0006F5F7F4FC8010E949B080F900F90882372\r
+:104BB00061F089811F928F939F928F920E94674626\r
+:104BC0000F900F900F900F9006C0BF92AF920E946F\r
+:104BD00067460F900F9068EE73E080E090E00E94CF\r
+:104BE0009F0A019609F4B1CF0E94F0074CC00297CA\r
+:104BF00009F03FC005581F4F40E061E0C8010E9426\r
+:104C00004F09811103C08CE797E035C086E4C82EB8\r
+:104C100087E0D82EC8010E949F097C010196F1F01F\r
+:104C200080917A00806480937A0080917A0086FD7A\r
+:104C3000FCCF60917900C8010E947F0980917900C2\r
+:104C40001F928F93FF92EF92DF92CF920E9467465E\r
+:104C50000F900F900F900F900F900F9060E070E00A\r
+:104C6000CB010E949F0A0196A9F2C8010E945F0928\r
+:104C70000AC082E497E09F938F930E9467460F904B\r
+:104C80000F908FEF29C064EF71E080E090E00E9408\r
+:104C90009F0A80E021C078856985C101272F362FC2\r
+:104CA000492F582F6E857F85888999890E94BF403A\r
+:104CB0006E877F87888B998B9A858B85282D392DD8\r
+:104CC000492F582FC301B2010E94BF402B013C0164\r
+:104CD0008F818F5F8F83E4CD61960FB6F894DEBF2E\r
+:104CE0000FBECDBFDF91CF911F910F91FF90EF903D\r
+:104CF000DF90CF90BF90AF909F908F907F906F90FC\r
+:104D00005F904F903F902F900895FC012281338156\r
+:104D10002230310541F4579A5F9A85589F4F0E947F\r
+:104D2000A4095F9808958091BC0080688093BC00BE\r
+:104D3000089520E620937C0027E820937A00289AA3\r
+:104D4000299824B1236024B95A9A22E02093C800FC\r
+:104D500028E92093C90026E02093CA001092CD00D4\r
+:104D60002BE92093CC0021E0FC0122830895FC0173\r
+:104D7000128210927C0010927A001092C800109259\r
+:104D8000C9001092CA001092CD001092CC005A981F\r
+:104D900084B18C7F84B985B18C7F85B90895CF9219\r
+:104DA000DF92EF92FF920F931F93CF93DF938C01CB\r
+:104DB00061114EC02898299887E0E82E89E0F82EE6\r
+:104DC000CC24CA94DC2CCCEED8E064EF71E080E017\r
+:104DD00090E00E949F0A019609F044C080917A00F9\r
+:104DE000806480937A0080917A0086FDFCCF809168\r
+:104DF000C80080648093C800289A299A809179001D\r
+:104E00008093CE008091C80086FFFCCF2998289817\r
+:104E1000809179001F928F93FF92EF920E946746D4\r
+:104E2000F894F80183819481D482C38278940F909E\r
+:104E30000F900F900F9097FDC8CF9F938F93DF93A4\r
+:104E4000CF930E9467460F900F900F900F90BDCFA9\r
+:104E500088EE98E09F938F930E9467460F900F9083\r
+:104E60008FEF01C080E0DF91CF911F910F91FF90F4\r
+:104E7000EF90DF90CF90089570E0FC01748363831E\r
+:104E800008955F9A08955F9808955E9A08955E98D0\r
+:104E90000895139A0895139808958FEF84B908958B\r
+:104EA00080918804813019F48FEF84B9089514B883\r
+:104EB000089580918804813041F487EB9BE001974D\r
+:104EC000F1F700C0000080E0089583B1089565B94E\r
+:104ED0000895109A0895109808951F93CF93DF9323\r
+:104EE000EC01162F0E944B278FEF84B98A8188230B\r
+:104EF00089F0812F807F85B9CE010E9449278CE3FC\r
+:104F00008A95F1F7CE010E944B2784E08A95F1F74C\r
+:104F10001295107F15B9CE010E9449278CE38A951E\r
+:104F2000F1F7CE010E944B2784E08A95F1F7DF91DB\r
+:104F3000CF911F9108951F93CF93DF93EC01162F0C\r
+:104F40000E944727CE010E944327612FCE01DF91A7\r
+:104F5000CF911F910C946D27EF92FF920F931F93A7\r
+:104F6000CF93DF93EC017B018B8187FD59C080914A\r
+:104F70008804813041F487EB9BE00197F1F700C092\r
+:104F8000000081E04EC0CE010E9450278FEF85B90E\r
+:104F9000CE010E944527CE010E94432794E09A95B6\r
+:104FA000F1F7CE010E9449278CE38A95F1F7CE01F3\r
+:104FB0000E945927082FCE010E944B2794E09A9512\r
+:104FC000F1F7CE010E9449278CE38A95F1F7CE01D3\r
+:104FD0000E94592782958F70007F182F102BCE01C9\r
+:104FE0000E944B2794E09A95F1F7CE010E94472743\r
+:104FF000912F90788BE0E816F10430F08BE0E81AFE\r
+:10500000F10811F09111C4CF8B81813021F49923E3\r
+:1050100011F08BEF8B8315B88FEF84B981E091117C\r
+:1050200080E0DF91CF911F910F91FF90EF90089555\r
+:10503000CF93DF93EC0162E370E00E94AC27811113\r
+:1050400002C08AEF8B83DF91CF9108951F93CF9396\r
+:10505000DF93EC01162F0E941828612F6068CE01A3\r
+:105060000E949B27CE01DF91CF911F910C941828AD\r
+:105070001F93CF93DF93EC0115B88FEF84B98FE7BF\r
+:105080009BEB0197F1F700C000001B8210E08A81C2\r
+:10509000882311F068E201C068E0CE010E949B27DE\r
+:1050A000111105C087E99AE30197F1F704C08BE27B\r
+:1050B00091E00197F1F700C000001F5F143039F74D\r
+:1050C0006CE0CE010E949B2762E370E0CE010E945B\r
+:1050D000AC27811102C08FEF1BC06CE0CE010E9493\r
+:1050E0009B2762E370E0CE010E94AC27811102C0D1\r
+:1050F0008DEF0EC061E0CE010E949B2760EB74E053\r
+:10510000CE010E94AC27811102C08CEF01C081E06A\r
+:105110008B83DF91CF911F910895CF93DF93EC01A3\r
+:1051200081B1896081B98FEF84B98AB1806C8AB905\r
+:10513000CE010E9438288AE499E09F938F930E94C1\r
+:1051400067468B810F900F90813049F486E499E097\r
+:105150009F938F930E9467460F900F9010C0282F47\r
+:10516000082E000C330B3F938F938CE399E09F93B1\r
+:105170008F930E9467460F900F900F900F90CE0173\r
+:10518000DF91CF910C946927CF93DF93FC012381AA\r
+:10519000213061F4EC010E9418286CE0CE010E94DD\r
+:1051A0009B27CE01DF91CF910C941828DF91CF91EE\r
+:1051B0000895CF93DF93FC012381213061F4EC014A\r
+:1051C0000E94182868E0CE010E949B27CE01DF9143\r
+:1051D000CF910C941828DF91CF910895CF93DF934E\r
+:1051E000FC012381213061F4EC010E94182861E068\r
+:1051F000CE010E949B27CE01DF91CF910C941828FD\r
+:10520000DF91CF9108950E94EE2882B1867F82B906\r
+:1052100081B1867F81B915B814B88BB18F738BB902\r
+:105220008AB18F738AB90895CF93DF93EC018B8194\r
+:105230008130B9F44431A8F4613039F048F062307B\r
+:1052400031F0633071F44C5A03C0405C01C04C5ED5\r
+:10525000642FCE010E942628CE01DF91CF910C94BD\r
+:105260001828DF91CF9108951F93CF93DF93FC010E\r
+:1052700023812130A1F4162FEC010E944727CE0193\r
+:105280000E944127612FCE010E946D27CE010E940E\r
+:105290004327CE01DF91CF911F910C941828DF9105\r
+:1052A000CF911F910895FF920F931F93CF93DF9398\r
+:1052B0008C0161114FC0C0E084E1F82ED0E2DC0F18\r
+:1052C0008C2F6F2D0E94963E911105C040E0682FF3\r
+:1052D000C8010E9414296D2FC8010E943429C801F9\r
+:1052E0000E941828CF5FC03549F787E399E09F9364\r
+:1052F0008F930E946746F80183810F900F90813051\r
+:1053000049F484E399E09F938F930E9467460F903E\r
+:105310000F9010C0282F082E000C330B3F938F9353\r
+:105320008AE299E09F938F930E9467460F900F90B7\r
+:105330000F900F9061E070E080E090E00E949F0A83\r
+:105340000196C1F364EF71E080E090E00E949F0A53\r
+:1053500080E009C086E299E09F938F930E946746A0\r
+:105360000F900F908FEFDF91CF911F910F91FF90D2\r
+:1053700008950F931F93CF93DF93EC018B01F801F6\r
+:1053800061918F01662339F08B81813021F4CE0148\r
+:105390000E943429F4CFDF91CF911F910F9108958E\r
+:1053A0008BB18F708BB98AB1806F8AB908958AB139\r
+:1053B0008F708AB98BB18F708BB908958130910548\r
+:1053C00049F030F08230910539F0039739F00895B3\r
+:1053D0005C9A08955D9A08955E9A08955F9A08957B\r
+:1053E000CB0141110C94DE296130710551F038F088\r
+:1053F0006230710541F06330710539F008955C98B1\r
+:1054000008955D9808955E9808955F9808956130B5\r
+:10541000710559F038F06230710551F06330710553\r
+:1054200059F008959BB180E105C09BB180E202C0B4\r
+:105430009BB180E4892702C08BB180588BB9089555\r
+:10544000CB010C94DE2940E00C94F029CF9360311D\r
+:10545000E8F5C62FC370C23091F0C330B9F0C13047\r
+:1054600039F063E070E00E94232A80E090E014C0ED\r
+:1054700060E070E00E94232A81E090E00DC061E0CE\r
+:1054800070E00E94232A82E090E006C062E070E0B3\r
+:105490000E94232A83E090E00E94DE296C2F70E0B6\r
+:1054A0006F5F7F4F7F936F9389E599E09F938F9311\r
+:1054B0000E94674664EF71E080E090E00E949F0ADE\r
+:1054C0000F900F900F900F9080E001C08FEFCF9161\r
+:1054D00008950895FC0112821092C8001092C9002C\r
+:1054E0001092CA001092CD001092CC005A9884B14C\r
+:1054F0008C7F84B985B18C7F85B908952F923F92B6\r
+:105500004F925F926F927F928F929F92AF92BF92D3\r
+:10551000CF92DF92EF92FF920F931F93CF93DF937F\r
+:1055200000D000D0CDB7DEB79C838B83611121C042\r
+:10553000289A299884B1836084B95A9A82E080932A\r
+:10554000C80088E98093C90086E08093CA00109261\r
+:10555000CD008BE98093CC0081E0EB81FC818283DC\r
+:1055600082E49AE09F938F930E9467460F900F907A\r
+:105570003DC18FEF860F843008F06EC0633039F084\r
+:10558000643041F0623051F41EE801E009C015E5D5\r
+:1055900000E002C01AEA01E0F12C04C011E000E0D2\r
+:1055A000FF24F3941F921F931F92FF921F920F9359\r
+:1055B00083E29AE09F938F930E9467460FB6F89418\r
+:1055C000DEBF0FBECDBFFF2011F0289A01C0289882\r
+:1055D000002311F0299A01C02998EBE2F1E03197FC\r
+:1055E000F1F700C00000EB81FC8113821093CE0024\r
+:1055F00087EB9BE00197F1F700C0000083818823CF\r
+:1056000089F084811F928F9383E19AE09F938F9317\r
+:105610000E946746EB81FC8113820F900F900F90E0\r
+:105620000F9008C082E09AE09F938F930E94674694\r
+:105630000F900F9088EE99E09F938F930E9467469A\r
+:105640000F900F906FEF7FEFCB010E949F0A0196A2\r
+:10565000C9F32998289ACAC0653009F0BDC08BEA01\r
+:1056600099E09F938F930E946746299A28988BE22E\r
+:1056700091E00197F1F700C000000F900F908DE9C5\r
+:10568000282E89E0382E95E9492E99E0592E27E8F1\r
+:10569000622E29E0722E35E8832E39E0932E42E8FF\r
+:1056A000E42E49E0F42E5AE7C52E59E0D52E6EE6D9\r
+:1056B000A62E69E0B62E299AEB81FC81138200E7C1\r
+:1056C00011E0F8018091C80080648093C800819146\r
+:1056D0008093CE008091C80085FFFCCF21E0E837A1\r
+:1056E000F20781F78091C80086FFFCCF29983F928E\r
+:1056F0002F920E9467460F900F90F80181918F01C1\r
+:105700001F928F935F924F920E9467460F900F9067\r
+:105710000F900F90F1E008371F0779F764E670E00B\r
+:1057200080E090E00E949F0A9A8389837F926F9223\r
+:105730000E9467460F900F90EB81FC818381882344\r
+:1057400011F010E01FC09F928F920E9467460F9049\r
+:105750000F901DC0183031F4FF92EF920E946746FF\r
+:105760000F900F90EB81FC81E10FF11D84811F925E\r
+:105770008F93DF92CF920E9467461F5F0F900F902A\r
+:105780000F900F90EB81FC818381181718F3EB8148\r
+:10579000FC818381803190F08289918920893785CD\r
+:1057A0003F932F939F938F93BF92AF920E94674630\r
+:1057B0000F900F900F900F900F900F9089819A810A\r
+:1057C0000196A1F468EE73E080E090E00E949F0AE9\r
+:1057D000019609F470CF0AC08AE699E09F938F93EF\r
+:1057E0000E9467460F900F908FEF07C064EF71E043\r
+:1057F00080E090E00E949F0A80E00F900F900F9051\r
+:105800000F90DF91CF911F910F91FF90EF90DF905C\r
+:10581000CF90BF90AF909F908F907F906F905F9050\r
+:105820004F903F902F900895FC012381203130F458\r
+:1058300031E0320F3383E20FF11D648308955798EE\r
+:1058400010927C0010927A0014BC15BC24B1277E03\r
+:1058500024B91398FC011282089580B183FB882734\r
+:1058600080F991E0892708952C9808952C9A08953D\r
+:10587000CF93DF93EC01579A80E680937C0087E812\r
+:1058800080937A0083E884BD84E085BD84B188611B\r
+:1058900084B9139ACE010E94362C81E08A83DF916D\r
+:1058A000CF9108952F923F924F925F926F927F9285\r
+:1058B0008F929F92AF92BF92CF92DF92EF92FF9220\r
+:1058C0000F931F93CF93DF936111E1C0EC0183ED40\r
+:1058D0009AE09F938F930E9467460F900F9083ECFE\r
+:1058E000482E8AE0582E9FEA692E9AE0792E00EA27\r
+:1058F0001AE026E9E22E2AE0F22E3BE8C32E3AE037\r
+:10590000D32E4FE7A42E4AE0B42E5EE4252E5AE0B3\r
+:10591000352E67E6862E6AE0962E6AE070E080E01B\r
+:1059200090E00E949F0A019609F0B3C080B183FB0A\r
+:10593000882780F91F928F9388EC9AE09F938F932A\r
+:105940000E9467460F900F900F900F90CE01039921\r
+:1059500005C00E94342C5F924F9206C00E94362CE4\r
+:105960008EEB9AE09F938F930E9467460F900F9063\r
+:1059700080917A00806480937A0080917A0086FD1D\r
+:10598000FCCF809179001F928F937F926F920E943B\r
+:10599000674682EE80937C008091790090E00597C5\r
+:1059A0000F900F900F900F9097FF02C080E090E053\r
+:1059B000809587BD1F928F931F930F930E94674618\r
+:1059C00080917A00806480937A000F900F900F90FE\r
+:1059D0000F9080917A0086FDFCCF809179001F9214\r
+:1059E0008F93FF92EF920E94674690E690937C001F\r
+:1059F00083B182FB882780F91F928F93DF92CF9229\r
+:105A00000E94674683B181701F928F93BF92AF92BD\r
+:105A10000E946746F8946B817C8178948DB79EB71D\r
+:105A20000C960FB6F8949EBF0FBE8DBF6115710521\r
+:105A300019F17F936F9380E090E00E94D9419B0120\r
+:105A4000AC0160E070E080E792E40E942B4127E126\r
+:105A500037EB41ED58E30E942B410E949D417F931B\r
+:105A60006F939F928F920E9467460F900F900F90B6\r
+:105A70000F900F900F9051CF1F921F923F922F9235\r
+:105A80000E9467460F900F900F900F9046CF8FEFB8\r
+:105A900001C080E0DF91CF911F910F91FF90EF90B7\r
+:105AA000DF90CF90BF90AF909F908F907F906F903E\r
+:105AB0005F904F903F902F90089583B182FB88278D\r
+:105AC00080F991E08927089583B1817008958BB1A1\r
+:105AD00080588BB908951F93CF93DF93EC0123B1C6\r
+:105AE0008091DD049091DE04122F117020FD1BC007\r
+:105AF0002091E104222309F12091DF043091E00498\r
+:105B000023303105D0F0820F931F9C838B8310923A\r
+:105B1000E0041092DF041092DE041092DD04CE0146\r
+:105B20000E94672D0AC0811520E4920748F501966E\r
+:105B30009093DE048093DD040DC08091DF0490918A\r
+:105B4000E004811520E49207F0F401969093E004BC\r
+:105B50008093DF048091DD049091DE0481159044F0\r
+:105B600038F48091DF049091E0048115904410F0A6\r
+:105B70001C821B821093E104DF91CF911F91089545\r
+:105B800080E090E4D5CF80E090E4E0CFE4E6F0E080\r
+:105B9000808184708083179A0F9A2C9A84B1806BCD\r
+:105BA00084B926988CB583658CBD0895269884B1F8\r
+:105BB0008F7584B90F9817981CBC0895179808958D\r
+:105BC000179A08950F931F93CF93DF93EC01062F3D\r
+:105BD000142F0E94DE2D80E48EBD0DB407FEFDCF94\r
+:105BE0000EBD0DB407FEFDCF1EBD0DB407FEFDCFEB\r
+:105BF000CE010E94E02D84E18A95F1F780E0DF91EB\r
+:105C0000CF911F910F9108951F93CF93DF93EC01D4\r
+:105C1000162F0E94DE2D81E48EBD0DB407FEFDCF50\r
+:105C20001EBD0DB407FEFDCF1EBC0DB407FEFDCF9B\r
+:105C3000CE010E94E02D8EB5DF91CF911F91089586\r
+:105C4000CF93DF93C42FD22F1F924F931F926F9346\r
+:105C500086E69BE09F938F930E9467460F900F907C\r
+:105C60000F900F900F900F90CD1769F08FE59BE08C\r
+:105C70009F938F930E9467460F900F90CF3F59F4E8\r
+:105C800084E49BE002C080E49BE09F938F930E949A\r
+:105C900067460F900F908EE39BE09F938F930E9437\r
+:105CA00067460F900F90DF91CF9108952F923F920A\r
+:105CB0004F925F926F927F928F929F92AF92BF921C\r
+:105CC000CF92DF92EF92FF920F931F93CF93DF93C8\r
+:105CD0006111D8C0EC018FE2282E8BE0382ECC2445\r
+:105CE000C394D12C2AE1422E2BE0522E35E0632EB4\r
+:105CF0003BE0732E40EFA42E4AE0B42E5BED852EE0\r
+:105D00005AE0952E64EF71E080E090E00E949F0AD7\r
+:105D1000019609F0B9C03F922F920E9467460F90FA\r
+:105D20000F90E12CF12C86010E2C01C0000F0A947B\r
+:105D3000EAF7402F409560E0CE010E94E22D402F0F\r
+:105D400062E1CE010E94E22DFF92EF925F924F92AC\r
+:105D50000E94674662E1CE010E94042E202F482F48\r
+:105D600062E1CE010E94202E68EC70E080E090E0BD\r
+:105D70000E949F0A40E062E1CE010E94E22DFF9264\r
+:105D8000EF927F926F920E94674662E1CE010E947D\r
+:105D9000042E20E0482F62E1CE010E94202E4FEF1A\r
+:105DA00060E0CE010E94E22D68EC70E080E090E0BF\r
+:105DB0000E949F0A8FEFE81AF80A8DB79EB70896DF\r
+:105DC0000FB6F8949EBF0FBE8DBF98E0E916F104A0\r
+:105DD00009F0A9CF00E010E07601002E01C0EE0C22\r
+:105DE0000A94EAF74E2D409561E0CE010E94E22D23\r
+:105DF0004E2D63E1CE010E94E22D1F930F93BF92BF\r
+:105E0000AF920E94674663E1CE010E94042E2E2DC0\r
+:105E1000482F63E1CE010E94202E68EC70E080E004\r
+:105E200090E00E949F0A40E063E1CE010E94E22DD3\r
+:105E30001F930F939F928F920E94674663E1CE015A\r
+:105E40000E94042E20E0482F63E1CE010E94202E04\r
+:105E50004FEF61E0CE010E94E22D68EC70E080E03F\r
+:105E600090E00E949F0A0F5F1F4F8DB79EB7089664\r
+:105E70000FB6F8949EBF0FBE8DBF0830110509F014\r
+:105E8000ABCF40CF8FEF01C080E0DF91CF911F916A\r
+:105E90000F91FF90EF90DF90CF90BF90AF909F90C9\r
+:105EA0008F907F906F905F904F903F902F900895CC\r
+:105EB00080E480937C0087E880937A0008951092B4\r
+:105EC0007C0010927A0008950F931F93CF93DF9375\r
+:105ED00061113AC088EA9BE09F938F930E946746C6\r
+:105EE0000F900F9003E91BE0C6E8DBE06AE070E08A\r
+:105EF00080E090E00E949F0A019641F51F930F9366\r
+:105F00000E94674680917A00806480937A000F90A7\r
+:105F10000F9080917A0086FDFCCF2091780030911F\r
+:105F2000790080917800909179003F932F939F930F\r
+:105F30008F93DF93CF930E9467460F900F900F903F\r
+:105F40000F900F900F90D2CF8FEF01C080E0DF91C4\r
+:105F5000CF911F910F91089582E480937C0087E890\r
+:105F600080937A00089510927C0010927A00089530\r
+:105F7000AF92BF92CF92DF92EF92FF920F931F9357\r
+:105F8000CF93DF9361117FC081EF9BE09F938F934D\r
+:105F90000E9467460F900F903CEDE32E3BE0F32EFE\r
+:105FA0000FEC1BE0CFEADBE06AE070E080E090E01D\r
+:105FB0000E949F0A019609F068C0FF92EF920E942A\r
+:105FC000674680917A00806480937A000F900F90EA\r
+:105FD00080917A0086FDFCCF209178003091790085\r
+:105FE00080917800909179003F932F939F938F93A6\r
+:105FF0001F930F930E94674660917800709179001B\r
+:1060000080E090E00E94D9412AE939E941E852E470\r
+:106010000E942B412DEC3CEC4CE05FE30E94BF4022\r
+:10602000D62EC72EB82EA92EA6019501652F742F46\r
+:10603000832F922F0E94A441862F90E061701F92BF\r
+:106040006F9381FB222720F91F922F9382FB222737\r
+:1060500020F91F922F9323E0959587952A95E1F7D4\r
+:106060009F938F93AF92BF92CF92DF92DF93CF93A4\r
+:106070000E9467468DB79EB744960FB6F8949EBFB0\r
+:106080000FBE8DBF91CF8FEF01C080E0DF91CF9128\r
+:106090001F910F91FF90EF90DF90CF90BF90AF9046\r
+:1060A0000895442371F06130710539F020F06230B9\r
+:1060B000710529F0089528980895299808952A9837\r
+:1060C00008956130710539F020F06230710529F0D2\r
+:1060D0000895289A0895299A08952A9A0895613072\r
+:1060E000710541F020F06230710539F0089595B1E5\r
+:1060F00081E005C095B182E002C095B184E08927B6\r
+:1061000085B9089541E00C94513040E00C94513031\r
+:10611000CF93DF93EC0160E070E00E94853061E096\r
+:1061200070E0CE010E94853062E070E0CE010E94F6\r
+:10613000853084B1876084B9DF91CF910895CF9382\r
+:10614000DF93EC0160E070E00E94853061E070E078\r
+:10615000CE010E94853062E070E0CE010E94853061\r
+:1061600084B1887F84B9DF91CF910895CF93DF9375\r
+:10617000EC01613009F43FC058F1623009F44EC0BF\r
+:10618000633009F064C060E070E00E94823061E03A\r
+:1061900070E0CE010E94823062E070E0CE010E9489\r
+:1061A000823087EF9BE09F938F930E94674668EB56\r
+:1061B0007BE080E090E00E949F0A60E070E0CE010A\r
+:1061C0000E94853061E070E0CE010E94853036C0CB\r
+:1061D00060E070E00E94823086E09CE09F938F93A5\r
+:1061E0000E94674668EB7BE080E090E00E949F0A97\r
+:1061F00060E070E025C061E070E00E94823080E0E5\r
+:106200009CE09F938F930E94674668EB7BE080E061\r
+:1062100090E00E949F0A61E070E012C062E070E0CE\r
+:106220000E9482308BEF9BE09F938F930E94674682\r
+:1062300068EB7BE080E090E00E949F0A62E070E003\r
+:10624000CE010E9485300F900F9080E001C08FEF4B\r
+:10625000DF91CF91089547983F9AE8EBF0E02DE069\r
+:1062600020832CE1208324E6208324E02093BC00BB\r
+:1062700021E0FC0124830895FC01148284E08093D2\r
+:10628000BC001092B800089585EA9EE00895ECEBFA\r
+:10629000F0E08081806880830895862F86958695BA\r
+:1062A00086958E71982F990F990F890F6F70860FB1\r
+:1062B00008950F931F93CF93DF938C01EA019E857E\r
+:1062C0009C7F92609E8781E0611101C080E09E8585\r
+:1062D00080FB97F99E876F87998180FB90F99B7F60\r
+:1062E00098609983662389F01F929F931F926F9302\r
+:1062F00089EE9CE09F938F930E9467460F900F90CA\r
+:106300000F900F900F900F9008C088ED9CE09F9326\r
+:106310008F930E9467460F900F900E5F1F4F21E0F2\r
+:10632000AE014F5F5F4F61E0C8010E94690888239A\r
+:10633000A1F0AE01425F5F4F22E06EE0C8010E9413\r
+:106340006908C82F882349F085ED9CE09F938F93BF\r
+:106350000E9467460F900F9009C08FEC9CE09F93BE\r
+:106360008F930E9467460F900F90C0E08C2FDF91B3\r
+:10637000CF911F910F910895CF92DF92EF92FF92EC\r
+:106380000F931F93CF93DF937C01EA01479B10C0CB\r
+:1063900080EC9CE09F938F930E9467463F9A4798BA\r
+:1063A000AE0160E0C7010E9459310F900F905CC0B0\r
+:1063B0008EEB9CE09F938F930E9467460F900F9007\r
+:1063C00009E010E08CE7C82E8CE0D82E1F930F93C5\r
+:1063D000DF92CF920E94674668EE73E080E090E023\r
+:1063E0000E94BA0A0F900F900F900F900130110584\r
+:1063F00031F0015011098F3F2FEF920739F34B977E\r
+:1064000099F1AE016AE0C7010E9459318981886023\r
+:106410008B7F81608983AE014F5F5F4F21E061E038\r
+:10642000C70102960E94690888E69CE09F938F93BB\r
+:106430000E9467463F9A479A87E99AE30197F1F7E6\r
+:1064400000C000003F98479868E873E180E090E062\r
+:106450000E94BA0A86E39CE09F938F930E9467464E\r
+:106460000F900F900F900F9081E0DF91CF911F91CF\r
+:106470000F91FF90EF90DF90CF9008958F929F92B1\r
+:10648000AF92BF92CF92DF92EF92FF920F931F9342\r
+:10649000CF93DF93CDB7DEB727970FB6F894DEBF63\r
+:1064A0000FBECDBF4C01362FCA011E2DFC2DEA2D8B\r
+:1064B000BA01605D774051E06536710508F450E03F\r
+:1064C0004E8150FB47F94E8364E670E00E94B03E77\r
+:1064D0006AE00E94963E8295807F982B9F8337FFCB\r
+:1064E00002C0395FFCCF373014F03750FCCF377023\r
+:1064F0008D81887F382B3D83121614F0245FFCCFEA\r
+:106500002D3014F02C50FCCF822F6AE00E94A23E66\r
+:106510009F702E81207F922B80FB94F99E83101612\r
+:1065200014F0015EFCCF003214F00F51FCCF802F2D\r
+:106530006AE00E94A23E9F703C81307C8370282FCD\r
+:106540002295207F832F892B822B8C8317FF02C0FB\r
+:10655000185EFCCF183114F01851FCCF812F6AE07F\r
+:106560000E94A23E9F703B81307C8370282F229531\r
+:10657000207F832F892B822B8B83F7FF02C0F45C53\r
+:10658000FCCFFC3314F0FC53FCCF8F2F6AE00E9449\r
+:10659000A23E9F703A8130788770282F2295207F05\r
+:1065A000832F892B822B8A83E7FF02C0E45CFCCF18\r
+:1065B000EC3314F0EC53FCCF8E2F6AE00E94A23E25\r
+:1065C0009F70398130788770282F2295207F832F04\r
+:1065D000892B822B8983CE0107969F938F930197F6\r
+:1065E0009F938F9301979F938F9301979F938F937F\r
+:1065F00001979F938F9301979F938F938E010F5FC6\r
+:106600001F4F1F930F9384E19CE09F938F930E94F1\r
+:10661000674678015E0188E0A80EB11C0FB6F894B9\r
+:10662000DEBF0FBECDBF8EE0C82E8CE0D82EF701A6\r
+:1066300081917F011F928F93DF92CF920E946746D4\r
+:106640000F900F900F900F90AE14BF0481F727E0CA\r
+:10665000A80162E0C40102960E94690827960FB65D\r
+:10666000F894DEBF0FBECDBFDF91CF911F910F9188\r
+:10667000FF90EF90DF90CF90BF90AF909F908F9062\r
+:1066800008952F923F924F925F926F927F928F92D6\r
+:106690009F92AF92BF92CF92DF92EF92FF920F93B1\r
+:1066A0001F93CF93DF93CDB7DEB76E970FB6F894F5\r
+:1066B000DEBF0FBECDBF611166C22C019C012E5FF3\r
+:1066C0003F4F3D8F2C8F61E5C9010E94E607CE0147\r
+:1066D00001969A8F898F80E1E98DFA8D11928A95C2\r
+:1066E000E9F78FE89EE09F938F930E9467468A8127\r
+:1066F00081608A8342E0BE016F5F7F4F8C8D9D8DEC\r
+:106700000E94BE080F900F90811103C083EF92E0AA\r
+:1067100002C08EEE92E09F938F930E9467460F9087\r
+:106720000F9086E89EE09F938F930E9467468EE6C7\r
+:106730009EE09F938F930E9467468CE49EE09F9318\r
+:106740008F930E94674686E39EE09F938F930E94FB\r
+:1067500067468CE19EE09F938F930E94674686E098\r
+:106760009EE09F938F930E9467468FEE9DE09F93DC\r
+:106770008F930E9467468AED9DE09F938F930E94BE\r
+:10678000674684EC9DE09F938F930E9467468CEA56\r
+:106790009DE09F938F930E94674683E99DE09F93BE\r
+:1067A0008F930E9467460FB6F894DEBF0FBECDBF31\r
+:1067B000188E84E79DE09F938F930E94674600E1C7\r
+:1067C0009E012F5F3F4F41E0BE01685E7F4F8C8D81\r
+:1067D0009D8D0E9406090F900F90811110C083EFCC\r
+:1067E00092E09F938F930E94674668EE73E080E08B\r
+:1067F00090E00E94BA0A4C010F900F90BDC127E0B3\r
+:1068000030E047E050E0BE016D5F7F4FCE01419622\r
+:106810000E94BC459E012F5F3F4F790110E0812F00\r
+:10682000837041F482E79DE09F938F930E946746B7\r
+:106830000F900F90F70181917F011F928F932CE6AB\r
+:106840003DE03F932F930E9467461F5F0F900F908C\r
+:106850000F900F90103119F78E8987FD03C040ED1E\r
+:1068600057E002C044E358E08F89982F969596959B\r
+:1068700096959E71292F220F220F920F8F70890FEC\r
+:106880001A01280E311C8E89982F9695969596950B\r
+:106890009E71792E770C770C790E8F70780E672C9D\r
+:1068A0008C89982F9695969596959E71B92EBB0CCE\r
+:1068B000BB0CB90E8F70B80EBB8E8B89982F969536\r
+:1068C000969596959E71D92EDD0CDD0CD90E8F70A4\r
+:1068D000D80EED2C8A89982F9695969596959E714F\r
+:1068E000F92EFF0CFF0CF90E8F70F80ECF2C898952\r
+:1068F000182F1695169516951E71912F990F990FB1\r
+:10690000190F8F70180FA12E0D890E8F073048F4C4\r
+:10691000E3E00E02C00111249C012255314F4901D0\r
+:1069200004C039E6832E3DE0932E82E69DE09F93DE\r
+:106930008F930E9467469F928F920E946746812F95\r
+:10694000012E000C990B9F931F938F2D0F2C000C81\r
+:10695000990B9F93FF928D2D0D2C000C990B9F93FB\r
+:10696000DF928B2D0B2C000C990B9F93BF92872DE0\r
+:10697000072C000C990B9F937F923F922F92802FB0\r
+:10698000002E000C990B9F930F932FE33DE03F9354\r
+:106990002F930E94674688891F928F93EFE2FDE054\r
+:1069A000FF93EF930E94674668EE73E080E090E00B\r
+:1069B0000E94BA0A4C010FB6F894DEBF0FBECDBFDD\r
+:1069C00094E68916910409F490C0F4F5FEE48F165C\r
+:1069D000910409F494C08CF438E48316910409F40A\r
+:1069E00087C08DE48816910409F47BC094E489166D\r
+:1069F000910409F0C1C0BA9479C0E7E58E169104FC\r
+:106A000009F485C044F423E58216910409F0B4C06A\r
+:106A1000AA24AA9478C039E58316910409F45AC0CF\r
+:106A200083E68816910409F0A7C08AE0A82E9CE0AE\r
+:106A3000C92E21E1E22E00E128E048EE57E065E0B2\r
+:106A4000C2010E943E3298C090E789169104D1F1AC\r
+:106A500094F4FDE68F16910409F440C02EE68216E8\r
+:106A6000910409F449C038E68316910409F084C002\r
+:106A7000EE24E3943FC084E788169104B1F044F417\r
+:106A8000E3E78E16910409F077C0AA24A3943BC0D3\r
+:106A9000F7E78F169104C9F129E78216910409F0EE\r
+:106AA0006BC03FEF231A330A34C08F8587FD02C0C5\r
+:106AB0006AE001C060E0AE014F5F5F4FC2010E941B\r
+:106AC00059315AC0AE014F5F5F4F6AE0C2010E9468\r
+:106AD000BC3152C081E0281A31081BC0662463947F\r
+:106AE00002C066246A94670C14C0B394BB8E11C0B4\r
+:106AF000EE24EA94ED0C0DC0CC24C39402C0CC2447\r
+:106B0000CA94CF0C06C0A10E04C00F5F01C0015093\r
+:106B10000E8F8A2D0A2C000C990B9F93AF928C2D0F\r
+:106B20000C2C000C990B9F93CF928E2D0E2C000CE9\r
+:106B3000990B9F93EF92EB8D8E2F0E2E000C990BDD\r
+:106B40009F93EF93862D062C000C990B9F936F92C9\r
+:106B50003F922F922AE03DE03F932F930E94674699\r
+:106B60000B8D262DA1016E8DC2010E943E320FB603\r
+:106B7000F894DEBF0FBECDBF9BE18916910409F0EA\r
+:106B800017CE80E001C08FEF6E960FB6F894DEBF8F\r
+:106B90000FBECDBFDF91CF911F910F91FF90EF906E\r
+:106BA000DF90CF90BF90AF909F908F907F906F902D\r
+:106BB0005F904F903F902F90089560FF02C0289AF9\r
+:106BC00001C0289861FF02C0299A01C0299862FF7C\r
+:106BD00002C02A9A01C02A9863FF02C02B9A01C002\r
+:106BE0002B9864FF02C02C9A01C02C9865FF02C04C\r
+:106BF0002D9A01C02D9866FF02C02E9A01C02E98D2\r
+:106C000067FF02C02F9A01C02F98809188048130BD\r
+:106C100019F0823061F0089570FF02C05E9A01C0E1\r
+:106C20005E9871FF02C05F9A08955F98089570FFA3\r
+:106C300002C0129A01C0129871FF02C0139A0895FF\r
+:106C40001398089580918804813019F08230B1F052\r
+:106C5000089560FF02C0109A01C0109861FF02C041\r
+:106C6000119A01C0119862FF02C0129A01C01298D5\r
+:106C700063FF02C0139A08951398089560FF02C03D\r
+:106C80005C9A01C05C9861FF02C05D9A01C05D988A\r
+:106C900062FF02C05E9A01C05E9863FF02C05F9A05\r
+:106CA00008955F980895CF93DF93EC0160E070E062\r
+:106CB0000E94DD3560E0CE010E9422368FEF84B95C\r
+:106CC00080918804813041F0823061F481B18E601E\r
+:106CD00081B98AB1806F05C081B18F6081B98AB1F5\r
+:106CE000806E8AB9DF91CF910895CF93DF93EC0145\r
+:106CF00060E070E00E94DD3560E0CE010E94223647\r
+:106D000014B880918804813041F0823061F481B1FF\r
+:106D1000817F81B98AB18F7005C081B1807F81B9CF\r
+:106D20008AB18F718AB9DF91CF91089580918804DB\r
+:106D3000813019F0823039F00895662311F05D98A2\r
+:106D400008955D9A0895662311F011980895119A97\r
+:106D50000895CF92DF92EF92FF920F931F93CF93FC\r
+:106D6000DF937C01611117C06FE00E9422366FEF44\r
+:106D700073E0C7010E94DD3561E0C7010E949636CD\r
+:106D80008FEE9EE09F938F930E94674660ED77E0C1\r
+:106D900080E090E028C0613069F48BEE9EE09F9324\r
+:106DA0008F930E94674668EE73E080E090E00E9457\r
+:106DB0009F0A20C0623039F460E071E00E94DD3546\r
+:106DC00082EE9EE008C06330C1F460E072E00E9491\r
+:106DD000DD3589ED9EE09F938F930E94674668EEB4\r
+:106DE00073E080E090E00E949F0A60E070E0C701DD\r
+:106DF0000E94DD350F900F9044C0643208F043C00C\r
+:106E0000C62FD0E024978E0183E0159507958A95CB\r
+:106E1000E1F7C770DD27CC24C394D12CB601002E36\r
+:106E200001C0660F0A94EAF7C7010E9422360C2EB1\r
+:106E300002C0CC0CDD1C0A94E2F7B601C7010E9427\r
+:106E4000DD35DF92CF92CC0FDD1FC05EDE4F898132\r
+:106E50008F9388818F931F930F9384EC9EE09F9371\r
+:106E60008F930E94674660E971E080E090E00E94A5\r
+:106E70009F0A8DB79EB708960FB6F8949EBF0FBEB7\r
+:106E80008DBF80E001C08FEFDF91CF911F910F91F7\r
+:106E9000FF90EF90DF90CF90089581B1807F81B90E\r
+:106EA00082B18F6082B9089582B1807F82B981B149\r
+:106EB000807F81B908956130710581F058F06230AA\r
+:106EC000710581F063307105A1F480B183FB8827DF\r
+:106ED00080F90CC080B180958170089580B186954D\r
+:106EE000817004C080B182FB882780F991E08927F6\r
+:106EF000089580E008950F931F93CF93DF9360313F\r
+:106F000008F04EC08C01C62FC695C695D0E06370C0\r
+:106F1000613021F0633009F44BC021C0BE010E94F2\r
+:106F20005B37811145C0CE0101969F938F9385E019\r
+:106F30009FE09F938F930E9467460F900F900F9052\r
+:106F40000F90BE01C8010E945B3781112BC060E029\r
+:106F500070E0CB010E949F0A019621F5F2CFBE019D\r
+:106F60000E945B37882321F1CE0101969F938F9376\r
+:106F700087EF9EE09F938F930E9467460F900F903C\r
+:106F80000F900F90BE01C8010E945B37882351F01B\r
+:106F900060E070E0CB010E949F0A019619F4F2CFE5\r
+:106FA0008FEF07C06AE070E080E090E00E949F0AE7\r
+:106FB00080E0DF91CF911F910F910895CF93C82F5B\r
+:106FC0008A3019F48DE00E94DE378091C80085FF79\r
+:106FD000FCCFC093CE0080E090E0CF9108955A9A04\r
+:106FE00022E02093C80028E92093C90026E02093DE\r
+:106FF000CA001092CD002CE02093CC0020E331E0B9\r
+:107000003093E7042093E60421E0FC0122830895F5\r
+:10701000FC0112821092C8001092C9001092CA009E\r
+:107020001092CD001092CC001092E7041092E6046A\r
+:1070300008950F931F93CF93DF93611122C007E34D\r
+:107040001FE0C7E1DFE01F930F930E946746DF93C5\r
+:10705000CF938091E7048F938091E6048F930E94F1\r
+:10706000104668E873E180E090E00E949F0A0F906C\r
+:107070000F900F900F900F900F90019621F380E0EA\r
+:1070800001C08FEFDF91CF911F910F910895862F4F\r
+:107090006091E6047091E7040C94DE37A0E1B0E063\r
+:1070A000E4E5F8E30C94EF3F7C011B016A01FC016D\r
+:1070B00017821682838181FF44C39E012F5F3F4F59\r
+:1070C0003901F7019381F10193FD859193FF81913E\r
+:1070D0001F01882309F431C3853239F493FD85916A\r
+:1070E00093FF81911F01853239F4B70190E00E942E\r
+:1070F0002B4656016501E5CF10E0512C912CFFE1A4\r
+:10710000F915D8F08B3279F038F4803279F0833287\r
+:10711000A1F4F92DF0612EC08D3261F0803369F455\r
+:10712000292D21602DC0392D3260932E892D846048\r
+:10713000982E2AC0E92DE86015C097FC2DC020EDDF\r
+:10714000280F2A3088F496FE06C03AE0139F200DDF\r
+:107150001124122F19C08AE0589E200D1124522E9E\r
+:10716000E92DE0629E2E10C08E3231F496FCE5C20D\r
+:10717000F92DF0649F2E08C08C3621F4292D20684B\r
+:10718000922E02C0883641F4F10193FD859193FF60\r
+:1071900081911F018111B3CF9BEB980F933020F4A5\r
+:1071A000992D9061805E07C09BE9980F933008F09D\r
+:1071B00066C1992D9F7E96FF16E09F73992E8536A6\r
+:1071C00019F49064992E08C0863621F4392F30685E\r
+:1071D000932E02C01111115097FE07C01C3350F4BA\r
+:1071E00044244394410E27E00BC0183038F027E0C8\r
+:1071F00017E005C027E09CE3492E02C0212F412C57\r
+:10720000560184E0A80EB11CF60160817181828173\r
+:107210009381042DA3010E94D0446C01F981FC8765\r
+:10722000F0FF02C0F3FF06C091FC06C092FE06C04C\r
+:1072300000E205C00DE203C00BE201C000E08C8556\r
+:107240008C7019F001115AC29BC297FE10C04C0CF1\r
+:10725000FC85F4FF04C08A81813309F44A94141434\r
+:1072600074F528E0241578F588E0482E2CC096FCAB\r
+:107270002AC0812F90E08C159D059CF03CEFC31631\r
+:107280003FEFD30674F0892D8068982E0AC0E2E0A3\r
+:10729000F0E0EC0FFD1FE10FF11D8081803319F448\r
+:1072A00011501111F4CF97FE0EC044244394410EA7\r
+:1072B000812F90E0C816D9062CF41C1904C0442470\r
+:1072C000439401C010E097FE06C01C141D0434F462\r
+:1072D000C601019605C085E090E002C081E090E023\r
+:1072E00001110196112331F0212F30E02F5F3F4F24\r
+:1072F000820F931F252D30E08217930714F4581A3C\r
+:1073000001C0512C892D897049F4552039F0B701FD\r
+:1073100080E290E00E942B465A94F7CF002329F098\r
+:10732000B701802F90E00E942B4693FC09C05520A6\r
+:1073300039F0B70180E390E00E942B465A94F7CFD2\r
+:1073400097FE4CC04601D7FE02C0812C912CC6018D\r
+:1073500088199909F301E80FF91FFE87ED87960157\r
+:1073600024193109388B2F87012F10E011950195D1\r
+:1073700011093FEF8316930629F4B7018EE290E0DE\r
+:107380000E942B46C814D9044CF08F859889881523\r
+:10739000990524F4ED85FE85818101C080E3F1E04B\r
+:1073A0008F1A91082D853E852F5F3F4F3E872D8791\r
+:1073B000801691062CF0B70190E00E942B46D9CFA1\r
+:1073C000C814D90441F49A81963320F4953319F402\r
+:1073D0003C8534FF81E3B70190E04EC08A81813360\r
+:1073E00019F09C859F7E9C87B70190E00E942B46F8\r
+:1073F000111105C094FC18C085E690E017C0B701D4\r
+:107400008EE290E00E942B461E5F82E001E0080FB2\r
+:10741000F301E80FF11D8081B70190E00E942B4637\r
+:10742000802F0113F3CFE6CF85E490E0B7010E94EF\r
+:107430002B46D7FC06C0C114D10441F4EC85E4FF0F\r
+:1074400005C0D194C194D1088DE201C08BE2B7018F\r
+:1074500090E00E942B4680E32AE0C216D1042CF073\r
+:107460008F5FFAE0CF1AD108F7CFB70190E00E9402\r
+:107470002B46B701C601C0960E942B4654C18336E5\r
+:1074800031F0833779F0833509F056C020C05601BA\r
+:1074900032E0A30EB11CF6018081898301E010E087\r
+:1074A000630112C05601F2E0AF0EB11CF601C080BC\r
+:1074B000D18096FE03C0612F70E002C06FEF7FEFB6\r
+:1074C000C6010E94D9458C01F92DFF7714C05601E1\r
+:1074D00022E0A20EB11CF601C080D18096FE03C04E\r
+:1074E000612F70E002C06FEF7FEFC6010E94B145CF\r
+:1074F0008C01F92DF0689F2EF3FD1AC0852D90E0C8\r
+:1075000008171907A8F4B70180E290E00E942B4603\r
+:107510005A94F4CFF60197FC859197FE81916F0103\r
+:10752000B70190E00E942B4651105A940150110966\r
+:107530000115110579F7F7C0843611F0893661F528\r
+:10754000560197FE09C024E0A20EB11CF60160812D\r
+:107550007181828193810AC0F2E0AF0EB11CF60105\r
+:1075600060817181072E000C880B990BF92DFF7635\r
+:107570009F2E97FF09C090958095709561957F4FDC\r
+:107580008F4F9F4FF0689F2E2AE030E0A3010E94AA\r
+:10759000A646C82EC6183FC0092D853721F40F7E98\r
+:1075A0002AE030E01DC0097F8F3691F018F488354D\r
+:1075B00059F0C3C0803719F0883711F0BEC00061A0\r
+:1075C00004FF09C0046007C094FE08C0066006C03E\r
+:1075D00028E030E005C020E130E002C020E132E0E8\r
+:1075E000560107FF09C084E0A80EB11CF6016081B6\r
+:1075F00071818281938108C0F2E0AF0EB11CF60167\r
+:107600006081718180E090E0A3010E94A646C82EAF\r
+:10761000C6180F77902E96FE0BC0092D0E7FC1164F\r
+:1076200050F494FE0AC092FC08C0092D0E7E05C0DD\r
+:10763000DC2C092D03C0DC2C01C0D12E04FF0DC0B1\r
+:10764000FE01EC0DF11D8081803311F4097E09C02B\r
+:1076500002FF06C0D394D39404C0802F867809F02B\r
+:10766000D39403FD11C000FF06C01C2DD51480F477\r
+:10767000150D1D190DC0D51458F4B70180E290E026\r
+:107680000E942B46D394F7CFD51410F45D1801C097\r
+:10769000512C04FF10C0B70180E390E00E942B46FC\r
+:1076A00002FF17C001FD03C088E790E002C088E533\r
+:1076B00090E0B7010CC0802F867859F001FF02C01E\r
+:1076C0008BE201C080E207FD8DE2B70190E00E94ED\r
+:1076D0002B46C11638F4B70180E390E00E942B4698\r
+:1076E0001150F7CFCA94F301EC0DF11D8081B70161\r
+:1076F00090E00E942B46C110F5CF15C0F4E0F515BF\r
+:1077000060F584E0581A93FE1FC0011127C02C8534\r
+:1077100023FF2AC00EEF10E0392D3071932EF801AF\r
+:107720008491811124C0552009F4E4CCB70180E292\r
+:1077300090E00E942B465A94F6CFF70186819781FC\r
+:1077400026C08FEF9FEF23C0B70180E290E00E9438\r
+:107750002B465A945110F8CFD8CF512CB701802F17\r
+:1077600090E00E942B46D3CF02E011E0D5CF9110DC\r
+:107770008052B70190E00E942B460F5F1F4FCFCF82\r
+:1077800023E0251510F483E0BDCF512CC0CF6096C7\r
+:10779000E2E10C940B400F931F93CF93DF93EC0126\r
+:1077A0008B0180EA91E099838883CE0104960E9440\r
+:1077B000AB0CCE01CD960E94F415CE0187589F4F99\r
+:1077C0000E94DB07CE0185589F4F0E944109FE01B0\r
+:1077D000E057FF4F10821B830A83DF91CF911F91E7\r
+:1077E0000F910895CF93DF93CDB7DEB7AE970FB665\r
+:1077F000F894DEBF0FBECDBF87B18C6987B988B161\r
+:10780000837688B93D98459A82E08093C00098E9D4\r
+:107810009093C10096E09093C2001092C5009CE046\r
+:107820009093C4008093B0008093B10096E9909348\r
+:10783000B3008093700080E191E09093E504809321\r
+:10784000E40482E091E09093E3048093E20478946E\r
+:107850000E94420A86E2EEE3F1E0DE011196019019\r
+:107860000D928A95E1F780918804811102C087E02A\r
+:1078700001C083E1F9EFCF2EF2E0DF2EABEFAA2EAD\r
+:10788000A2E0BA2E682E712C4E0127E2820E911CC6\r
+:10789000CE018B969EA78DA762E7262E62E0362E3C\r
+:1078A00078E3472E73E0572EEEE6EE2EE2E0FE2E52\r
+:1078B000DF92CF920E946746BF92AF920E946746C6\r
+:1078C000A4E2B3E0BF93AF930E9467463F922F922A\r
+:1078D0000E9467465F924F920E946746FF92EF9226\r
+:1078E0000E9467468FE293E09F938F930E946746C2\r
+:1078F000BF92AF920E946746809188049FEF980FD5\r
+:107900000FB6F894DEBF0FBECDBF923078F40E9460\r
+:10791000350A9F938F938EE592E09F938F930E94F9\r
+:1079200067460F900F900F900F9008C086E492E08A\r
+:107930009F938F930E9467460F900F90BF92AF92D4\r
+:107940000E946746DF92CF920E94674683E392E0EF\r
+:107950009F938F930E9467461CA61BA60F900F90C3\r
+:107960000F900F900F900F908BA59CA586159705F3\r
+:1079700070F5FC01EE0FFF1F21E030E02C0F3D1FE2\r
+:10798000E20FF31F008111819F938F938AE292E0AF\r
+:107990009F938F930E946746D801ED91FC910680DA\r
+:1079A000F781E02DC80109959F938F930E94674648\r
+:1079B000DF92CF920E9467468BA59CA501969CA75B\r
+:1079C0008BA70FB6F894DEBF0FBECDBFCDCF8BE136\r
+:1079D00092E09F938F930E94674610925F041092EB\r
+:1079E0005E044091E2045091E30464E070E0C4015D\r
+:1079F0000E94E4453EA53F938DA58F9388E791E0D3\r
+:107A00009F938F939F928F920E948D460FB6F8940A\r
+:107A1000DEBF0FBECDBF019709F04ACF8BA59CA555\r
+:107A20008615970508F044CF880F991FE1E0F0E034\r
+:107A3000EC0FFD1FE80FF91F0081118187E192E033\r
+:107A40009F938F930E946746D801ED91FC91068029\r
+:107A5000F781E02DC80109959F938F930E94674697\r
+:107A600083E192E09F938F930E9467468FEF9FEF91\r
+:107A70009093010180930001D801ED91FC91028067\r
+:107A8000F381E02DC80109950F900F900F900F9092\r
+:107A90000F900F90E12CF12C3CE0432E32E0532E5E\r
+:107AA00022242A94322CFF92EF925F924F920E94EE\r
+:107AB0006746D801ED91FC910190F081E02D6E2D8B\r
+:107AC000C80109950F900F900F900F9087FD18C077\r
+:107AD00080910001909101014B9739F48FEF9FEF56\r
+:107AE00090930101809300010BC03092010120921C\r
+:107AF0000001BFEFEB1AFB0A2FEFE216F10499F633\r
+:107B0000D801ED91FC910480F581E02DC801099523\r
+:107B1000C3CE84EC91E090935D0480935C0481E497\r
+:107B200092E090935B0480935A048CE092E09093EF\r
+:107B300059048093580484E292E090935604809311\r
+:107B400055041092570484EF91E09093540480936D\r
+:107B5000530482E991E09093500480934F04109273\r
+:107B600052041092510480E092E090934E0480936E\r
+:107B70004D048CED91E09093490480934804109259\r
+:107B80004A0410924C0410924B0488EE91E09093BA\r
+:107B900047048093460488EB91E0909343048093DC\r
+:107BA000420481E090918804913009F480E0809350\r
+:107BB0004404109245048DE492E090934004809335\r
+:107BC0003F041092410480ED91E090932C04809347\r
+:107BD0002B0410922D0410922E048CEA91E09093C5\r
+:107BE000270480932604109228048FEF9FEF909330\r
+:107BF0002A048093290460E070E085E993E00E9404\r
+:107C0000CB3B61E070E084E093E00E94CB3B62E01C\r
+:107C100070E083E792E00E94CB3B88E192E0909392\r
+:107C20006D0280936C028EE692E00E94DB07109258\r
+:107C30007002109272021092710286E891E09093A5\r
+:107C400062028093610210926A0221E030E0309378\r
+:107C500069022093680210926302109264021092EB\r
+:107C60006502109266021092670290935702809309\r
+:107C7000560210925F0282E090E090935E02809341\r
+:107C80005D02109258021092590210925A021092FC\r
+:107C90005B0210925C0208958AE994E00E94AB0CAA\r
+:107CA00088E191E0909399048093980490939704CD\r
+:107CB00080939604909395048093940408958AE3A6\r
+:107CC00097E008958EE199E0089585E599E008959B\r
+:107CD00086E699E0089587E49AE0089585ED9AE0B4\r
+:107CE00008958EE79BE008958AEA9BE0089583EF6C\r
+:107CF0009BE008958AE09CE0089582EF9EE008955D\r
+:107D000080E19FE0089587E59FE00895DB018F9370\r
+:107D10009F930E94E33EBF91AF91A29F800D911D62\r
+:107D2000A39F900DB29F900D11240895991B79E0A7\r
+:107D300004C0991F961708F0961B881F7A95C9F7FB\r
+:107D40008095089587FB082E062687FD819567FD9F\r
+:107D500061950E94963E0EF4919507FC81950895D9\r
+:107D6000AA1BBB1B51E107C0AA1FBB1FA617B70761\r
+:107D700010F0A61BB70B881F991F5A95A9F780957D\r
+:107D80009095BC01CD010895052E97FB1EF400943B\r
+:107D90000E94DB3E57FD07D00E94874007FC03D0BE\r
+:107DA0004EF40C94DB3E50954095309521953F4F15\r
+:107DB0004F4F5F4F089590958095709561957F4FD7\r
+:107DC0008F4F9F4F08950E94AF40A59F900DB49F85\r
+:107DD000900DA49F800D911D11240895B7FF0C9460\r
+:107DE000E33E0E94E33E821B930B0895DF93CF9303\r
+:107DF0001F930F939A9DF02D219FF00D8B9DF00DF9\r
+:107E00008A9DE02DF10D039FF00D029FE00DF11D05\r
+:107E10004E9DE00DF11D5E9DF00D4F9DF00D7F9389\r
+:107E20006F93BF92AF925F934F93D5010E94AF4083\r
+:107E30008B01AC01D7010E94AF40EB01E80FF91FA5\r
+:107E4000D6010E94463F2F913F91D6010E94AF403C\r
+:107E5000C60FD71FE81FF91FAF91BF910E94463F81\r
+:107E60002F913F910E94AF40C60FD71FE81FF91F07\r
+:107E7000D6010E94AF40E60FF71F9801BE01CF0167\r
+:107E800011240F911F91CF91DF9108950E94AF406F\r
+:107E9000460F571FC81FD91F08F4319608956894DC\r
+:107EA00001C0E894F92FF12B12F00C94833FA0E06D\r
+:107EB000B0E0EDE5FFE30C94F53F092E059422F4C4\r
+:107EC0000E94DF3F112392F4F0E80F26FFEFE094C9\r
+:107ED000F09400951095B094C094D094A194BF0AEA\r
+:107EE000CF0ADF0AEF0AFF0A0F0B1F0B0E948E3F1B\r
+:107EF00007FC0E94DF3FCDB7DEB7ECE00C941140E9\r
+:107F0000689401C0E8948F929F92CF93DF930E9470\r
+:107F10008E3FDF91CF919F908F9008958824992470\r
+:107F2000F401E401B0E49F93AA279A158B049C0402\r
+:107F3000ED05FE05CF05D007A10798F4AD2FDC2F86\r
+:107F4000CF2FFE2FE92D982C892E982F872F762F53\r
+:107F5000652F542F432F322F2227B85031F7BF916E\r
+:107F600027C01B2EBF91BB27220F331F441F551F55\r
+:107F7000661F771F881F991F881C991CEE1FFF1F03\r
+:107F8000CC1FDD1FAA1FBB1F8A149B04EC05FD0537\r
+:107F9000CE05DF05A007B10748F08A189B08EC0959\r
+:107FA000FD09CE09DF09A00BB10B21601A94E1F69F\r
+:107FB0002EF49401AF01BE01CD01000C089560952F\r
+:107FC00070958095909530954095509521953F4FAF\r
+:107FD0004F4F5F4F6F4F7F4F8F4F9F4F08952F929F\r
+:107FE0003F924F925F926F927F928F929F92AF9249\r
+:107FF000BF92CF92DF92EF92FF920F931F93CF9396\r
+:10800000DF93CDB7DEB7CA1BDB0B0FB6F894DEBF2C\r
+:108010000FBECDBF09942A88398848885F846E8452\r
+:108020007D848C849B84AA84B984C884DF80EE809C\r
+:10803000FD800C811B81AA81B981CE0FD11D0FB6A5\r
+:10804000F894DEBF0FBECDBFED0108950F93083049\r
+:1080500090F0982F872F762F652F542F432F322F94\r
+:1080600022270850F4CF220F331F441F551F661FCD\r
+:10807000771F881F991F0A95B2F70F91089597FBF4\r
+:1080800010F8169400080F93083098F00850232F2A\r
+:10809000342F452F562F672F782F892F902DF4CF0F\r
+:1080A0000594979587957795679557954795379553\r
+:1080B00027950A95AAF70F9108952A0D3B1D4C1D8F\r
+:1080C0005D1D6E1D7F1D801F911F08950024A7FD5B\r
+:1080D00000942A0F301D401D501D601D701D801D15\r
+:1080E000901D08952A193B094C095D096E097F0905\r
+:1080F000800B910B08950024A7FD00942A173005EA\r
+:108100004005500560057005800590050895A1E2C1\r
+:108110001A2EAA1BBB1BFD010DC0AA1FBB1FEE1F01\r
+:10812000FF1FA217B307E407F50720F0A21BB30B4C\r
+:10813000E40BF50B661F771F881F991F1A9469F7C8\r
+:1081400060957095809590959B01AC01BD01CF0124\r
+:108150000895EE0FFF1F0590F491E02D0994A29F62\r
+:10816000B001B39FC001A39F700D811D1124911D0B\r
+:10817000B29F700D811D1124911D08955058BB2789\r
+:10818000AA270E94D6400C947B420E946D4238F090\r
+:108190000E94744220F039F49F3F19F426F40C94A5\r
+:1081A0005A420EF4E095E7FB0C945442E92F0E94EA\r
+:1081B0008C4258F3BA17620773078407950720F0BB\r
+:1081C00079F4A6F50C94AE420EF4E0950B2EBA2F7E\r
+:1081D000A02D0B01B90190010C01CA01A0011124CD\r
+:1081E000FF27591B99F0593F50F4503E68F11A1679\r
+:1081F000F040A22F232F342F4427585FF3CF46950A\r
+:1082000037952795A795F0405395C9F77EF41F162B\r
+:10821000BA0B620B730B840BBAF09150A1F0FF0FF5\r
+:10822000BB1F661F771F881FC2F70EC0BA0F621FE1\r
+:10823000731F841F48F4879577956795B795F795D1\r
+:108240009E3F08F0B0CF9395880F08F09927EE0F66\r
+:108250009795879508950E943F410C947B420E9418\r
+:10826000744258F00E946D4240F029F45F3F29F0BB\r
+:108270000C94544251110C94AF420C945A420E94F7\r
+:108280008C4268F39923B1F3552391F3951B550B59\r
+:10829000BB27AA2762177307840738F09F5F5F4FD9\r
+:1082A000220F331F441FAA1FA9F335D00E2E3AF018\r
+:1082B000E0E832D091505040E695001CCAF72BD030\r
+:1082C000FE2F29D0660F771F881FBB1F2617370781\r
+:1082D0004807AB07B0E809F0BB0B802DBF01FF27B3\r
+:1082E00093585F4F3AF09E3F510578F00C945442FA\r
+:1082F0000C94AF425F3FE4F3983ED4F386957795B4\r
+:108300006795B795F7959F5FC9F7880F911D96956B\r
+:10831000879597F90895E1E0660F771F881FBB1FC7\r
+:10832000621773078407BA0720F0621B730B840B74\r
+:10833000BA0BEE1F88F7E09508950E94A441689457\r
+:10834000B1110C94AF4208950E94944288F09F5757\r
+:1083500098F0B92F9927B751B0F0E1F0660F771F69\r
+:10836000881F991F1AF0BA95C9F714C0B13091F05F\r
+:108370000E94AE42B1E008950C94AE42672F782F70\r
+:108380008827B85F39F0B93FCCF386957795679524\r
+:10839000B395D9F73EF490958095709561957F4F90\r
+:1083A0008F4F9F4F089597FB16F40E945D420C94E7\r
+:1083B0001742E89409C097FB3EF49095809570951C\r
+:1083C00061957F4F8F4F9F4F9923A9F0F92F96E921\r
+:1083D000BB279395F695879577956795B795F11196\r
+:1083E000F8CFFAF4BB0F11F460FF1BC06F5F7F4F33\r
+:1083F0008F4F9F4F16C0882311F096E911C0772345\r
+:1084000021F09EE8872F762F05C0662371F096E84D\r
+:10841000862F70E060E02AF09A95660F771F881F1C\r
+:10842000DAF7880F9695879597F90895E894F92FCC\r
+:1084300096EBFF2381F0121613061406440B939556\r
+:10844000F69587957795679557954040FF23B9F73F\r
+:108450001BC099270895882351F49850D2F7872B91\r
+:10846000762F652F542F432F322F20E0B1F31216B1\r
+:1084700013061406440B88233AF09A95440F551FAF\r
+:10848000661F771F881FCAF755234AF4440F551FEC\r
+:1084900011F460FF04C06F5F7F4F8F4F9F4F880FB5\r
+:1084A0009695879597F9089597F99F6780E870E00A\r
+:1084B00060E008959FEF80EC089590958095709509\r
+:1084C000609550954095309521953F4F4F4F5F4FA8\r
+:1084D0006F4F7F4F8F4F9F4F089500240A941616B9\r
+:1084E000170618060906089500240A9412161306A2\r
+:1084F000140605060895092E0394000C11F4882330\r
+:1085000052F0BB0F40F4BF2B11F460FF04C06F5F4B\r
+:108510007F4F8F4F9F4F089557FD9058440F551F21\r
+:1085200059F05F3F71F04795880F97FB991F61F0F5\r
+:108530009F3F79F087950895121613061406551F6C\r
+:10854000F2CF4695F1DF08C0161617061806991FD8\r
+:10855000F1CF86957105610508940895E894BB27CD\r
+:1085600066277727CB0197F908950E94C8420C949B\r
+:108570007B420E946D4238F00E94744220F09523A5\r
+:1085800011F00C9454420C945A4211240C94AF42B2\r
+:108590000E948C4270F3959FC1F3950F50E0551FD8\r
+:1085A000629FF001729FBB27F00DB11D639FAA2748\r
+:1085B000F00DB11DAA1F649F6627B00DA11D661F97\r
+:1085C000829F2227B00DA11D621F739FB00DA11DB8\r
+:1085D000621F839FA00D611D221F749F3327A00D72\r
+:1085E000611D231F849F600D211D822F762F6A2F0E\r
+:1085F00011249F5750409AF0F1F088234AF0EE0F73\r
+:10860000FF1FBB1F661F771F881F91505040A9F79F\r
+:108610009E3F510580F00C9454420C94AF425F3F52\r
+:10862000E4F3983ED4F3869577956795B795F795DB\r
+:10863000E7959F5FC1F7FE2B880F911D9695879553\r
+:1086400097F90895FA01EE0FFF1F309621053105C5\r
+:10865000A1F16115710561F48038BFE39B0749F111\r
+:1086600068949038810561F08038BFEF9B0741F036\r
+:1086700099234AF5FF3FE1053105210519F1E894F9\r
+:108680000894E795D901AA2329F4AB2FBE2FF85FF0\r
+:10869000D0F310C0FF5F70F4A695E0F7F73950F003\r
+:1086A00019F0FF3A38F49F779F930DD00F9007FC95\r
+:1086B0009058089546F00C945A4260E070E080E8CB\r
+:1086C0009FE308954FE79F775F934F933F932F93D7\r
+:1086D0000E9446442F913F914F915F910E94B54275\r
+:1086E0000C947F430E94B143880B990B089529F4A1\r
+:1086F00016F00C9454420C94AE420C945A420E94D0\r
+:108700009442A8F39638A0F707F80F92E8942BE369\r
+:108710003AEA48EB5FE70E94CB420F920F920F922A\r
+:108720004DB75EB70F920E948E44ECE7F0E00E94D6\r
+:10873000D5434F915F91EF91FF91E595EE1FFF1F9C\r
+:1087400049F0FE57E0684427EE0F441FFA95E1F721\r
+:108750004195550B0E9408440F9007FE0C94FC4372\r
+:108760000895990F0008550FAA0BE0E8FEEF1616C2\r
+:108770001706E807F907C0F012161306E407F50715\r
+:1087800098F0621B730B840B950B39F40A2661F089\r
+:10879000232B242B252B21F408950A2609F4A1402C\r
+:1087A000A6958FEF811D811D0895DF93CF931F93B1\r
+:1087B0000F93FF92EF92DF927B018C01689406C0C9\r
+:1087C000DA2EEF010E94C842FE01E894A59125919E\r
+:1087D000359145915591A6F3EF010E94D640FE01D7\r
+:1087E0009701A801DA9469F7DF90EF90FF900F915D\r
+:1087F0001F91CF91DF9108959B01AC0160E070E083\r
+:1088000080E89FE30C942B410C9454420C94C24496\r
+:108810000E949442D8F39923C9F3940F511DA3F3F6\r
+:108820009150504094F059F0882332F0660F771F32\r
+:10883000881F91505040C1F79E3F51052CF7880F7B\r
+:10884000911D9695879597F908955F3FACF0983EF6\r
+:108850009CF0BB27869577956795B79508F4B1602E\r
+:108860009395C1F7BB0F58F711F460FFE8CF6F5F26\r
+:108870007F4F8F4F9F4FE3CF0C94AF4216F00C9475\r
+:10888000C2440C945A4268940C9454420E949442FC\r
+:10889000A8F39923C1F3AEF3DF93CF931F930F9304\r
+:1088A000FF92C92FDD2788232AF02197660F771FB3\r
+:1088B000881FDAF720E030E040E85FEB9FE388397B\r
+:1088C00020F0803E38F021968F770E94BF40E4EA86\r
+:1088D000F0E004C00E94BF40E1EDF0E00E94D5430B\r
+:1088E0008B01BE01EC01FB2E6F5771097595771F47\r
+:1088F000880B990B0E94DB4128E132E741E35FE3FB\r
+:108900000E94C842AF2D9801AE01FF900F911F91B8\r
+:10891000CF91DF910E94D6400C947B42FA01DC019A\r
+:10892000AA0FBB1F9B01AC01BF5728F42227332796\r
+:108930004427507820C0B75190F4AB2F00244695BF\r
+:1089400037952795011CA395D2F3002071F0220FD3\r
+:10895000331F441FB395DAF30ED00C94BE40613040\r
+:108960007105A0E88A07B94630F49B01AC0166277F\r
+:10897000772788279078309621F0208331834283AF\r
+:10898000538308959F3F31F0915020F48795779558\r
+:108990006795B795880F911D9695879597F90895D6\r
+:1089A000283008F027E03327DA01990F311D87FDC1\r
+:1089B000916000966105710539F432602E5F3D9338\r
+:1089C00030E32A95E1F708959F3F30F08038710534\r
+:1089D000610509F03C5F3C5F3D93913008F0806891\r
+:1089E000911DDF93CF931F930F93FF92EF92192F57\r
+:1089F000987F9695E92F96959695E90FFF27E05A6F\r
+:108A0000FE4F99273327EE24FF24A701E7010590A5\r
+:108A10000894079428F4360FE71EF81E491F511DCD\r
+:108A2000660F771F881F991F0694A1F7059007947A\r
+:108A300028F4E70EF81E491F561FC11D770F881F27\r
+:108A4000991F661F0694A1F70590079428F4F80E65\r
+:108A5000491F561FC71FD11D880F991F661F771FFB\r
+:108A60000694A1F70590079420F4490F561FC71FDD\r
+:108A7000D81F990F661F771F881F0694A9F7849146\r
+:108A80001095177041F0D695C79557954795F7946F\r
+:108A9000E7941A95C1F7E6E0F1E068941590159116\r
+:108AA00035916591959105907FE27395E118F10AF2\r
+:108AB000430B560BC90BD009C0F7E10CF11E431F45\r
+:108AC000561FC91FD01D7EF4703311F48A95E6CF6E\r
+:108AD000E894015030F0080F0AF40027021708F458\r
+:108AE000202F2395022F7A3328F079E37D932A955E\r
+:108AF000E9F710C07D932A9589F6069497956795B6\r
+:108B0000379517951794E118F10A430B560BC90BCB\r
+:108B1000D00998F023957E9173957A3308F070E32D\r
+:108B20007C932013B8F77E9170617D9330F083952C\r
+:108B300071E37D9370E32A95E1F71124EF90FF90A4\r
+:108B40000F911F91CF91DF91992787FD90950895FF\r
+:108B5000FB01DC0102C005900D9241505040D8F756\r
+:108B60000895FC010590615070400110D8F7809580\r
+:108B700090958E0F9F1F0895FB01DC01215030401E\r
+:108B800030F001900D920416C9F7CD0108958827A1\r
+:108B900099270895FB01DC014150504048F00190B5\r
+:108BA0000D920020C9F701C01D9241505040E0F7DE\r
+:108BB0000895FC016150704001900110D8F7809534\r
+:108BC00090958E0F9F1F0895A0E0B0E0EAEEF5E4C7\r
+:108BD0000C94F93FFA01238120FD03C080E090E06E\r
+:108BE0001AC016161706D4F77A018C01EB016C0136\r
+:108BF000C130D10569F0C7010E94C5498F3FFFEF21\r
+:108C00009F0761F3F60181936F0121970A9781F71E\r
+:108C1000F6011082C801CDB7DEB7E8E00C9415402C\r
+:108C2000A0E0B0E0E6E1F6E40C94FD3F0F8118858A\r
+:108C3000F801838188608383AE01455F5F4F69855A\r
+:108C40007A85C8010E944E38F8012381277F23834B\r
+:108C5000E4E00C9419400F931F93CF93DF93FB0133\r
+:108C6000238121FD03C08FEF9FEF2CC022FF16C090\r
+:108C700046815781248135814217530744F4A081EE\r
+:108C8000B1819D012F5F3F4F318320838C932681DB\r
+:108C900037812F5F3F4F3783268314C08B01EC0150\r
+:108CA000FB010084F185E02D0995892BE1F6D801BF\r
+:108CB00016968D919C911797019617969C938E937B\r
+:108CC0001697CE01DF91CF911F910F910895A0E0EB\r
+:108CD000B0E0EDE6F6E40C94FD3FAE01495F5F4F76\r
+:108CE000DA016D917D91AD0102EE14E0F80182810F\r
+:108CF0009381DC0113962C911397286013962C9383\r
+:108D00000E944E38D8011296ED91FC911397238161\r
+:108D1000277F2383E4E00C941940AEE0B0E0E3E960\r
+:108D2000F6E40C94FF3F85E08C838B899C899A83C1\r
+:108D30008983AE01495E5F4F6D897E89CE010196C0\r
+:108D40000E94A0482E96E2E00C941B40FA01AA274C\r
+:108D5000283051F1203181F1E8946F936E7F6E5F7E\r
+:108D60007F4F8F4F9F4FAF4FB1E03ED0B4E03CD02C\r
+:108D7000670F781F891F9A1FA11D680F791F8A1F0F\r
+:108D8000911DA11D6A0F711D811D911DA11D20D076\r
+:108D900009F468943F912AE0269F11243019305D30\r
+:108DA0003193DEF6CF010895462F4770405D419321\r
+:108DB000B3E00FD0C9F7F6CF462F4F70405D4A336E\r
+:108DC00018F0495D31FD4052419302D0A9F7EACF36\r
+:108DD000B4E0A6959795879577956795BA95C9F765\r
+:108DE00000976105710508959B01AC010A2E069458\r
+:108DF0005795479537952795BA95C9F7620F731F11\r
+:108E0000841F951FA01D089520FD09C0FC0123FDAE\r
+:108E100005C022FF02C0738362835183408308959B\r
+:108E200044FD17C046FD17C0AB01BC01DA01FB01D0\r
+:108E3000AA0FBB1FEE1FFF1F1094D1F74A0F5B1F35\r
+:108E40006E1F7F1FCB01BA01660F771F881F991F06\r
+:108E500009C033E001C034E0660F771F881F991FF7\r
+:108E60003150D1F7620F711D811D911D08950F932F\r
+:108E70001F93CF93DF938C01C8010E94C549EC0179\r
+:108E800097FD08C00E94B149892BB1F7B801CE0106\r
+:108E90000E94034ACE01DF91CF911F910F91089557\r
+:108EA0008F929F92AF92BF92EF92FF920F931F9378\r
+:108EB000CF93DF938C01D62F7A01B22E0E94C54941\r
+:108EC0009C0133272B32310531F02D32310561F40D\r
+:108ED0008B2D8068B82ED15011F480E068C0C80195\r
+:108EE0000E94C54997FDF9CFCB2DCD7F2B2D207347\r
+:108EF00009F58033F9F4AA24AA94AD0E09F443C00D\r
+:108F0000C8010E94C54997FD3EC09C012F7D3327B3\r
+:108F10002835310549F4C264D250A9F1C8010E9434\r
+:108F2000C54997FF07C02FC0B6FE02C0C26001C08E\r
+:108F3000C261DA2D812C912C540120ED280F2830AC\r
+:108F400080F0C4FF04C0B8010E94034A19C02A304F\r
+:108F500040F0C6FFF8CF2F7D3FEE320F363098F746\r
+:108F600027504C2FC501B4010E9410474B015C01F2\r
+:108F7000C260D15059F0C8010E94C54997FFDDCFAA\r
+:108F8000C1FD04C0AACF812C912C5401C7FF08C099\r
+:108F9000B094A09490948094811C911CA11CB11C4D\r
+:108FA0002C2FB501A401C7010E94044781E0DF9185\r
+:108FB000CF911F910F91FF90EF90BF90AF909F9036\r
+:108FC0008F900895A0E2B0E0E8EEF7E40C94F23F51\r
+:108FD0005C01962E7A01F9018E010F5F1F4F680127\r
+:108FE00080E2D8011D928A95E9F7D50113968C90FD\r
+:108FF00080E090E0612C712C30E061E070E083FC57\r
+:10900000259183FE21918F01522E211103C080E012\r
+:1090100090E092C02E3511F4009751F1432F50E0AB\r
+:10902000481759073CF42D3559F12D3219F47720A2\r
+:1090300009F103C0772009F46AC0452D469546958D\r
+:109040004695D601A40FB11D452D47708B0102C076\r
+:10905000000F111F4A95E2F7A8015C91452B4C9334\r
+:10906000651459F0561410F45394E7CF5A94E5CF91\r
+:1090700031E004C07724739401C0712C0196BFCFF6\r
+:10908000772019F08E8180628E83311103C088248D\r
+:10909000839417C0F6019E012F5D3F4F808180951C\r
+:1090A00081932E173F07D1F7F2CFE114F10429F095\r
+:1090B000D7018C93F70131967F019A94812C9920E6\r
+:1090C000F9F0C5010E94C54997FD18C0FC01FF27B2\r
+:1090D00023E0F595E7952A95E1F7EC0DFD1D20813C\r
+:1090E00030E0AC014770552702C0359527954A9569\r
+:1090F000E2F720FDDACFB5010E94034A811087CF45\r
+:10910000E114F10411F0D7011C92C80115C0422FDF\r
+:10911000469546954695D601A40FB11D422F47703E\r
+:109120008B0102C0000F111F4A95E2F7A8015C9164\r
+:10913000452B4C93622EA2CFA096EFE00C940E40EC\r
+:10914000A0E0B0E0E6EAF8E40C94F23F6C01EB0139\r
+:109150005A01FC0117821682512CF601E380FE01B0\r
+:10916000E3FC8591E3FE8191182FEF01882309F438\r
+:10917000EEC090E00E94B149892B21F0C6010E9407\r
+:109180003747EBCF153241F4FE01E3FC1591E3FEC6\r
+:109190001191EF01153281F4C6010E94C54997FD76\r
+:1091A000D4C0412F50E09C01332724173507A9F282\r
+:1091B000B6010E94034ACBC01A3239F4E3FC159180\r
+:1091C000E3FE1191EF0101E001C000E0F12C20ED80\r
+:1091D000210F2A3080F402606F2D70E080E090E073\r
+:1091E00040E20E941047F62EFE01E3FC1591E3FEDB\r
+:1091F0001191EF01ECCF01FF03C0F11003C0A7C034\r
+:10920000FF24FA94183619F01C3651F010C0FE01F4\r
+:10921000E3FC1591E3FE1191EF01183641F408606B\r
+:109220000460FE01E3FC1591E3FE1191EF011123AF\r
+:1092300009F48DC0612F70E080E092E00E94BA498D\r
+:10924000892B09F484C000FD07C0F501808091805E\r
+:10925000C50102965C0102C0812C912C1E3651F48E\r
+:10926000F6014681578160E070E0202FC4010E9422\r
+:10927000044773CF1336A9F401FD02C0FF24F39411\r
+:10928000C6010E94C54997FD60C08114910429F070\r
+:10929000F4018083C40101964C01FA94F110F0CFDF\r
+:1092A00050C01B3559F49E01A4016F2DC6010E94C8\r
+:1092B000E247EC01892B09F044C03EC0C6010E9480\r
+:1092C000374797FD42C01F3661F128F4143639F153\r
+:1092D000193651F128C0133771F0153701F123C049\r
+:1092E0008114910429F0F4016082C40101964C01BB\r
+:1092F000FA94FF2071F0C6010E94C5493C0197FD18\r
+:1093000008C00E94B149892B59F3B601C3010E94DC\r
+:10931000034A81149104A9F0F401108212C0006282\r
+:1093200003C0006101C00064202FA4016F2DC6019D\r
+:109330000E945047811105C0F6018381807329F492\r
+:1093400006C000FD0ACF539408CF552019F0852D93\r
+:1093500090E002C08FEF9FEFCDB7DEB7EFE00C9447\r
+:109360000E4091110C941C4A803219F0895085509E\r
+:10937000C8F70895FC010590061621F00020D9F7E2\r
+:10938000C00108953197CF010895CF93DF93EC0189\r
+:109390002B8120FF33C026FF0AC02F7B2B838E81B9\r
+:1093A0009F8101969F838E838A8190E029C022FF4E\r
+:1093B0000FC0E881F9818081082E000C990B00977D\r
+:1093C00019F420622B831AC03196F983E8830EC00A\r
+:1093D000EA85FB85099597FF09C02B81019611F05D\r
+:1093E00080E201C080E1822B8B8308C02E813F8107\r
+:1093F0002F5F3F4F3F832E83992702C08FEF9FEF50\r
+:10940000DF91CF910895FB01238120FF12C026FD3B\r
+:1094100010C08F3F3FEF930761F082832F7D206460\r
+:109420002383268137812150310937832683992769\r
+:1094300008958FEF9FEF0895992788270895F8944E\r
+:02944000FFCF5C\r
+:10944200FFFF00000001000000000000C30900004F\r
+:109452000000000200000000E40900000000030315\r
+:109462002C022E02300232023402360238023A0252\r
+:109472000000000200000000DE37000000003F0490\r
+:109482000403730295036C02610256025C045A04DF\r
+:109492005804550453044F044D044804460442043E\r
+:1094A2002B042604160533052305D108C608BC087B\r
+:1094B20001040000000271CB257800424D4532388C\r
+:1094C200300000000000F0203F22371A261A000068\r
+:1094D2000000AE229B22A5225F3E3F00000000005A\r
+:1094E200772352236923412300000000CF269926C7\r
+:1094F200B726623E0000000053298D280329653EED\r
+:1095020000000000262AD029D729683E000000006A\r
+:109512007E2A692A6A2A6B3E00000000522C382CEF\r
+:109522001F2C6E3E00000000562EC62DD62D713E19\r
+:1095320000000000642F582F5F2F743E00000000CF\r
+:10954200B82FAC2FB32F773E00000000B630883022\r
+:109552009F307A3E0000000041332B313C314431D0\r
+:1095620000000000A936533675367D3E41004200A8\r
+:1095720043004400450046004700445000000000FC\r
+:10958200007B374D375437803E000000001938EF1A\r
+:06959200370838833E009B\r
+:00000001FF\r
diff --git a/software/deye-sun-12k/nano-644/src b/software/deye-sun-12k/nano-644/src
new file mode 120000 (symlink)
index 0000000..5cd551c
--- /dev/null
@@ -0,0 +1 @@
+../src
\ No newline at end of file
diff --git a/software/deye-sun-12k/src/adafruit/bme280.cpp b/software/deye-sun-12k/src/adafruit/bme280.cpp
new file mode 100644 (file)
index 0000000..1836c56
--- /dev/null
@@ -0,0 +1,512 @@
+#include "bme280.h"
+#include <util/delay.h>
+#include <stdio.h>
+
+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/deye-sun-12k/src/adafruit/bme280.h b/software/deye-sun-12k/src/adafruit/bme280.h
new file mode 100644 (file)
index 0000000..aa5aa72
--- /dev/null
@@ -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 <Adafruit_I2CDevice.h>
+// #include <Adafruit_SPIDevice.h>
+// #include <Adafruit_Sensor.h>
+
+
+#include "../i2cmaster.hpp"
+#include "../main.hpp"
+// #define byte uint8_t
+
+
+
+#include <stdint.h>
+#include <string.h>
+#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/deye-sun-12k/src/adafruit/ens160.cpp b/software/deye-sun-12k/src/adafruit/ens160.cpp
new file mode 100644 (file)
index 0000000..29e3704
--- /dev/null
@@ -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 <util/delay.h>
+#include <stdio.h>
+#include <avr/io.h>
+
+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 <n> 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/deye-sun-12k/src/adafruit/ens160.h b/software/deye-sun-12k/src/adafruit/ens160.h
new file mode 100644 (file)
index 0000000..7f26ba1
--- /dev/null
@@ -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 <stdint.h>
+// #define byte uint8_t
+
+// #if (ARDUINO >= 100)
+//     #include "Arduino.h"
+// #else
+//     #include "WProgram.h"
+// #endif
+
+// #include <Wire.h>
+
+// 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 <n> 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/deye-sun-12k/src/adafruit/sensor.h b/software/deye-sun-12k/src/adafruit/sensor.h
new file mode 100644 (file)
index 0000000..ac7e454
--- /dev/null
@@ -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 <stdint.h>
+#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; /**<Percentage, unit-less (%) */
+    sensors_color_t color;  /**< color in RGB component values */
+    float altitude; /**< Distance between a reference datum and a point or
+                       object, in meters. */
+  };                ///< Union for the wide ranges of data we can carry
+} sensors_event_t;
+
+/* Sensor details (40 bytes) */
+/** struct sensor_s is used to describe basic information about a specific
+ * sensor. */
+typedef struct {
+  char name[12];     /**< sensor name */
+  int32_t version;   /**< version of the hardware + driver */
+  int32_t sensor_id; /**< unique sensor identifier */
+  int32_t type;      /**< this sensor's type (ex. SENSOR_TYPE_LIGHT) */
+  float max_value;   /**< maximum value of this sensor's value in SI units */
+  float min_value;   /**< minimum value of this sensor's value in SI units */
+  float resolution; /**< smallest difference between two values reported by this
+                       sensor */
+  int32_t min_delay; /**< min delay in microseconds between events. zero = not a
+                        constant rate */
+} sensor_t;
+
+/** @brief Common sensor interface to unify various sensors.
+ * Intentionally modeled after sensors.h in the Android API:
+ * https://github.com/android/platform_hardware_libhardware/blob/master/include/hardware/sensors.h
+ */
+class Adafruit_Sensor {
+public:
+  // Constructor(s)
+  Adafruit_Sensor() {}
+//   virtual ~Adafruit_Sensor() {}
+
+//   // These must be defined by the subclass
+
+//   /*! @brief Whether we should automatically change the range (if possible) for
+//      higher precision
+//       @param enabled True if we will try to autorange */
+//   virtual void enableAutoRange(bool enabled) {
+//     (void)enabled; /* suppress unused warning */
+//   };
+
+//   /*! @brief Get the latest sensor event
+//       @returns True if able to fetch an event */
+//   virtual bool getEvent(sensors_event_t *) = 0;
+//   /*! @brief Get info about the sensor itself */
+//   virtual void getSensor(sensor_t *) = 0;
+
+//   void printSensorDetails(void);
+};
+
+#endif
diff --git a/software/deye-sun-12k/src/i2cmaster.cpp b/software/deye-sun-12k/src/i2cmaster.cpp
new file mode 100644 (file)
index 0000000..ca883d6
--- /dev/null
@@ -0,0 +1,155 @@
+#include <avr/io.h>
+#include <avr/pgmspace.h>
+#include <stdio.h>
+
+#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/deye-sun-12k/src/i2cmaster.hpp b/software/deye-sun-12k/src/i2cmaster.hpp
new file mode 100644 (file)
index 0000000..89b1e46
--- /dev/null
@@ -0,0 +1,30 @@
+#ifndef I2C_MASTER
+#define I2C_MASTER
+
+#include <stdint.h>
+
+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/deye-sun-12k/src/i2cslave.cpp b/software/deye-sun-12k/src/i2cslave.cpp
new file mode 100644 (file)
index 0000000..2bf6ac2
--- /dev/null
@@ -0,0 +1,92 @@
+#include <avr/io.h>
+#include <stdio.h>
+#include <util/atomic.h>
+
+#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/deye-sun-12k/src/i2cslave.hpp b/software/deye-sun-12k/src/i2cslave.hpp
new file mode 100644 (file)
index 0000000..2fe2dc7
--- /dev/null
@@ -0,0 +1,32 @@
+#ifndef I2C_SLAVE
+#define I2C_SLAVE
+
+#include <stdint.h>
+
+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/deye-sun-12k/src/main.cpp b/software/deye-sun-12k/src/main.cpp
new file mode 100644 (file)
index 0000000..8039aaf
--- /dev/null
@@ -0,0 +1,458 @@
+#include <avr/io.h>
+#include <avr/pgmspace.h>
+#include <avr/interrupt.h>
+#include <util/delay.h>
+
+#include <stdio.h>
+#include <util/atomic.h>
+
+#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"
+#include "units/deye.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);
+   Deye deye;
+}
+
+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 Nano-X-Base Hardware-Version: ADC7H = %d (ATmega644P, 3.3V)\n"), ADCH);
+      #elif __AVR_ATmega1284P__
+         printf_P(PSTR("\nInvalid Nano-X-Base Hardware-Version: ADC7H = %d (ATmega1284P, 3.3V)\n"), ADCH);
+      #elif __AVR_ATmega328P__
+         printf_P(PSTR("\nInvalid Nano-X-Base Hardware-Version: ADC7H = %d (ATmega328P, 5V)\n"), ADCH);
+      #endif
+      hardwareVersion = 0;
+   } 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 <<TXEN0);
+   UCSR0C = (1 << UCSZ01) | ( 1<< UCSZ00);
+   UBRR0H = 0;
+   UBRR0L = F_CPU / 8 / BAUD_RATE - 1;
+
+   TCCR2A = (1 << WGM21);
+   TCCR2B = (1 << CS21); // CTC, F_CPU/8=1.5MHz
+   OCR2A = 150; // 150/1.5E6 = 0.1ms
+   TIMSK2 = (1 << OCIE2A);
+
+   stdout = &mystdout;
+   stdin = &mystdin;
+
+   sei();
+
+   detectHardwareVersion();
+
+   uint8_t units;
+   #if defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__)
+      TestUnit *unit[] = {
+         &uart1, &i2cMaster, &i2cSlave, &i2cSparkfun, &rtc8563, &cc1101Send, &cc1101Receive,
+         &led, &sw, &rgb, &seg7, &poti, &encoder, &r2r, &motor, &portExp, &lcd,  &modbus, &ieee485, &deye
+      };
+      units = hardwareVersion == 0 ? 7 : sizeof(unit) / sizeof(unit[0]);
+   #endif
+
+   #ifdef __AVR_ATmega328P__
+      TestUnit *unit[] = {
+         &i2cMaster, &i2cSlave, &i2cSparkfun,
+         &led, &sw, &rgb, &seg7, &poti, &encoder, &r2r, &motor, &portExp, &lcd
+      };
+      units = hardwareVersion == 0 ? 3 : sizeof(unit) / sizeof(unit[0]);
+   #endif
+
+
+
+   while (1) {
+      uint16_t i;
+      char s[4];
+      do {
+         printf_P(PSTR_LINEFEED);
+         printf_P(PSTR_DIVIDER);
+         printf_P(MAIN_CPP_PART_NAME); printf_P(PSTR(" / "));
+         printf_P(MAIN_CPP_DATE); printf_P(PSTR(" / "));
+         printf_P(MAIN_CPP_TIME);
+         printf_P(PSTR_DIVIDER);
+         if (hardwareVersion >= 1 && hardwareVersion <= 2) {
+            printf_P(PSTR("Nano-X-Base: %S"), hardwareVersionPStr(hardwareVersion)); 
+         } else {
+            printf_P(PSTR("No Nano-X-Base detected"));
+         }
+         printf_P(PSTR_DIVIDER);
+         printf_P(PSTR_LINEFEED);
+         printf_P(PSTR("Available units:\n\n"));
+         for (i = 0; i < units; 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 >= units );
+      
+      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 (deye.enabled) {
+         deye.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/deye-sun-12k/src/main.hpp b/software/deye-sun-12k/src/main.hpp
new file mode 100644 (file)
index 0000000..7eeff16
--- /dev/null
@@ -0,0 +1,38 @@
+#ifndef MAIN_HPP
+#define MAIN_HPP
+
+#include <stdint.h>
+#include <avr/pgmspace.h>
+
+#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/deye-sun-12k/src/units/cc1101.cpp b/software/deye-sun-12k/src/units/cc1101.cpp
new file mode 100644 (file)
index 0000000..6cb011e
--- /dev/null
@@ -0,0 +1,761 @@
+#include <stdio.h>
+#include <avr/io.h>
+#include <avr/pgmspace.h>
+#include <util/delay.h>
+
+#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) {
+      if (!initDone) {
+         return -1;
+      }
+      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<<SPIF))) {}
+      return SPDR;
+   }
+
+   void Cc1101::triggerOn () {
+      PORTB |= (1 << PB0);
+   }
+
+   void Cc1101::triggerOff () {
+      PORTB &= ~(1 << PB0);
+   }
+
+   void Cc1101::triggerToggle () {
+      PORTB ^= (1 << PB0);
+   }
+
+   PGM_P Cc1101::getName () {
+      switch (mode) {
+         case Send: return PSTR("CC-1101-Send");
+         case Receive: return PSTR("CC-1101-Receive");
+         case Test: return PSTR("CC-1101-Test");
+         default: return PSTR("CC-1101-?");
+      }
+   }
+
+   void Cc1101::init () {
+
+      // trigger for debugging
+      PORTB &= ~(1 << PB0);
+      DDRB |= ( 1 << PB0);
+
+      #ifdef __AVR_ATmega1284P__
+         // Nano-1284
+         triggerOn();
+         DDRC |= (1 << PC6);
+         PORTC |= (1 << PC6); // modem voltage 3.3V ON
+         _delay_us(100);
+         triggerOff();
+      #endif
+
+      PRR0 &= (1 << PRSPI);
+      
+      // nCs
+      PORTA |= (1 << PA4);
+      DDRA |= (1 << PA4);
+      // PORTB/DDRB must be configured before SPCR !!
+      
+      PORTB |= (1 << PB4); // nSS must be HIGH, otherwise SPI master will not become active!!
+      DDRB &= ~(1 << PB6); // MISO
+      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
+
+      // GDO0
+      PORTA |= (1 << PA5);
+      DDRA &= ~(1 << PA5);
+
+      printf_P(PSTR(" reset CC1101 ... "));
+      if (!resetCC1101()) {
+         printf_P(PSTR("fails"));
+         return;
+      }
+      printf_P(PSTR("OK, init register ... "));;
+      if (!initRegister()) {
+         printf_P(PSTR("fails"));
+         return;
+      }
+      printf_P(PSTR("OK, init PATABLE ... "));;
+      if (!initPaTable()) {
+         printf_P(PSTR("fails"));
+         return;
+      }
+      printf_P(PSTR("OK"));
+      initDone = true;
+
+      debugPrint.byte = 0xff; // print all
+      printRegisters();
+      debugPrint.byte = 0x00; // print nothing
+
+   }
+
+   void Cc1101::cleanup () {
+      // trigger for debugging
+      PORTB &= ~(1 << PB0);
+      DDRB &= ~( 1 << PB0);
+      
+      SPCR = 0;
+      PORTB &= ~(1 << PB4);
+      DDRB &= ~((1 << PB7) | (1 << PB6) | (1 << PB5) | (1 << PB4));
+      DDRA &= ~((1 << PA5) | (1 << PA4));
+      PORTA &= ~((1 << PA5) | (1 << PA4));
+
+      #ifdef __AVR_ATmega1284P__
+         // Nano-1284
+         DDRC &= ~(1 << PC6);
+         PORTC &= ~(1 << PC6); // modem voltage 3.3V OFF
+      #endif
+
+      initDone = false;
+   }
+
+   void Cc1101::setChipEnableLow () {
+      // triggerOn();
+      PORTA &= ~(1 << PA4);
+   }
+
+   void Cc1101::setChipEnableHigh () {
+      // triggerOff();
+      PORTA |= (1 << PA4);
+   }
+
+   bool Cc1101::isMisoHigh () {
+      return (PINB & (1 << PB6)) != 0;
+   }
+
+   bool Cc1101::isGd0High () {
+      return (PINA & (1 << PA5)) != 0;
+   }
+
+   bool Cc1101::waitForMisoLow () {
+      timer = 10;
+      while (isMisoHigh()) {
+         if (timer == 0) {
+            return false;
+         }
+      }
+      return true;
+   }
+
+   bool Cc1101::waitForGD0High () {
+      timer = 100;
+      while (!isGd0High()) {
+         if (timer == 0) {
+            return false;
+         }
+      }
+      return true;
+   }
+
+   bool Cc1101::waitForGD0Low () {
+      timer = 100;
+      while (isGd0High()) {
+         if (timer == 0) {
+            return false;
+         }
+      }
+      return true;
+   }
+
+   bool Cc1101::strobe (StrobeCommand_t command) {
+          bool ok = true;
+      setChipEnableLow();
+      ok &= waitForMisoLow();
+          sendSpiByte(command & 0x3f);
+      setChipEnableHigh();
+          return ok;
+   }
+
+   bool Cc1101::writeRegister (uint8_t addr, uint8_t value) {
+      bool ok = true;
+      
+      setChipEnableLow();
+      ok &= waitForMisoLow();
+      sendSpiByte(addr);
+      status.spiResponse.byte = sendSpiByte(value);
+      status.spiResponseValid = 1;
+      setChipEnableHigh();
+      
+      if (debugPrint.print.writeRegister) {
+         printf_P(PSTR("\n [writeRegister(0x%02x, 0x%02x) -> "), 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(&regValue, ((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);
+      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(&regValue, ((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/deye-sun-12k/src/units/cc1101.hpp b/software/deye-sun-12k/src/units/cc1101.hpp
new file mode 100644 (file)
index 0000000..3a51ccc
--- /dev/null
@@ -0,0 +1,282 @@
+#ifndef CC1101_HPP
+#define CC1101_HPP
+
+#include <stdint.h>
+#include "../main.hpp"
+#include <avr/pgmspace.h>
+
+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; initDone = false; }
+      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:
+      bool initDone;
+      Cc1101Mode mode;
+      volatile 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/deye-sun-12k/src/units/deye.cpp b/software/deye-sun-12k/src/units/deye.cpp
new file mode 100644 (file)
index 0000000..71cd961
--- /dev/null
@@ -0,0 +1,231 @@
+#include <stdio.h>
+#include <avr/io.h>
+#include <util/delay.h>
+
+#include "deye.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 Deye::init () {
+}
+
+void Deye::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));
+}
+
+uint16_t Deye::updateModbusCRC (uint8_t b, uint16_t crc) {
+   crc = crc ^ (uint16_t)b;
+   for (uint8_t i = 0; i < 8; i++) {
+       crc = crc & 0x01 ? (crc >> 1) ^ 0xa001 : crc >> 1;
+   }
+   return crc;
+}
+
+
+int8_t Deye::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 <<TXEN1);
+      UCSR1C = (1 << UCSZ11) | ( 1<< UCSZ10);
+      // UCSR1C |= (1 <<UPM11); // even Parity
+      // UCSR1C |= (1 << UPM11) | (1 << UPM10); // odd Parity
+      UBRR1H = 0;
+      UBRR1L = F_CPU / 8 / 9600 - 1;
+
+      enabled = 1;
+      printf_P(PSTR("init 9600/8N1"));
+
+   } else if (subtest == 1) {
+      while (1) {
+         static uint8_t frame[16] = { 0x01, 0x03 };
+         uint16_t addr = 672; // 0x2A0;
+         uint16_t quantity = 8;
+         frame[2] = (uint8_t)(addr >> 8); frame[3] = (uint8_t)(addr & 0xff);
+         frame[4] = (uint8_t)(quantity >> 8); frame[5] = (uint8_t)(quantity & 0xff);
+         uint16_t crc = updateModbusCRC(frame[0], 0xffff);
+         for (uint8_t i = 1; i < 6; i++) {
+            crc = updateModbusCRC(frame[i], crc);
+         }
+         frame[6] = (uint8_t)(crc & 0xff);
+         frame[7] = (uint8_t)(crc >> 8);
+
+         SET_DE; CLR_nRE; _delay_us(500); receivedBytes = 0;
+         for (uint8_t i = 0; i < 8; i++) {
+            UCSR1A |= (1 << TXC1);
+            UDR1 = frame[i];
+            while ((UCSR1A & (1 <<UDRE1)) == 0) {}
+         }
+         while ((UCSR1A & (1 << TXC1)) == 0) {}
+         CLR_DE;
+
+         int k = wait(100);
+   
+         if (received[8] == 0x01 && received[9] == 3 && received[10] == quantity * 2) {
+            uint16_t pv1_p = (received[8 + 3 + 0] << 8) | received[8 + 3 + 1];
+            uint16_t pv1_v = (received[8 + 3 + 8] << 8) | received[8 + 3 + 9];
+            uint16_t pv1_i = (received[8 + 3 + 10] << 8) | received[8 + 3 + 11];
+            printf_P(PSTR("\nPV1: P=%uW  V=%.1fV  I=%.2fA"), pv1_p, pv1_v * 0.1, pv1_i * 0.1);
+         } else {
+            printf_P(PSTR("\n ERROR: 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 (k != EOF) {
+            break;
+         }
+      }
+
+   } else if (subtest == 2) {
+      // static uint8_t frame[] = { 0x01, 0x04, 0x00, 0x00, 0x00, 0x02, 0x71, 0xcb };
+      static uint8_t frame[] = { 0x01, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00 };
+      
+      uint16_t addr = 627;
+      /// uint16_t addr = 1;
+      printf_P(PSTR("Modbus: lese Register %d (0x%04x)"), addr, addr);
+      
+      frame[2] = (uint8_t)(addr >> 8);
+      frame[3] = (uint8_t)(addr & 0xff);
+      uint16_t crc = updateModbusCRC(frame[0], 0xffff);
+      for (uint8_t i = 1; i < sizeof(frame) - 2; i++) {
+         crc = updateModbusCRC(frame[i], crc);
+      }
+      frame[sizeof(frame) - 2] = (uint8_t)(crc & 0xff);
+      frame[sizeof(frame) - 1] = (uint8_t)(crc >> 8);
+
+      SET_DE;
+      CLR_nRE;
+
+      for (uint32_t addr = 0; addr < 65535; addr++) {
+         
+         /// uint16_t addr = 1;
+         // printf_P(PSTR("Modbus: lese Register %d (0x%04x)"), addr, addr);
+         
+         frame[2] = (uint8_t)( (addr >> 8) & 0xff);
+         frame[3] = (uint8_t)(addr & 0xff);
+         uint16_t crc = updateModbusCRC(frame[0], 0xffff);
+         for (uint8_t i = 1; i < sizeof(frame) - 2; i++) {
+            crc = updateModbusCRC(frame[i], crc);
+         }
+         frame[sizeof(frame) - 2] = (uint8_t)(crc & 0xff);
+         frame[sizeof(frame) - 1] = (uint8_t)(crc >> 8);
+
+         SET_DE;
+         _delay_us(500);
+         receivedBytes = 0;
+         for (uint8_t i = 0; i < sizeof(frame); i++) {
+            UCSR1A |= (1 << TXC1);
+            UDR1 = frame[i];
+            while ((UCSR1A & (1 <<UDRE1)) == 0) {}
+         }
+         while ((UCSR1A & (1 << TXC1)) == 0) {}
+         CLR_DE;
+         // printf_P(PSTR("\n => Sending:"));
+         // for (uint8_t i = 0; i < sizeof(frame); i++) {
+         //    printf_P(PSTR(" 0x%02x"), frame[i]);
+         // }
+         int k = wait(100);
+      
+         if (receivedBytes != 15 || received[8] != 1 || received[9] != 3 || received[10] != 2) {
+            printf_P(PSTR("%u ERROR => Sending"), (uint16_t)addr );
+            for (uint8_t i = 0; i < sizeof(frame); i++) {
+               printf_P(PSTR(" 0x%02x"), frame[i]);
+            }
+            printf_P(PSTR(" => "));
+            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]);
+               }
+            }
+            printf_P(PSTR("\n"));
+         } else {
+            printf_P(PSTR("%u %u\n"), (uint16_t)addr, received[11] << 8 | received[12] );
+         }
+         // 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 Deye::handleRxByte (uint8_t b) {
+   if (receivedBytes < sizeof(received)) {
+      received[receivedBytes++] = b;
+   }
+}
+
+#endif
diff --git a/software/deye-sun-12k/src/units/deye.hpp b/software/deye-sun-12k/src/units/deye.hpp
new file mode 100644 (file)
index 0000000..a79c6da
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef DEYE_HPP
+#define DEYE_HPP
+
+#include <stdint.h>
+#include "../main.hpp"
+#include <avr/pgmspace.h>
+
+class Deye : public TestUnit {
+   public:
+      uint8_t  enabled;
+      uint8_t  receivedBytes;
+      uint8_t  received[128];
+
+
+   public:
+   Deye () { enabled = 0; receivedBytes = 0; }
+      virtual void init ();
+      virtual void cleanup ();
+      virtual int8_t run (uint8_t subtest);
+      virtual PGM_P getName () { return PSTR("Deye"); }
+      uint16_t updateModbusCRC (uint8_t b, uint16_t crc);
+      void handleRxByte (uint8_t);
+};
+
+#endif
\ No newline at end of file
diff --git a/software/deye-sun-12k/src/units/encoder.cpp b/software/deye-sun-12k/src/units/encoder.cpp
new file mode 100644 (file)
index 0000000..7b33b76
--- /dev/null
@@ -0,0 +1,138 @@
+#include <stdio.h>
+#include <avr/io.h>
+
+#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/deye-sun-12k/src/units/encoder.hpp b/software/deye-sun-12k/src/units/encoder.hpp
new file mode 100644 (file)
index 0000000..9b0861b
--- /dev/null
@@ -0,0 +1,28 @@
+#ifndef ENCODER_HPP
+#define ENCODER_PP
+
+#include <stdint.h>
+#include "../main.hpp"
+#include <avr/pgmspace.h>
+
+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/deye-sun-12k/src/units/i2c.cpp b/software/deye-sun-12k/src/units/i2c.cpp
new file mode 100644 (file)
index 0000000..60dd22d
--- /dev/null
@@ -0,0 +1,216 @@
+#include <stdio.h>
+#include <avr/io.h>
+#include <avr/pgmspace.h>
+#include <util/delay.h>
+#include <math.h>
+
+#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/deye-sun-12k/src/units/i2c.hpp b/software/deye-sun-12k/src/units/i2c.hpp
new file mode 100644 (file)
index 0000000..2148cc0
--- /dev/null
@@ -0,0 +1,43 @@
+#ifndef I2C_HPP
+#define I2C_HPP
+
+#include <stdint.h>
+#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/deye-sun-12k/src/units/ieee485.cpp b/software/deye-sun-12k/src/units/ieee485.cpp
new file mode 100644 (file)
index 0000000..8fcb67a
--- /dev/null
@@ -0,0 +1,111 @@
+#include <stdio.h>
+#include <avr/io.h>
+#include <util/delay.h>
+#include <util/atomic.h>
+
+#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 <<TXEN1);
+   UCSR1C = (1 << UCSZ11) | ( 1<< UCSZ10);
+   // UCSR1C |= (1 <<UPM11); // even Parity
+   // UCSR1C |= (1 << UPM11) | (1 << UPM10); // odd Parity
+   UBRR1H = 0;
+   UBRR1L = F_CPU / 8 / 9600 - 1;
+
+   enabled = 1;
+}
+
+void Ieee485::cleanup () {
+   enabled = 0;
+
+   ADMUX = 0;
+   ADCSRA = 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 Ieee485::run (uint8_t subtest) {
+   if (subtest == 0) {
+      CLR_nRE; CLR_DE;
+      while (wait(500) == EOF) {
+         ADCSRA |= (1 << ADSC); // start ADC
+         while (ADCSRA & (1 << ADSC)) {} // wait for result
+         UCSR1A |= (1 << TXC1);
+         SET_nRE;
+         SET_DE;
+         UDR1 = ADCH;
+         while ((UCSR1A & (1 << TXC1)) == 0) {}
+         CLR_DE;
+         CLR_nRE;
+         printf_P(PSTR("\n  => 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/deye-sun-12k/src/units/ieee485.hpp b/software/deye-sun-12k/src/units/ieee485.hpp
new file mode 100644 (file)
index 0000000..ffbb15c
--- /dev/null
@@ -0,0 +1,22 @@
+#ifndef IEEE485_HPP
+#define IEEE485_HPP
+
+#include <stdint.h>
+#include "../main.hpp"
+#include <avr/pgmspace.h>
+
+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/deye-sun-12k/src/units/lcd.cpp b/software/deye-sun-12k/src/units/lcd.cpp
new file mode 100644 (file)
index 0000000..e779c16
--- /dev/null
@@ -0,0 +1,443 @@
+#include <stdio.h>
+#include <avr/io.h>
+#include <util/delay.h>
+
+#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/deye-sun-12k/src/units/lcd.hpp b/software/deye-sun-12k/src/units/lcd.hpp
new file mode 100644 (file)
index 0000000..47a30cc
--- /dev/null
@@ -0,0 +1,48 @@
+#ifndef LCD_HPP
+#define LCD_HPP
+
+#include <stdint.h>
+#include "../main.hpp"
+#include <avr/pgmspace.h>
+
+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/deye-sun-12k/src/units/led.cpp b/software/deye-sun-12k/src/units/led.cpp
new file mode 100644 (file)
index 0000000..e908c21
--- /dev/null
@@ -0,0 +1,139 @@
+#include <stdio.h>
+#include <avr/io.h>
+#include <util/delay.h>
+
+#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/deye-sun-12k/src/units/led.hpp b/software/deye-sun-12k/src/units/led.hpp
new file mode 100644 (file)
index 0000000..780827f
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef LED_HPP
+#define LED_HPP
+
+#include <stdint.h>
+#include "../main.hpp"
+#include <avr/pgmspace.h>
+
+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/deye-sun-12k/src/units/modbus.cpp b/software/deye-sun-12k/src/units/modbus.cpp
new file mode 100644 (file)
index 0000000..abbe36d
--- /dev/null
@@ -0,0 +1,160 @@
+#include <stdio.h>
+#include <avr/io.h>
+#include <util/delay.h>
+
+#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 <<TXEN1);
+      UCSR1C = (1 << UCSZ11) | ( 1<< UCSZ10);
+      // UCSR1C |= (1 <<UPM11); // even Parity
+      // UCSR1C |= (1 << UPM11) | (1 << UPM10); // odd Parity
+      UBRR1H = 0;
+      UBRR1L = F_CPU / 8 / 9600 - 1;
+
+      enabled = 1;
+      printf_P(PSTR("init"));
+
+   } else if (subtest >= 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 <<UDRE1)) == 0) {}
+         }
+         while ((UCSR1A & (1 << TXC1)) == 0) {}
+         CLR_DE;
+         printf_P(PSTR("\n => 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/deye-sun-12k/src/units/modbus.hpp b/software/deye-sun-12k/src/units/modbus.hpp
new file mode 100644 (file)
index 0000000..44b6a9d
--- /dev/null
@@ -0,0 +1,24 @@
+#ifndef MODBUS_HPP
+#define MODBUS_HPP
+
+#include <stdint.h>
+#include "../main.hpp"
+#include <avr/pgmspace.h>
+
+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/deye-sun-12k/src/units/motor.cpp b/software/deye-sun-12k/src/units/motor.cpp
new file mode 100644 (file)
index 0000000..7f8fbf9
--- /dev/null
@@ -0,0 +1,221 @@
+#include <stdio.h>
+#include <avr/io.h>
+#include <util/atomic.h>
+
+#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/deye-sun-12k/src/units/motor.hpp b/software/deye-sun-12k/src/units/motor.hpp
new file mode 100644 (file)
index 0000000..2cbd15a
--- /dev/null
@@ -0,0 +1,30 @@
+#ifndef MOTOR_HPP
+#define MOTOR_HPP
+
+#include <stdint.h>
+#include "../main.hpp"
+#include <avr/pgmspace.h>
+
+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/deye-sun-12k/src/units/portexp.cpp b/software/deye-sun-12k/src/units/portexp.cpp
new file mode 100644 (file)
index 0000000..a153589
--- /dev/null
@@ -0,0 +1,195 @@
+#include <stdio.h>
+#include <avr/io.h>
+#include <util/delay.h>
+
+#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/deye-sun-12k/src/units/portexp.hpp b/software/deye-sun-12k/src/units/portexp.hpp
new file mode 100644 (file)
index 0000000..8705662
--- /dev/null
@@ -0,0 +1,24 @@
+#ifndef PORTEXP_HPP
+#define PORTEXP_HPP
+
+#include <stdint.h>
+#include "../main.hpp"
+#include <avr/pgmspace.h>
+
+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/deye-sun-12k/src/units/poti.cpp b/software/deye-sun-12k/src/units/poti.cpp
new file mode 100644 (file)
index 0000000..94fc5a4
--- /dev/null
@@ -0,0 +1,34 @@
+#include <stdio.h>
+#include <avr/io.h>
+
+#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/deye-sun-12k/src/units/poti.hpp b/software/deye-sun-12k/src/units/poti.hpp
new file mode 100644 (file)
index 0000000..b13dd29
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef POTI_HPP
+#define POTI_PP
+
+#include <stdint.h>
+#include "../main.hpp"
+#include <avr/pgmspace.h>
+
+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/deye-sun-12k/src/units/r2r.cpp b/software/deye-sun-12k/src/units/r2r.cpp
new file mode 100644 (file)
index 0000000..54664b1
--- /dev/null
@@ -0,0 +1,48 @@
+#include <stdio.h>
+#include <avr/io.h>
+
+#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/deye-sun-12k/src/units/r2r.hpp b/software/deye-sun-12k/src/units/r2r.hpp
new file mode 100644 (file)
index 0000000..84e97e6
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef R2R_HPP
+#define R2R_PP
+
+#include <stdint.h>
+#include "../main.hpp"
+#include <avr/pgmspace.h>
+
+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/deye-sun-12k/src/units/rgb.cpp b/software/deye-sun-12k/src/units/rgb.cpp
new file mode 100644 (file)
index 0000000..3f69cbd
--- /dev/null
@@ -0,0 +1,152 @@
+#include <stdio.h>
+#include <avr/io.h>
+
+#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/deye-sun-12k/src/units/rgb.hpp b/software/deye-sun-12k/src/units/rgb.hpp
new file mode 100644 (file)
index 0000000..12e9da4
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef RGB_HPP
+#define RGB_PP
+
+#include <stdint.h>
+#include "../main.hpp"
+#include <avr/pgmspace.h>
+
+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/deye-sun-12k/src/units/rtc8563.cpp b/software/deye-sun-12k/src/units/rtc8563.cpp
new file mode 100644 (file)
index 0000000..6ae6497
--- /dev/null
@@ -0,0 +1,253 @@
+#include <stdio.h>
+#include <avr/io.h>
+#include <avr/pgmspace.h>
+#include <util/delay.h>
+#include <math.h>
+
+#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 *)&reg;
+      memset(&reg, 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, &reg.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) {
+
+   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, &reg.reg1.byte, 1) && rtc8563.writeByteAndBuffer(14, &reg.timerControl.byte, 2)) {
+      printf_P(PSTR("OK"));
+      return true;
+   } else {
+      printf_P(PSTR("fails"));
+      return false;
+   }
+}
+
+bool Rtc8563::powerOnOff (uint8_t delayOffSeconds, Rtc8563Reg_t &reg) {
+   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, &reg.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/deye-sun-12k/src/units/rtc8563.hpp b/software/deye-sun-12k/src/units/rtc8563.hpp
new file mode 100644 (file)
index 0000000..ca79713
--- /dev/null
@@ -0,0 +1,70 @@
+#ifndef RTC8563_HPP
+#define RTC8563_HPP
+
+#include <stdint.h>
+#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 &reg);
+      bool powerOnOff (uint8_t delayOffSeconds, Rtc8563Reg_t &reg);
+      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/deye-sun-12k/src/units/seg7.cpp b/software/deye-sun-12k/src/units/seg7.cpp
new file mode 100644 (file)
index 0000000..f522456
--- /dev/null
@@ -0,0 +1,283 @@
+#include <stdio.h>
+#include <avr/io.h>
+
+#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/deye-sun-12k/src/units/seg7.hpp b/software/deye-sun-12k/src/units/seg7.hpp
new file mode 100644 (file)
index 0000000..0e71fde
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef SEG7_HPP
+#define SEG7_HPP
+
+#include <stdint.h>
+#include "../main.hpp"
+#include <avr/pgmspace.h>
+
+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/deye-sun-12k/src/units/switch.cpp b/software/deye-sun-12k/src/units/switch.cpp
new file mode 100644 (file)
index 0000000..4ce9456
--- /dev/null
@@ -0,0 +1,100 @@
+#include <stdio.h>
+#include <avr/io.h>
+#include <util/delay.h>
+
+#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/deye-sun-12k/src/units/switch.hpp b/software/deye-sun-12k/src/units/switch.hpp
new file mode 100644 (file)
index 0000000..03bf0b2
--- /dev/null
@@ -0,0 +1,20 @@
+#ifndef SWITCH_HPP
+#define SWITCH_HPP
+
+#include <stdint.h>
+#include "../main.hpp"
+#include <avr/pgmspace.h>
+
+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/deye-sun-12k/src/units/uart1.cpp b/software/deye-sun-12k/src/units/uart1.cpp
new file mode 100644 (file)
index 0000000..57e0bfb
--- /dev/null
@@ -0,0 +1,65 @@
+#include <stdio.h>
+#include <avr/io.h>
+#include <util/delay.h>
+
+#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 <<TXEN1);
+   UCSR1C = (1 << UCSZ11) | ( 1<< UCSZ10);
+   UBRR1H = 0;
+   UBRR1L = F_CPU / 8 / 115200 - 1;
+   stderr = &mystderr;
+   enabled = 1;
+}
+
+void Uart1::cleanup () {
+   enabled = 0;
+   UCSR1A = 0;
+   UCSR1B = 0;
+   UCSR1C = 0;
+   UBRR1H = 0;
+   UBRR1L = 0;
+   stderr = NULL;
+}
+
+int8_t Uart1::run (uint8_t subtest) {
+   if (subtest == 0) {
+      do {
+         printf_P(PSTR("\n => 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/deye-sun-12k/src/units/uart1.hpp b/software/deye-sun-12k/src/units/uart1.hpp
new file mode 100644 (file)
index 0000000..40437e1
--- /dev/null
@@ -0,0 +1,21 @@
+#ifndef UART1_HPP
+#define UART1_HPP
+
+#include <stdint.h>
+#include "../main.hpp"
+#include <avr/pgmspace.h>
+
+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