summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHarsh Sharma <92harshsharma@gmail.com>2018-06-13 13:24:54 -0500
committerHarsh Sharma <92harshsharma@gmail.com>2018-06-13 13:24:54 -0500
commit7c383be1542368f2601015d9fc2a417197677677 (patch)
treebc06453f879cbadf65fd88123c506956403c5684
downloadlora_gateway_mtac_full-7c383be1542368f2601015d9fc2a417197677677.tar.gz
lora_gateway_mtac_full-7c383be1542368f2601015d9fc2a417197677677.tar.bz2
lora_gateway_mtac_full-7c383be1542368f2601015d9fc2a417197677677.zip
Initial Commit
-rw-r--r--.gitignore3
-rw-r--r--LICENSE49
-rw-r--r--Makefile27
-rw-r--r--VERSION1
-rw-r--r--fpga/SX1301_FPGA_200K_NOTCH_LBT_SPECTRAL_SCAN_863_v33.hex1659
-rw-r--r--fpga/SX1301_FPGA_200K_NOTCH_LBT_SPECTRAL_SCAN_915_v33.hex1659
-rw-r--r--fpga/SX1301_FPGA_NOTCH_PROG_SPECTRAL_SCAN_v31.hex1659
-rw-r--r--fpga/readme.md72
-rw-r--r--libloragw/99-libftdi.rules8
-rw-r--r--libloragw/Makefile91
-rw-r--r--libloragw/inc/loragw_aux.h48
-rw-r--r--libloragw/inc/loragw_fpga.h135
-rw-r--r--libloragw/inc/loragw_gps.h235
-rw-r--r--libloragw/inc/loragw_hal.h419
-rw-r--r--libloragw/inc/loragw_lbt.h70
-rw-r--r--libloragw/inc/loragw_radio.h73
-rw-r--r--libloragw/inc/loragw_reg.h461
-rw-r--r--libloragw/inc/loragw_spi.h105
-rw-r--r--libloragw/inc/loragw_sx125x.h49
-rw-r--r--libloragw/inc/loragw_sx1272_fsk.h113
-rw-r--r--libloragw/inc/loragw_sx1272_lora.h89
-rw-r--r--libloragw/inc/loragw_sx1276_fsk.h112
-rw-r--r--libloragw/inc/loragw_sx1276_lora.h94
-rw-r--r--libloragw/library.cfg12
-rw-r--r--libloragw/readme.md457
-rw-r--r--libloragw/src/agc_fw.var529
-rw-r--r--libloragw/src/arb_fw.var529
-rw-r--r--libloragw/src/cal_fw.var529
-rw-r--r--libloragw/src/loragw_aux.c61
-rw-r--r--libloragw/src/loragw_fpga.c352
-rw-r--r--libloragw/src/loragw_gps.c835
-rw-r--r--libloragw/src/loragw_hal.c1767
-rw-r--r--libloragw/src/loragw_lbt.c391
-rw-r--r--libloragw/src/loragw_radio.c562
-rw-r--r--libloragw/src/loragw_reg.c819
-rw-r--r--libloragw/src/loragw_spi.native.c385
-rw-r--r--libloragw/tst/test_loragw_cal.c756
-rw-r--r--libloragw/tst/test_loragw_gps.c288
-rw-r--r--libloragw/tst/test_loragw_hal.c416
-rw-r--r--libloragw/tst/test_loragw_reg.c134
-rw-r--r--libloragw/tst/test_loragw_spi.c85
-rw-r--r--readme.md410
-rwxr-xr-xreset_lgw.sh62
-rw-r--r--util_lbt_test/Makefile65
-rw-r--r--util_lbt_test/readme.md50
-rw-r--r--util_lbt_test/src/util_lbt_test.c274
-rw-r--r--util_pkt_logger/Makefile70
-rw-r--r--util_pkt_logger/global_conf.json87
-rw-r--r--util_pkt_logger/inc/parson.h222
-rw-r--r--util_pkt_logger/local_conf.json5
-rw-r--r--util_pkt_logger/readme.md143
-rw-r--r--util_pkt_logger/src/parson.c1765
-rw-r--r--util_pkt_logger/src/util_pkt_logger.c626
-rw-r--r--util_spectral_scan/Makefile63
-rw-r--r--util_spectral_scan/readme.md79
-rw-r--r--util_spectral_scan/src/util_spectral_scan.c403
-rw-r--r--util_spi_stress/Makefile66
-rw-r--r--util_spi_stress/readme.md93
-rw-r--r--util_spi_stress/src/util_spi_stress.c292
-rw-r--r--util_tx_continuous/Makefile68
-rw-r--r--util_tx_continuous/readme.md62
-rw-r--r--util_tx_continuous/src/util_tx_continuous.c454
-rw-r--r--util_tx_test/Makefile67
-rw-r--r--util_tx_test/readme.md75
-rw-r--r--util_tx_test/src/util_tx_test.c661
65 files changed, 22300 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..ea0baf2
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+*.o
+*.swp
+*.bak
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..62de0d4
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,49 @@
+Copyright (c) 2013, SEMTECH S.A.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of the Semtech corporation nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL SEMTECH S.A. BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+--- For the parson library used by the packet logger ---
+
+Parson ( http://kgabis.github.com/parson/ )
+Copyright (c) 2012 Krzysztof Gabis
+
+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,
+ITNESS 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/Makefile b/Makefile
new file mode 100644
index 0000000..3a1c041
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,27 @@
+### Environment constants
+
+ARCH ?=
+CROSS_COMPILE ?=
+export
+
+### general build targets
+
+all:
+ $(MAKE) all -e -C libloragw
+ $(MAKE) all -e -C util_pkt_logger
+ $(MAKE) all -e -C util_spi_stress
+ $(MAKE) all -e -C util_tx_test
+ $(MAKE) all -e -C util_lbt_test
+ $(MAKE) all -e -C util_tx_continuous
+ $(MAKE) all -e -C util_spectral_scan
+
+clean:
+ $(MAKE) clean -e -C libloragw
+ $(MAKE) clean -e -C util_pkt_logger
+ $(MAKE) clean -e -C util_spi_stress
+ $(MAKE) clean -e -C util_tx_test
+ $(MAKE) clean -e -C util_lbt_test
+ $(MAKE) clean -e -C util_tx_continuous
+ $(MAKE) clean -e -C util_spectral_scan
+
+### EOF
diff --git a/VERSION b/VERSION
new file mode 100644
index 0000000..6b244dc
--- /dev/null
+++ b/VERSION
@@ -0,0 +1 @@
+5.0.1
diff --git a/fpga/SX1301_FPGA_200K_NOTCH_LBT_SPECTRAL_SCAN_863_v33.hex b/fpga/SX1301_FPGA_200K_NOTCH_LBT_SPECTRAL_SCAN_863_v33.hex
new file mode 100644
index 0000000..4cff280
--- /dev/null
+++ b/fpga/SX1301_FPGA_200K_NOTCH_LBT_SPECTRAL_SCAN_863_v33.hex
@@ -0,0 +1,1659 @@
+ff 00
+4c 61 74 74 69 63 65 00
+69 43 45 63 75 62 65 32 20 32 30 31 35 2e 30 34 2e 32 37 34 30 39 00
+50 61 72 74 3a 20 69 43 45 34 30 4c 50 31 4b 2d 43 4d 34 39 00
+44 61 74 65 3a 20 4f 63 74 20 31 37 20 32 30 31 36 20 31 31 3a 33 33 3a 31 32 00
+00 ff
+7e aa 99 7e
+51 00
+01 05
+92 00 20
+62 01 4b
+72 00 90
+82 00 00
+11 00
+01 01
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 40 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 01 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 10 00 00
+00 00 00 00 00 04 00 00 00 00 00 00 10 00 00 00 00 00 00 40 00 00 00 00 10 00 00 00 00 00 00 40 00 00 00 00 00 01 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 04 00 00 00 00 00 00 10 00 00 00 00 00 00 40 00 00 00 00 10 00 00 00 00 00 00 40 00 00 00 00 08 03 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 06 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 50 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 80 03 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 08 00 30 00 10 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 04 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 08 00 00 00 00 00 00
+00 00 00 00 00 0f 22 13 00 00 01 c0 1c 00 00 00 00 00 0f 70 01 00 00 07 00 c5 00 00 00 00 00 fa 21 30 00 00 00 21 78 f5 00
+00 00 00 00 00 0b 70 04 90 80 00 02 00 e0 a5 01 00 00 01 ad 82 00 00 00 40 c0 a0 00 00 00 00 e3 00 49 08 00 03 40 06 0a 00 10
+00 00 18 00 80 0f 22 13 00 00 00 40 0d e5 00 09 81 85 80 10 00 10 80 00 20 c0 50 01 83 89 00 32 21 30 00 81 2c 02 00 24 00
+00 00 00 00 07 00 50 04 90 00 00 00 24 10 50 00 00 00 00 03 82 00 00 00 00 c0 0a 00 00 00 78 07 00 49 40 04 01 40 04 91 80 00
+00 00 10 00 01 9d 22 13 00 00 00 03 a1 e5 00 00 00 00 08 d8 00 02 00 06 80 e5 00 01 00 00 00 9a 21 30 00 00 0c 01 48 05 20
+00 00 01 00 00 08 78 04 90 00 00 00 02 40 a0 00 00 00 00 0f 01 00 40 00 00 c0 a0 00 10 18 f0 03 00 49 40 00 00 03 83 00 50 00
+00 02 00 00 19 9d 22 13 00 00 00 03 15 80 50 00 00 08 00 30 00 00 00 00 1e c0 50 00 00 00 1a 5a 21 30 00 00 00 04 18 50 00
+00 00 00 00 0d 08 58 04 90 00 00 2c 00 30 05 00 40 00 50 0b 01 00 00 04 00 00 05 00 00 05 00 07 80 49 00 00 20 03 64 0a 01 00
+00 00 00 00 00 0f a2 13 00 40 02 00 24 00 00 00 00 05 0a 10 10 00 03 40 16 8f 50 00 00 00 00 d2 21 30 00 00 00 00 5c 50 00
+00 00 20 00 00 00 70 04 90 04 00 0c 02 40 a5 00 00 00 50 07 80 00 00 0c 00 d0 a0 00 00 00 70 03 00 49 00 00 20 00 02 05 00 00
+00 00 00 00 00 0d a2 13 00 00 00 00 17 80 50 00 00 00 01 f0 10 00 01 46 9e c0 50 00 00 01 00 7a 21 30 00 00 1e 20 0e 50 00
+00 00 00 00 00 00 50 04 90 00 00 00 00 30 05 00 00 00 10 af 80 00 00 00 00 20 05 00 00 00 b0 07 80 49 00 00 40 00 24 0a 00 00
+00 00 00 00 98 0d a2 13 00 00 00 40 07 aa 00 00 00 07 1b 98 00 00 16 00 01 c5 00 00 00 0d 80 ba 21 32 00 00 04 00 5c 50 00
+00 00 00 00 01 00 78 04 90 00 00 00 20 00 a0 00 80 00 08 a3 00 10 00 14 00 d0 a0 00 00 00 b0 03 00 49 00 00 00 00 03 05 00 00
+00 00 10 00 b8 0d a2 11 00 00 02 02 1d 80 50 03 00 0f 0a b8 10 00 01 62 8c a5 00 01 00 08 1a 72 21 30 01 00 00 00 0a 50 00
+00 00 01 00 01 80 58 04 90 00 00 1c 00 10 05 00 30 00 58 a7 80 00 00 00 00 10 50 00 10 00 50 07 00 49 00 10 00 00 24 0a 00 00
+00 00 00 00 70 01 61 7d 80 00 00 07 21 c0 50 00 00 08 0c 90 02 04 02 06 80 12 40 00 80 03 0a 1a 21 30 00 00 20 28 58 c0 d0
+40 00 00 00 00 89 04 17 d0 00 00 00 00 40 0a 00 00 00 90 03 80 00 28 14 03 4a 18 00 00 00 91 0f 00 49 90 04 00 44 03 83 04 04
+00 00 18 00 81 e1 e1 40 00 60 02 00 2e d5 60 01 80 07 00 10 01 00 00 03 96 cf 50 01 83 8d 80 12 21 30 0a 40 00 38 e8 96 80
+00 00 00 00 0f 19 08 14 00 00 00 1c 02 cf 20 00 00 00 08 03 00 00 00 00 41 d0 50 00 00 00 50 0b 00 49 00 a2 00 00 00 09 60 04
+00 00 30 00 00 09 62 80 08 c8 00 02 21 c0 12 20 08 01 80 f0 00 00 02 06 20 c5 00 01 28 00 1c 12 21 30 00 80 00 01 e8 96 80
+00 00 03 00 00 00 d4 28 40 04 00 00 00 40 02 00 01 20 08 0f 80 40 00 1c 41 50 a0 00 30 00 00 0f 80 49 40 04 00 00 00 09 60 10
+00 02 02 80 80 ad ba 04 00 00 00 60 2e a2 e0 00 00 09 80 30 00 00 60 e0 77 cf 50 00 00 11 81 1a 21 30 01 06 00 00 e8 96 80
+00 00 00 10 0f 00 9a 30 80 00 00 3c 03 d9 bd 00 00 00 98 0b 80 40 00 82 3e 50 50 00 01 06 08 9b 00 49 00 10 e0 00 02 09 60 10
+00 00 00 00 00 1d e4 00 00 02 20 00 7d a1 04 20 00 05 9b 18 00 00 00 06 a0 85 00 00 00 00 4c 5a 21 38 00 40 00 00 e8 96 80
+00 00 20 00 00 0d 96 c1 00 40 00 1c 21 40 30 40 00 28 00 af 02 00 00 00 39 50 a0 00 00 10 01 0f 80 49 00 08 c0 00 00 09 60 00
+00 00 00 00 00 03 a7 44 00 00 02 c3 2e d0 40 00 00 00 18 d0 00 00 00 00 05 a0 50 00 00 00 00 5a 21 30 00 00 16 05 c8 96 80
+00 00 00 03 80 08 1e 74 80 10 00 2c 42 cf 00 00 00 00 51 0f 02 00 00 1c 38 00 05 00 00 00 70 0b 00 49 00 00 01 c3 c2 09 60 00
+00 00 00 00 19 81 06 04 00 00 02 40 1f d8 00 00 00 07 89 38 10 00 00 00 74 ef 50 00 00 00 0c 7a 21 38 00 00 2e 69 c8 96 80
+00 00 00 00 00 00 93 79 c0 00 00 04 00 fc 00 00 00 18 09 c7 80 00 00 3c 35 50 a0 00 00 00 01 0f 80 49 00 00 01 c0 00 09 60 08
+00 00 30 00 10 ef b1 1c 0c c0 01 c0 3d 84 00 23 00 07 1b d8 00 14 e0 00 37 cf 50 03 00 00 00 72 21 10 0c 00 44 21 e8 96 80
+00 00 03 00 00 80 9c 01 40 0c 00 00 38 c0 d0 20 f0 00 08 a5 02 01 a0 00 03 40 50 00 10 00 00 f1 80 85 00 c0 08 e0 02 09 60 80
+00 00 00 00 81 87 f3 d5 00 02 02 02 0f ea 44 00 00 20 00 00 00 02 01 42 e4 98 00 00 00 08 00 f3 bd 40 00 00 be 01 e8 96 00
+00 00 00 00 01 08 9c 28 10 00 40 2c 2b 6f 80 40 00 44 00 00 00 00 00 36 61 5b 00 00 00 00 90 c9 41 40 00 00 02 60 02 09 60 50
+00 00 18 00 80 01 7a 81 00 60 01 e0 2c fa 14 00 00 00 00 00 00 00 00 07 a4 88 00 20 30 08 00 1e b4 40 80 0c 20 39 7c f5 00
+00 00 00 00 01 00 d0 3d 50 00 00 24 2e da 02 40 00 00 00 00 00 00 00 34 03 50 00 10 03 00 d0 c0 03 44 04 00 03 40 3f 05 00 80
+00 00 30 00 00 07 b3 d5 00 42 00 02 af ea 44 00 00 20 00 00 00 04 c3 e0 16 aa 00 00 00 00 00 7a 94 00 00 40 20 00 6c a0 00
+00 00 03 00 00 09 90 28 10 04 00 00 6d 7f 80 40 00 15 00 00 00 00 a0 0e 2c 10 a0 00 00 00 00 90 c1 40 02 02 06 c0 07 0f a0 00
+00 02 00 00 80 03 22 95 00 00 01 42 a6 e8 54 00 10 00 00 00 00 00 01 42 a1 ea 00 00 00 01 80 00 49 00 00 a0 00 6b ec 00 00
+00 00 00 00 09 00 bc 15 50 00 00 36 42 fc 40 40 00 80 00 00 00 00 00 36 6e 40 50 00 00 00 90 03 3c 60 00 04 03 c4 14 82 00 00
+00 00 00 00 19 b7 23 d5 00 00 00 40 2e ea 44 00 00 00 00 00 00 00 01 c0 0c aa 50 00 00 27 80 32 bd 40 00 04 20 6a eb e2 00
+00 00 20 00 00 08 9c 28 10 00 00 1e 03 7f 80 40 09 00 00 00 00 00 00 02 00 40 aa 01 00 00 00 01 42 80 00 00 00 c0 1e 88 12 00
+00 00 00 00 99 81 ba 81 00 00 00 06 24 e8 54 00 00 00 00 00 00 00 00 40 21 ea 00 00 00 07 00 97 34 40 80 00 00 38 00 00 00
+00 00 00 00 03 00 d0 3d 50 00 00 2c 32 db 40 40 00 00 00 00 00 00 00 02 02 50 50 00 00 00 58 af 81 40 00 00 00 06 00 00 00 00
+00 00 00 00 d8 97 73 d5 02 00 00 07 6e 8a 44 00 10 00 00 00 00 00 00 00 07 ca 00 00 00 00 00 3e bd 40 00 00 00 04 00 00 00
+00 00 00 00 05 1a 90 28 10 00 00 00 76 ff 80 40 00 85 00 00 00 00 00 00 00 20 a0 00 00 00 10 91 02 80 00 00 80 02 00 00 00 00
+00 00 30 00 d8 18 22 81 00 40 00 00 25 c0 50 00 00 00 00 00 00 00 01 42 86 aa 00 04 00 00 00 97 34 40 c0 00 04 04 00 00 00
+00 00 01 00 05 0a 54 14 10 04 00 1c 38 60 5a 00 00 00 00 00 00 00 00 00 01 40 f5 01 00 00 00 ff c1 40 00 00 00 03 40 00 00 00
+00 00 00 00 00 10 2a bd 02 00 20 43 85 dc 10 00 00 00 00 00 00 00 02 02 be 8b 7c 00 00 00 00 d3 28 10 00 0e 84 78 5e 83 40
+00 00 00 00 00 0f d0 17 d0 00 00 02 02 ed c7 00 00 00 00 00 00 00 00 04 22 68 12 42 00 00 00 03 03 d5 00 00 62 67 a4 ce 34 10
+00 00 18 00 d0 03 2c 08 00 00 00 00 20 ca 30 28 10 00 00 00 00 60 01 40 3c 99 5c 01 80 00 00 3a a8 10 02 00 00 00 6f f1 40
+00 00 00 00 0d 80 f6 06 40 00 00 00 26 c0 53 00 02 80 00 00 00 00 00 1c 28 4f 56 48 00 00 70 03 43 e9 00 a0 00 03 c6 e7 05 10
+00 00 18 00 81 e1 bb d4 00 00 00 00 1d ef 50 00 00 00 00 00 00 40 08 06 3e 9b 7c 00 00 48 18 53 28 04 00 00 0e 39 cc f5 40
+00 00 01 00 01 1b 34 01 40 00 00 00 02 e0 a0 00 00 00 00 00 00 04 01 40 03 e8 12 48 00 00 14 00 02 80 01 00 08 00 37 05 04 90
+00 02 00 00 00 03 04 00 00 00 00 00 1e c0 50 00 00 00 00 00 00 00 00 60 14 99 5c 00 10 09 98 ba bd 50 00 00 26 65 dc a5 40
+00 00 00 00 00 00 f2 10 80 00 00 00 00 00 05 00 00 00 00 00 00 00 00 00 02 6f 56 48 00 80 10 05 41 41 00 00 02 c3 46 05 54 00
+00 00 00 00 00 01 ba 80 00 0a 00 07 a0 e0 50 00 00 00 00 00 00 00 00 00 1e 8b 7c 10 00 09 80 fe bd 50 40 00 20 21 da f5 40
+80 00 20 80 09 09 04 28 00 02 00 34 6c c0 0a 00 00 00 00 00 00 02 00 1c 26 ec 12 40 08 00 30 05 01 41 00 00 00 40 3e 05 04 10
+00 00 00 00 80 00 30 14 00 00 e1 42 00 c0 50 00 10 00 00 00 00 04 01 46 76 99 5c 00 00 08 00 be bd 50 40 00 00 69 7c a5 40
+00 00 00 00 01 00 f0 02 82 00 00 26 78 40 0a 00 02 80 00 00 00 00 a0 14 20 cf 56 48 00 00 70 0f 01 41 00 00 01 c0 1c 05 54 00
+00 00 00 00 00 11 b8 7c 00 0a 00 00 1c c5 00 00 00 00 00 00 00 00 00 62 9e 9b 7c 00 00 00 00 ff bd 50 40 00 06 63 da f5 40
+40 00 00 00 00 0f d7 46 80 00 00 34 28 10 50 00 00 00 00 00 00 00 00 00 03 ed 12 40 40 00 00 0d 41 41 00 00 2b c3 57 05 04 00
+00 00 30 00 10 03 e2 04 08 00 03 e0 06 c0 50 00 10 00 00 00 00 c0 01 c2 ee 9b 74 01 00 08 01 b6 bd 50 4c 00 24 00 5b f1 40
+00 00 03 00 00 00 d0 38 80 00 00 3c 00 20 05 00 00 80 00 00 00 0c 00 00 3b cd 21 48 10 00 70 87 42 81 00 c0 03 c0 25 db 06 04
+00 00 c0 00 80 a7 65 d1 00 00 04 02 74 ca 00 00 00 80 00 00 00 00 00 00 5c 88 4c 00 00 0f 1a 56 bc 00 00 00 26 63 ca f4 40
+00 00 20 00 0f 0e 1f d4 14 30 00 04 68 e0 fa 08 00 00 00 00 00 00 00 00 3f c0 12 42 00 00 58 0d 82 94 00 00 02 c0 24 fd 04 04
+00 00 18 00 00 a3 6b 00 00 00 00 00 1c 8a 50 00 00 00 00 00 00 60 02 00 04 88 4e 00 28 08 00 1a a1 c0 8a 00 06 71 ca c3 61
+08 00 04 00 03 10 9f bf 00 00 40 00 27 d0 aa 00 80 00 00 00 00 00 00 1c 02 e0 12 40 11 00 70 00 02 1c 00 20 00 03 9e 8d 14 00
+00 00 10 00 51 c7 71 1d 0c 00 00 00 75 ca 00 00 03 80 00 00 00 c0 00 06 54 88 4c 08 00 25 0b 12 a1 c0 80 00 3c 01 ce c3 60
+00 00 01 01 00 1a 1c 10 98 20 00 00 2a f0 fa 08 00 18 00 00 00 04 00 00 23 e0 12 40 00 04 50 b0 02 1c 04 00 00 43 fd de 24 04
+00 01 00 00 18 a3 2a 80 00 00 00 00 2c 8a 50 00 00 00 00 00 00 00 08 66 54 88 4c 00 00 00 01 3a a8 00 00 80 00 01 ce e5 60
+00 00 00 00 00 00 7b 39 c0 00 00 00 00 f0 55 08 00 00 00 00 00 00 00 40 22 e0 12 40 00 00 d0 a0 02 80 00 14 00 00 26 e5 84 00
+00 00 00 00 30 15 3b 14 08 00 11 e6 9e 8f 50 00 00 20 00 00 00 00 00 03 de 88 4c 00 00 40 00 82 a8 00 00 24 0e 04 6b 83 40
+08 00 00 80 00 08 d8 32 40 02 00 80 26 50 a0 00 88 00 00 00 00 02 00 00 3b c0 12 40 4a 00 00 03 01 40 00 00 02 e2 1f cd 34 00
+00 00 00 00 00 e1 7b 89 4d 00 e1 66 86 8a 50 00 00 00 00 00 00 00 00 00 16 88 4c 00 00 00 00 3a a8 00 00 00 20 01 dd c3 41
+00 00 00 00 09 00 f4 20 52 30 00 24 26 f0 55 08 00 00 00 00 00 00 00 00 02 c0 12 40 00 00 f0 00 42 80 00 00 00 43 1f 8d 14 10
+00 00 00 00 80 07 3b d4 00 00 63 60 15 ef a0 00 00 20 00 00 20 00 02 03 96 88 4c 00 2b 03 c0 5a 7d c0 00 02 3e 73 ec a5 40
+08 00 00 00 01 09 b4 3f c0 00 00 14 24 30 fa 00 00 01 00 00 00 00 00 04 03 e0 12 40 00 00 08 01 ff fc 00 08 01 c6 26 05 54 00
+00 00 10 00 00 ed f1 41 08 00 02 00 44 8a 50 00 00 00 00 00 00 40 02 00 16 88 44 00 08 00 0e 3b a8 00 0c 00 1e 7e 5e a5 40
+00 00 01 00 87 00 70 04 10 20 00 14 25 d0 55 08 00 08 00 00 00 04 00 04 02 e0 12 49 40 00 01 00 02 80 00 c0 e0 26 3d 05 56 80
+00 00 00 00 d1 d1 21 55 02 00 00 00 2e ab 04 00 00 00 00 00 00 00 01 42 16 af 50 00 20 4f 80 13 e4 40 10 04 1c 00 d9 d5 00
+00 00 00 00 01 88 14 16 90 00 00 00 02 6e f1 40 00 00 00 00 00 80 20 02 6c 10 f5 00 00 02 f0 e7 63 8c 00 00 02 62 34 8d 00 00
+00 00 18 00 d0 17 73 d4 00 60 00 00 1d 8a 14 01 80 00 00 00 00 00 e1 42 a6 af 50 00 00 00 00 b3 7f 00 00 a0 3c 25 fc c1 02
+00 00 00 00 01 09 54 3f c0 00 00 00 30 da 5b 40 00 00 00 00 00 80 00 36 6c 70 ff 00 00 00 f0 03 6d e0 00 04 01 c7 8f 0e 60 00
+00 00 00 00 01 89 21 c0 08 00 03 e0 74 cf 70 00 00 00 00 00 00 00 00 02 d6 a5 f0 00 00 00 1c 36 a1 c0 80 00 06 28 da 91 00
+00 00 00 00 05 0a 14 14 00 00 00 06 20 ca ff 00 00 00 00 00 00 80 04 34 78 10 5f 00 02 05 70 00 82 1c 00 00 00 00 2c 9d 30 00
+00 02 00 00 18 00 2b 4d 08 00 00 00 2e ca 50 00 00 00 00 00 00 00 01 40 4e cf 50 20 03 a0 00 3a 21 c0 80 00 1d 29 40 e7 02
+00 00 00 00 00 00 94 38 d0 40 00 00 2f 4c f7 08 00 40 00 00 00 80 00 14 26 60 81 00 00 00 70 e0 c2 1c 00 00 01 74 04 08 10 00
+00 00 00 00 00 05 61 54 00 02 02 60 74 cf 52 00 00 00 00 00 08 00 02 63 2d af f2 20 00 00 1e 02 a1 c0 80 00 3c 3a f8 42 02
+00 00 20 00 00 00 08 15 40 00 40 04 38 c0 ff 08 00 00 00 00 00 00 00 04 41 70 fb 01 00 18 30 81 01 2c 00 00 a2 c2 a7 0d 10 10
+00 00 00 80 80 05 a3 c1 02 0a 00 03 54 c2 00 20 00 00 00 00 00 00 00 00 06 ef 70 00 00 47 00 02 a8 00 00 00 40 3e 1b c5 00
+00 00 00 10 05 0a 94 3d 50 00 40 24 70 10 20 08 00 00 00 00 00 40 00 00 24 4a ff 00 00 02 08 95 41 40 20 00 c0 07 94 9c a0 10
+00 00 00 00 50 0d 62 80 00 00 01 c0 75 a2 50 20 00 00 00 00 00 00 08 40 06 cf 70 20 01 21 01 00 00 00 01 00 00 38 dd 47 00
+00 00 00 00 00 00 b8 00 00 00 00 02 24 f0 2a 00 00 00 00 00 00 40 01 42 02 60 ff 10 00 04 08 b0 00 00 00 10 00 04 0f b4 20 10
+00 00 30 00 10 03 e3 88 08 c0 00 46 9f c5 b0 23 40 07 00 00 08 00 20 00 00 00 00 00 00 00 00 00 00 00 00 00 40 20 4f 74 00
+00 00 03 00 00 80 54 14 00 0c 00 02 43 f0 02 00 b4 00 08 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 04 2d da 00 10
+00 00 00 00 18 0d 2c 41 00 00 00 63 8d ca 00 00 00 00 00 00 00 00 01 43 1c 98 4c 02 00 00 0c 7a 3e 80 00 40 04 70 4e 85 00
+00 00 00 00 00 00 97 49 10 00 00 00 01 50 00 00 00 00 00 00 00 80 00 02 01 4b 12 42 00 00 00 00 c3 e8 40 0a 00 00 2c be a0 00
+00 00 18 00 00 15 f3 bc 00 60 03 40 07 a4 74 30 00 00 00 00 00 60 00 60 1e 88 4c 00 80 00 00 f7 be c0 80 00 20 06 6c c5 02
+00 00 00 00 00 0b d6 bf c0 00 00 04 00 40 81 68 80 00 00 00 00 40 00 00 00 4c 12 40 28 00 00 07 43 fc 20 00 00 c2 de 0c 60 00
+00 00 34 00 80 0f 29 f1 08 c4 00 e6 a4 c1 00 00 00 00 00 00 00 c0 01 43 54 98 4c 00 00 01 00 fb 3f c0 02 00 00 22 1c e2 02
+00 00 03 40 0d 0e 90 0f 10 04 20 02 02 ea 26 00 00 20 00 00 00 44 00 02 21 6e 12 40 00 00 08 0f 03 d4 20 00 00 00 0d 0d 10 00
+00 02 00 00 18 05 f3 fc 00 00 00 60 54 e5 b4 20 40 00 00 00 00 00 00 07 de 88 4c 00 00 00 01 87 bd 44 00 00 1e 05 6e 03 02
+40 00 00 00 00 00 56 fd c0 00 00 00 20 20 5b 40 44 00 00 00 00 80 00 00 20 4d 12 40 00 00 00 87 43 e8 00 00 00 03 ec 05 30 00
+00 00 00 00 10 01 01 f9 08 00 01 c0 21 ef a0 00 00 00 00 00 00 00 00 66 1e 9b 7c 00 40 03 80 da 00 00 20 01 40 3b cc a0 00
+00 00 20 00 00 00 00 1f 90 00 00 02 3a d0 f5 00 00 00 00 00 00 40 00 80 3b 4e de c0 04 00 08 0f c1 40 00 00 03 46 e7 0f a0 00
+00 00 00 00 80 10 3b e8 00 00 00 c6 40 af 70 00 00 00 00 00 00 04 02 06 1e 98 4c 00 28 50 00 00 3c 10 00 00 04 72 cd d5 00
+00 00 00 00 03 0a 30 3d 40 00 00 00 20 c9 fb 00 00 04 00 00 00 40 00 0c 00 48 12 40 01 00 10 e0 03 c3 80 00 03 44 0d bd 00 00
+00 00 00 00 d8 ed 2b dc 48 04 00 63 97 c5 05 28 00 00 00 00 00 00 02 00 16 98 4c 00 00 03 80 7f bd 48 00 21 14 02 4e c5 02
+00 00 00 00 07 40 b4 3f c2 00 20 00 01 e0 b8 48 00 00 00 00 00 40 00 04 01 6e 12 40 00 00 08 07 83 fc 80 00 03 63 9e 0c 90 00
+00 00 30 00 00 07 70 01 00 c0 00 e0 0e fa 50 00 00 00 00 00 00 c0 02 40 1e 9b 7c 03 00 08 1f 3f be c0 80 00 7e 00 7c c5 02
+00 00 01 00 00 00 56 c2 10 0c 00 00 3e 78 8b 00 00 00 00 00 00 44 00 06 02 4d de c0 10 00 f0 e9 c3 fc 20 00 01 40 00 0c 50 00
+40 70 00 00 81 87 f3 d5 00 00 00 e6 00 0a 54 00 00 09 0e 80 00 00 02 00 0e 8b 74 04 00 0b 00 00 19 9c 10 00 00 22 6a f5 40
+00 04 20 00 01 00 7c 28 10 00 00 00 3a c0 5a c0 00 00 f9 05 00 00 00 04 02 c8 de c4 00 00 18 0b 22 65 01 00 43 c3 ee 05 04 80
+00 00 18 00 80 09 3a 95 00 60 02 60 0c c0 00 11 80 00 00 00 00 60 00 00 00 c0 f0 01 80 08 00 77 00 54 12 00 00 3b 6e f5 40
+08 00 00 00 01 00 d0 15 50 00 00 3c 29 60 50 01 00 00 00 01 00 00 00 00 00 10 0f 00 00 00 30 0f b7 89 44 a0 00 03 9e 05 04 80
+6c 00 30 00 00 05 33 d5 00 00 03 e0 00 8f 04 00 00 00 00 80 00 c0 00 00 00 00 00 01 00 00 0f 33 82 9c 00 00 7e 62 6e f5 40
+03 80 03 00 05 0a 78 28 10 00 00 06 00 10 f0 c0 00 00 00 0f 00 0c 00 00 00 00 00 00 30 80 01 db c2 95 81 00 00 40 27 05 06 00
+00 03 00 00 00 bb 3a 95 00 00 00 07 c0 8f 04 00 04 0f 81 00 00 02 00 00 00 00 00 00 03 83 80 13 28 00 00 00 20 3a 4a f5 40
+00 00 00 00 05 0d 58 15 50 00 00 00 70 10 f0 c0 00 00 f8 f9 00 00 40 00 00 00 00 00 00 00 08 00 42 80 00 00 04 40 1d 05 04 08
+00 00 00 38 19 b7 a3 d5 00 00 12 00 47 f5 02 00 00 00 00 00 00 0a 00 00 40 00 00 00 40 05 8f b3 89 98 d0 0c 00 00 5a f5 40
+00 00 20 00 00 18 74 28 10 00 00 9c 21 5b b8 00 00 00 00 01 00 00 40 00 3c 00 00 00 04 00 00 83 c2 25 20 08 00 00 06 0a 04 80
+40 00 00 00 19 81 b8 15 00 00 00 00 27 8a f0 00 00 00 00 80 00 02 08 c0 00 00 00 00 00 0f 00 13 35 40 00 00 a6 02 4e a0 50
+00 80 00 00 00 00 00 01 50 00 00 00 03 50 ff 08 00 00 90 05 00 00 01 44 00 00 00 00 00 00 18 07 63 40 00 00 05 c3 cd 0f a4 08
+00 28 00 00 50 85 73 d5 00 00 22 00 00 e7 00 20 00 00 00 80 00 00 00 07 00 00 00 00 00 08 19 37 30 40 81 40 06 77 6e f5 00
+08 06 c0 12 00 10 70 28 18 00 00 1c 01 40 b0 08 00 00 00 07 00 00 00 00 00 00 00 00 00 00 50 e1 03 98 00 00 02 46 3c 0a 00 00
+40 00 30 00 10 15 ba 95 00 c0 00 40 66 c0 00 03 00 03 0c 80 00 c4 00 00 00 00 00 01 39 00 00 3e 09 40 8c 00 04 70 5c e2 02
+00 00 03 00 03 0b b8 2a 90 0c 00 00 33 48 10 20 10 00 09 0d 00 04 20 00 00 00 00 00 30 28 00 0d 03 ec 20 c8 84 c0 02 0e 20 08
+00 00
+11 01
+01 01
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 40 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 48 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 04 00 00 00 00 00 00 10 00 00 00 00 00 01 40 00 00 00 00 10 00 00 00 00 00 00 40 00 00 00 00 0d 11 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 00 00 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 00 00
+00 00 00 00 00 04 00 00 00 00 00 00 10 00 00 00 00 00 00 00 00 00 00 80 30 00 00 00 00 00 00 40 80 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 05 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 30 00 00 00 00 00 00 00 00 00 00 00 00 00 80 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 04 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 02 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 10 00 00 8f c1 41 00 c0 00 02 3f 05 04 00 00 00 00 00 00 40 00 02 3f 05 04 03 00 00 08 fc 14 10 04 00 00 23 f0 50 40
+00 00 03 00 01 81 f6 bd 50 0c 00 04 06 da f5 40 00 00 00 00 00 04 00 00 06 da f5 40 30 00 10 1b 6b d5 00 c0 00 07 ff af 54 00
+00 00 00 00 01 8f c3 d5 00 00 00 02 15 d7 24 00 00 00 00 00 00 00 00 02 15 d7 24 00 00 00 08 07 6c 50 00 00 00 21 70 50 40
+00 00 00 00 01 8f 7a a8 10 00 00 06 06 1e b1 40 02 00 00 00 00 00 00 06 06 1e b1 40 00 00 18 13 fa c5 00 00 00 60 6f ef 54 00
+00 00 00 00 10 0b 43 d5 00 00 00 00 16 05 04 00 00 00 00 00 00 00 00 00 16 05 04 00 00 00 00 5b 10 90 00 00 04 01 60 50 40
+00 00 00 00 00 00 7e 28 10 00 00 00 02 da f5 40 00 00 04 00 00 00 00 00 02 da f5 40 00 00 19 ab 07 9d 00 00 00 07 bf af 54 00
+00 02 00 00 01 0f 43 d5 00 00 00 02 b4 d7 24 00 00 00 00 00 00 00 00 02 f4 d7 24 00 00 00 0f d3 5c 90 00 00 00 03 60 50 40
+00 00 00 00 00 0e 5b a8 10 00 00 00 00 1a b1 40 00 00 00 00 00 00 00 00 00 1a b1 40 00 00 00 00 6a c5 00 00 00 00 0f af 54 00
+00 00 00 00 10 0b 83 d5 00 00 00 40 3f 05 04 00 28 00 00 00 00 00 00 40 3f 05 04 00 00 01 00 fc 14 10 00 00 04 03 f0 50 40
+00 00 20 00 0d 18 57 a8 10 00 00 26 60 ca f5 40 01 00 00 00 00 00 00 26 60 ca f5 40 00 00 81 83 2b d5 00 00 02 66 1e af 54 00
+00 00 00 00 10 a7 c1 41 00 00 00 40 1d d7 24 00 00 00 00 00 00 00 00 40 1d d7 24 00 00 01 00 77 5c 90 00 00 04 01 f0 50 40
+00 00 00 00 08 18 33 bd 50 00 00 20 60 0e b1 40 00 00 00 00 00 00 00 20 60 0e b1 40 00 00 81 80 3a c5 00 00 02 06 0e ef 54 00
+00 00 00 00 00 ab 03 d5 00 00 00 00 16 05 04 00 00 00 00 00 00 00 01 c4 16 05 04 00 00 00 00 58 14 10 00 00 00 01 60 50 40
+00 00 01 80 00 00 76 a8 10 06 00 00 68 ce f5 40 00 00 00 00 00 06 00 00 60 ce f5 40 1a 80 00 03 3b d5 00 60 00 02 9e ef 54 00
+00 00 00 00 00 0d 81 41 00 00 00 00 2d 0f 54 00 00 10 00 00 00 00 00 00 2d 0f 54 00 00 00 00 b4 3d 50 00 00 00 03 d0 f5 40
+00 00 00 00 00 00 32 bd 50 00 00 00 01 58 a0 40 00 00 00 00 00 00 00 00 01 58 a0 40 00 00 00 05 72 81 00 00 00 00 35 8a 04 00
+00 00 30 00 00 85 c1 41 00 40 00 02 3d 05 04 00 00 00 00 00 00 c0 00 02 3d 05 04 01 00 0f 08 f4 14 10 04 00 00 23 d0 50 40
+00 00 01 00 00 01 b6 bd 50 04 00 00 06 fa f5 40 00 38 00 00 00 0c 00 0e 07 5a f5 40 30 00 00 19 eb d5 00 40 00 40 7f af 54 00
+00 00 00 00 00 87 75 c9 00 00 00 02 15 c7 24 00 00 00 00 00 00 10 00 02 15 a7 24 00 00 00 08 54 14 10 00 00 00 21 50 50 40
+00 00 00 00 01 81 07 ac 50 00 00 06 06 1f b1 40 00 00 00 00 00 01 00 06 06 1e b1 40 00 00 18 1f fb d5 00 00 00 60 6d ef 54 00
+00 00 00 00 00 03 c3 e9 00 00 02 40 14 05 04 00 00 00 00 00 00 00 00 00 14 05 04 00 00 03 00 50 14 10 00 00 00 01 40 50 40
+00 00 00 00 01 80 b6 a8 10 00 00 00 02 fa f5 40 00 00 00 00 00 00 00 00 03 5a f5 40 00 00 80 09 eb d5 00 00 00 00 3f af 54 00
+00 02 00 00 00 e1 35 c9 00 00 00 00 34 c7 24 00 00 00 00 00 00 00 00 00 34 a7 24 00 00 00 00 d0 14 10 00 00 02 03 40 50 40
+00 00 00 00 00 01 06 ac 50 00 00 00 00 1b b1 40 00 00 00 00 00 00 00 00 00 1a b1 40 00 00 00 07 eb d5 00 00 01 e0 0d af 54 00
+00 00 00 00 18 e9 83 e9 00 00 00 40 3d 05 04 00 00 00 00 00 00 00 00 40 3d 05 04 00 00 01 00 f4 14 10 00 00 04 03 d0 50 40
+00 00 20 00 09 18 36 28 10 00 00 26 60 ea f5 40 00 00 00 00 00 00 00 26 61 4a f5 40 00 00 99 81 ab d5 00 00 02 66 1e af 54 00
+00 00 00 00 10 00 f6 c5 00 00 00 40 1d c7 24 00 00 00 00 00 00 00 00 60 1d a7 24 00 00 01 00 74 14 10 00 0a 04 01 d0 50 40
+00 00 00 00 08 00 13 ac 50 00 00 20 60 0f b1 40 04 10 00 00 00 00 00 3e 60 0e b1 40 00 00 81 87 bb d5 00 00 02 06 0c ef 54 00
+00 00 00 00 d0 05 81 41 00 00 02 44 14 05 04 00 00 00 00 00 00 00 00 04 14 05 04 00 00 0d 10 50 14 10 00 00 24 01 40 50 40
+00 00 01 80 00 00 33 bd 50 06 00 00 28 ee f5 40 00 00 00 00 00 06 00 00 29 4e f5 40 18 00 80 a1 bb d5 00 60 00 02 9e ef 54 00
+00 00 00 00 d0 0b 43 d5 00 00 00 00 0d 0f 54 00 04 00 00 00 00 00 00 00 15 0f 54 00 00 00 00 14 3d 50 00 00 00 01 d0 f5 40
+00 00 00 00 00 18 56 a8 10 00 00 00 03 58 a0 40 02 80 00 00 00 00 00 00 01 58 a0 40 00 00 00 0d 62 81 00 00 00 00 35 8a 04 00
+00 00 10 00 01 8f c1 41 00 c0 00 26 3f 05 04 00 00 00 00 00 00 c0 00 12 3d 05 04 03 00 00 88 fc 14 18 0c 00 00 23 f0 50 40
+00 00 03 00 00 0f fe bd 50 0c 00 04 27 fa f5 40 00 00 00 00 00 0c 00 1c 06 7a f5 40 30 00 10 1b eb d5 00 c0 01 c0 65 af 54 00
+00 00 00 00 00 85 7d c9 00 00 00 02 15 f7 24 00 00 00 00 00 00 00 00 02 15 87 24 00 00 00 08 54 14 10 00 00 00 21 59 72 40
+00 00 00 00 01 81 87 ec 50 00 00 06 06 1f b1 40 00 00 00 00 00 00 00 06 06 1f b1 40 00 00 18 1b 7b d5 00 00 00 60 61 eb 14 00
+00 00 00 00 98 05 81 41 00 00 00 00 16 05 04 00 00 00 00 00 00 00 00 00 14 05 04 00 00 00 0f 58 14 10 00 00 00 01 60 50 40
+00 00 00 00 05 80 fe bd 50 00 00 00 03 fa f5 40 00 38 00 00 00 00 00 00 02 7a f5 40 00 00 00 0b eb d5 00 00 00 00 25 af 54 00
+00 02 00 00 00 0d 3d c9 00 00 00 00 34 f7 24 00 20 00 00 00 00 00 00 00 34 87 24 00 00 00 80 d0 14 10 00 00 00 03 49 72 40
+00 00 00 00 00 00 06 ec 50 00 00 00 00 1b b1 40 00 00 00 00 00 00 00 00 00 1b b1 40 00 00 70 03 6b d5 00 00 00 00 01 ab 14 00
+00 00 00 00 10 0f c1 41 00 00 00 40 3f 05 04 00 00 00 00 00 00 00 00 40 3d 05 04 00 00 01 00 fc 14 10 00 00 04 03 f0 50 40
+00 00 20 00 09 98 7a bd 50 00 00 26 61 ea f5 40 00 00 00 00 00 00 00 26 60 6a f5 40 00 00 99 83 ab d5 00 00 02 66 04 af 54 00
+00 00 00 00 10 07 7d c9 00 00 00 40 1d f7 24 00 00 00 00 00 00 00 00 40 1d 87 24 00 00 01 00 74 14 10 00 00 04 01 d9 72 40
+00 00 00 00 08 18 03 ec 50 00 00 20 60 0f b1 40 00 00 00 00 00 00 0c 20 60 0f b1 40 00 00 81 83 3b d5 00 00 02 06 00 eb 14 00
+00 00 00 00 00 05 81 41 00 00 00 04 16 05 04 00 00 00 00 00 00 00 01 c4 14 05 04 00 00 00 00 58 14 10 00 00 00 01 60 50 40
+00 00 01 80 00 00 7b bd 50 06 00 00 29 ee f5 40 00 00 00 00 00 06 00 20 28 6e f5 40 18 00 01 a3 bb d5 00 60 00 02 84 ef 54 00
+00 00 00 00 00 0f 03 d5 00 00 00 00 3d 0f 54 00 00 00 00 00 00 00 00 10 05 0f 54 00 00 00 00 b8 28 10 00 00 00 22 50 f5 40
+00 00 00 00 00 00 d7 28 10 00 00 00 03 58 a0 40 00 10 00 00 00 00 00 00 03 58 a0 40 00 00 00 09 ab d5 00 00 00 00 15 8a 04 00
+00 00 30 00 50 8b 83 e9 00 c0 02 42 3d e7 24 00 00 00 00 00 00 44 00 43 3e 01 24 01 00 00 08 b8 3d 50 04 00 00 23 70 50 40
+00 00 01 00 08 01 9e 28 10 44 00 06 06 1b b1 40 00 00 00 00 00 04 80 20 03 68 84 40 30 00 00 15 e2 81 00 c0 00 00 2f af 54 00
+00 00 00 00 00 89 83 d5 00 00 00 02 05 05 04 00 00 00 00 00 00 00 00 40 2e 01 24 00 00 00 18 5c 14 10 00 00 00 21 5d 72 40
+00 00 00 00 01 9b ff a8 14 00 00 06 67 fe f5 40 00 00 00 00 00 00 00 26 03 68 84 c0 00 00 18 fb 7b d5 20 00 00 00 61 bb 14 00
+00 00 00 00 00 03 c3 e9 00 00 00 00 1d 0f 54 00 00 00 00 00 00 00 08 03 3c 01 24 00 00 0f 00 58 14 10 00 00 1c 39 60 50 40
+00 00 00 00 01 98 9b a8 10 00 00 00 03 ea a0 40 00 03 00 00 00 00 01 40 03 68 84 c0 00 00 00 0f 6b d5 00 00 06 00 6f af 54 00
+00 02 09 00 00 00 26 c5 00 20 00 00 1c 05 04 00 00 00 00 00 00 20 00 00 2c 01 24 10 80 00 10 d8 14 10 02 00 00 00 2d b1 40
+00 00 00 28 00 00 3e ec 50 00 00 00 03 fa f5 40 02 80 00 00 00 00 00 40 03 e8 84 c0 00 00 00 e3 6b d5 00 00 00 00 05 bb 14 00
+12 00 00 00 10 0f c1 41 00 00 00 40 3d e7 24 00 01 80 00 00 00 00 1c 02 3e 01 24 80 01 01 00 fc 14 10 00 00 04 23 e9 42 40
+00 00 00 00 09 00 1a bd 50 00 00 6e 60 0f b1 40 00 00 00 00 00 00 00 06 67 48 84 c0 00 00 99 87 2b d5 00 00 02 66 4e 0e 74 00
+80 00 00 00 10 07 65 c9 00 00 a0 00 1d 05 04 00 20 40 00 00 00 40 00 02 2e 01 24 00 00 01 00 7c 14 10 00 04 04 42 d0 a0 40
+40 00 00 00 08 18 03 ec 50 00 00 00 69 ee f5 40 00 28 00 00 00 04 00 00 67 48 84 c8 00 00 81 83 3b d5 00 00 02 07 34 ef 54 00
+80 00 00 00 31 c5 81 41 00 00 61 44 00 eb 14 00 00 00 00 00 00 00 01 c0 3c 01 24 00 00 03 00 58 14 10 00 00 02 00 40 5a 40
+00 00 01 80 00 0b 1b bd 50 06 00 20 28 4f b1 40 00 00 00 00 00 06 00 20 03 c8 84 c0 18 00 00 07 3b d5 00 60 00 40 20 0a 54 00
+10 02 00 00 00 09 43 d5 00 00 00 40 05 0f a4 00 04 00 00 00 00 10 00 03 2c 01 24 20 00 00 00 d8 14 10 00 00 00 03 50 f5 40
+00 00 04 00 00 00 d6 28 10 00 00 20 01 f8 a0 40 00 00 00 00 00 00 00 00 07 c8 84 c0 00 00 00 0b 2b d5 00 00 00 66 05 ea 04 00
+00 00 10 00 10 0d 03 9d 00 c0 00 00 02 07 80 80 00 00 00 00 00 00 00 00 27 af 70 82 00 05 00 33 ff c0 48 00 00 25 58 ff 08
+00 00 03 00 09 80 97 bb d0 8c 00 04 01 78 78 02 00 00 00 00 00 00 00 00 03 c9 e7 00 30 00 80 03 eb dc 02 c0 00 00 77 cf 70 00
+00 00 00 00 00 01 82 84 00 00 00 42 2e 09 c0 00 10 00 00 00 00 0a 00 20 27 0f f0 80 88 01 88 58 3f c2 02 00 02 22 d0 55 c8
+00 00 00 00 00 00 5a a0 40 80 00 26 24 ea 93 02 80 00 00 00 00 00 40 16 68 7c f7 02 01 00 90 1f 7b d4 00 0a 00 46 6f ea 56 00
+00 00 00 00 10 85 80 3c 00 00 00 00 05 00 a0 00 00 00 00 00 00 00 00 22 81 0f 50 00 00 05 00 58 3e b0 00 00 00 20 ef 58 40
+00 00 00 00 00 01 b6 3c 00 00 00 00 72 4c a0 00 00 00 00 00 00 00 00 0e 6c 6e f5 00 00 00 80 09 ea 81 00 00 00 60 74 ee 54 00
+00 02 08 00 f0 db 40 3c 40 20 00 02 2c 0f 00 80 00 00 00 00 00 20 14 04 3e df f0 10 80 00 00 76 29 90 00 00 00 23 e0 fa c0
+00 00 00 00 09 00 12 bc 00 00 00 00 04 6a 0f 00 00 00 00 00 00 00 00 8e 71 5b f7 00 00 00 58 05 ea 95 00 00 00 00 5f aa 04 00
+00 00 00 00 50 e3 6c 75 02 00 00 04 01 0f 50 00 00 00 00 00 00 20 03 e4 03 0f 50 00 81 01 19 1c 3e b0 02 00 04 03 eb b5 40
+00 00 20 00 00 00 7f 46 90 00 00 00 70 4c f5 00 00 00 00 00 00 00 00 14 28 7a f5 00 00 00 99 91 aa 81 20 00 03 60 1c ea 14 00
+00 00 34 00 10 ab 78 31 00 00 00 c0 1d f7 24 80 00 00 00 00 00 00 00 23 95 00 10 08 00 09 00 94 3d 70 00 00 04 28 30 55 c0
+00 00 01 40 08 0e fe d7 90 00 00 20 00 0e b1 40 00 00 00 00 00 00 00 14 2e e8 00 22 00 38 81 8f 3a 81 00 00 02 62 9d e5 54 00
+00 00 00 00 70 0d 60 31 00 00 00 44 1e 05 04 00 00 00 00 00 00 00 03 c6 ec 80 00 02 00 00 0a 1a 9e 90 08 06 00 01 4f d8 d8
+00 00 01 80 00 00 ff 17 90 06 00 3c 29 ce f5 40 00 00 00 00 00 00 00 14 60 4a 80 00 28 00 00 05 ba 85 00 a0 01 40 00 be 44 00
+00 00 00 00 50 03 00 00 00 00 00 c0 3d 0f 54 00 00 00 00 00 00 00 03 42 74 ef f0 80 00 09 00 72 d9 50 00 00 00 01 cd 70 40
+00 00 00 00 05 00 13 28 00 00 00 20 01 d8 a0 40 00 00 00 00 00 00 00 1c 64 d8 f7 00 00 00 98 07 2e 95 00 00 00 60 06 af 14 00
+00 00 00 00 00 00 00 00 00 40 00 40 26 81 e0 00 00 00 00 00 00 40 00 02 c0 00 00 02 00 05 00 04 39 32 08 00 00 00 d0 0a 00
+04 00 00 00 05 80 00 00 00 0c 00 26 00 ff d2 00 00 00 00 00 00 04 00 00 04 00 00 00 30 00 80 01 6b 91 08 c0 00 00 00 80 50 00
+80 00 00 00 50 80 00 00 00 10 00 04 26 a8 54 00 00 00 00 00 00 00 00 40 00 00 00 00 00 55 0e b3 bf c4 00 00 00 02 40 fa 00
+00 00 00 00 0d 80 00 00 00 01 00 06 7b 7f 47 40 00 00 00 00 00 00 00 20 00 00 00 00 00 02 d8 11 3b dc 00 00 00 00 00 cf 50 00
+08 00 00 00 00 a9 b3 30 00 00 00 c2 2f 02 e4 00 28 00 00 00 00 00 00 02 fc 82 14 00 00 00 00 0c 28 02 00 00 00 00 0c c0 00
+04 40 00 00 00 01 52 0c c0 00 00 20 77 58 25 43 01 00 00 00 00 00 00 00 06 49 84 40 00 00 00 05 a2 80 00 00 00 00 00 cc 00 00
+00 36 00 00 00 00 ba 58 02 00 00 02 67 00 30 00 00 00 00 00 00 00 00 00 34 dd e4 10 00 00 0a d2 46 00 21 00 04 00 c0 fa 00
+00 00 00 00 05 80 12 25 a0 00 00 00 65 7c 43 02 00 30 00 00 00 00 00 06 03 69 b7 c0 00 00 00 08 00 90 00 10 02 60 00 cf 50 00
+00 00 00 00 01 00 3e 58 00 00 00 02 a5 0a a0 00 00 00 00 00 00 00 00 44 16 91 24 00 00 00 08 d4 14 30 20 00 00 00 0c fc 00
+00 00 10 00 00 0a 72 25 a0 00 00 14 01 cc 33 22 00 00 00 00 00 00 00 20 20 e8 84 c0 00 00 01 98 2a 81 00 00 00 00 00 cf c0 00
+00 00 00 00 00 b0 b6 58 00 c0 00 00 1d d0 f0 00 00 00 00 00 00 40 01 c2 06 d1 24 10 00 00 00 9c 14 30 0c 40 00 00 c0 f5 00
+00 00 00 00 00 0a 52 65 a0 0c 00 00 2a 69 87 00 00 00 00 00 00 04 00 00 05 49 84 c0 00 00 01 85 bb d5 01 4a 00 07 00 cf a0 00
+80 00 00 00 00 00 22 58 00 00 03 63 dd 0f a4 00 00 00 00 00 00 10 02 40 16 c1 24 02 00 00 00 12 df 90 08 00 00 00 d0 55 c0
+00 00 00 00 00 00 7a 25 a0 06 00 14 07 78 a0 40 00 00 00 00 00 06 00 06 00 e8 84 c1 28 00 00 00 06 f5 00 a0 00 00 00 8a a4 00
+80 02 00 00 08 00 2e 58 00 00 00 06 96 8f e4 10 04 00 00 00 00 00 41 c3 c4 01 24 24 00 01 08 17 56 10 00 00 00 2e 4c c3 c0
+00 00 00 00 05 0a 70 65 a0 00 00 00 2a df fc 40 00 00 00 00 00 02 00 00 65 c8 84 c0 00 00 98 17 bb 95 00 00 00 00 0c 09 94 00
+00 00 10 00 10 07 02 20 00 c0 00 20 36 89 30 00 00 00 00 00 00 c0 00 07 4d f8 50 03 00 0f 80 d6 79 40 0c 00 00 00 cc d0 00
+00 00 03 00 00 0a de 2e c0 cc 00 04 00 dc 6c 00 00 00 00 00 00 0c 00 1c 26 fd a5 01 30 00 90 01 66 f0 00 c0 01 c0 35 ad 50 00
+00 00 00 00 00 00 43 84 00 0a 02 c2 75 c0 f0 00 00 00 00 00 00 00 20 00 00 0f 04 00 00 00 80 5e 7f c0 40 00 06 21 4a 98 10
+00 00 00 00 00 0e 5a 38 40 c0 0c 20 05 d8 69 00 00 00 00 00 00 00 00 00 00 18 f0 41 00 00 10 09 af dc 00 00 02 e0 3d ae 50 00
+00 00 00 00 90 90 43 84 00 00 01 e0 36 0c c0 00 00 00 00 00 00 00 02 c2 00 0f 06 18 00 00 09 04 3c c0 00 00 1c 03 7c d3 60
+00 00 00 00 01 9a 52 38 40 80 00 0e 01 4a 33 03 00 00 00 00 00 00 00 3e 04 18 f0 60 80 00 00 00 63 cc 08 00 02 60 26 98 34 00
+00 02 00 00 00 00 40 3c 00 00 22 c2 4d 05 f0 00 00 00 00 00 00 00 00 40 01 0f 04 00 00 00 09 9e bf c0 00 a1 00 34 59 95 40
+00 00 00 00 00 18 03 03 c0 00 00 00 06 4e 50 00 00 00 00 00 00 00 00 26 00 08 f0 40 00 00 00 01 ef ec 00 00 e8 60 16 ba 54 10
+00 00 00 00 18 01 79 11 01 00 00 00 1d 00 f0 00 00 00 00 00 00 00 20 00 01 0f 04 00 00 01 1a 06 79 40 00 00 06 23 5f 70 40
+00 00 20 00 0d 00 9e 6e d8 20 00 00 00 ca f0 00 00 00 00 00 00 00 00 00 78 1e f0 40 00 00 f9 95 a7 94 00 00 02 e0 26 af 14 04
+00 00 30 00 08 01 c1 dc 00 00 00 02 f4 c6 f0 00 00 00 00 00 00 00 00 00 00 0f 04 01 00 50 0b d0 36 c8 00 00 02 24 7c 43 50
+00 00 03 00 05 18 b7 11 00 80 00 16 68 0e 9f 00 00 00 00 00 00 00 20 00 00 0c f0 48 30 02 01 8d fb dc 08 00 00 e6 1c 9e 34 80
+00 00 00 00 18 85 c1 68 00 00 00 04 01 00 f4 00 00 00 00 00 00 00 00 40 00 0f 04 00 28 00 19 d2 40 00 0a 00 1c 3b fb e5 40
+00 00 01 80 0d 01 ff 3c 00 06 00 00 28 0a 0f 41 00 00 00 00 00 06 00 26 00 0c f0 40 19 00 00 b5 bc 40 00 a0 02 00 0c 98 55 08
+04 00 00 00 01 bd 80 3c 01 00 00 20 00 0f 04 00 00 00 00 00 00 00 00 00 34 05 a4 00 00 05 0b b6 e8 10 00 00 0c 62 68 f0 60
+00 00 00 00 00 0a 17 3c 00 08 00 14 00 1c f0 40 00 00 00 00 00 00 40 00 62 00 a5 40 00 00 00 0f ea 01 24 00 e2 07 9c ed 14 00
+00 00 10 00 00 8f 41 41 00 c0 02 63 dd be 50 90 00 00 00 00 00 c0 01 c0 1f 0a 04 00 0b 10 8b 30 36 40 28 00 80 22 c9 d1 00
+04 00 01 00 00 01 b6 bd 50 24 00 1c 03 cb a5 00 40 00 00 00 00 04 00 20 60 7e 05 60 01 02 10 01 33 04 08 c0 04 07 45 ba 10 00
+80 00 00 00 50 85 71 c9 00 10 00 00 01 0f 04 00 00 00 00 00 00 00 02 63 d5 c1 d0 00 00 00 0f 16 b8 00 00 00 00 03 c0 5a c0
+00 00 00 00 00 01 87 ac 50 01 00 06 00 1c f0 40 00 30 00 00 00 00 40 1c 3c da 25 01 00 00 00 11 af 54 00 00 31 e0 20 0a 54 00
+0c 30 00 00 00 05 01 41 00 00 00 02 14 ff f0 00 00 20 00 00 00 0a 02 40 0e 8a 10 00 02 07 9d d8 00 00 00 00 fc 22 40 a5 00
+04 40 00 00 00 00 b6 bd 50 00 00 00 27 df f7 28 00 01 00 00 00 00 48 14 03 eb e2 08 00 00 b0 bb f9 00 08 00 c8 60 5d c5 00 00
+00 02 04 00 f0 0d 31 c9 00 00 e8 42 1d 00 10 00 00 20 00 00 00 80 03 c2 41 00 f0 80 20 0b 0f b8 09 00 08 00 02 01 50 00 20
+80 00 00 40 00 00 06 ac 50 00 01 20 05 fa 00 03 00 00 00 00 00 0c 00 36 00 0e 0f 01 00 00 f8 f7 a9 40 08 c0 40 e7 a7 e0 50 98
+00 00 00 00 10 0f 41 41 00 00 0b e3 fc af 00 00 00 00 00 00 00 00 10 32 dc f2 40 00 00 80 9f b0 3e 80 00 01 00 43 c0 a0 00
+01 00 10 00 09 98 32 bd 50 00 00 7c 03 ed e0 00 00 00 00 00 00 00 00 9e 00 00 18 00 80 00 78 a0 73 d4 00 00 01 63 a7 a0 00 1c
+00 00 00 08 10 03 42 81 01 00 08 00 2c 05 a4 00 00 00 00 00 00 40 62 c0 3c 05 20 00 00 41 0a 0c 3d 40 40 00 00 01 50 f5 01
+c2 00 00 00 08 18 53 bd 50 00 00 00 62 00 a5 40 00 00 00 00 00 04 02 06 00 ea d1 03 00 00 80 07 33 d4 00 00 00 06 a1 ef a1 04
+98 00 00 00 30 00 43 c1 00 00 60 00 03 05 04 00 00 00 00 00 00 00 08 03 75 05 a0 00 08 00 00 b7 3f c0 08 00 2c 40 10 03 00
+00 00 05 80 08 00 02 3c 10 06 80 00 00 dc 50 68 00 00 00 00 00 06 06 04 02 ec ad 02 00 30 78 03 ef dc 00 a0 c0 43 01 c0 32 20
+12 02 00 00 f0 d1 03 d5 00 10 00 00 34 ed b4 08 04 00 00 00 00 00 14 03 dd 0f f0 00 00 85 00 3c 00 00 00 02 04 43 4b 20 00
+00 07 00 00 01 81 13 a8 10 01 00 00 00 00 e7 60 80 00 00 00 00 00 00 80 01 fa af 00 00 00 00 0b 71 40 00 80 02 07 8d d0 00 00
+00 00
+11 02
+01 01
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 20 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 08 00 00 00 00 00 00 20 00 00 00 00 08 00 00 00 00 00 00 20 00 00 00 00 00 00 80 00 00 00 00 00 02 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 08 00 00 00 00 00 00 20 00 00 00 00 08 00 00 00 00 00 00 20 00 00 00 00 00 00 80 00 00 00 00 00 03 00 00 00
+00 00 00 00 00 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 08 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 e0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 a0 25 be 00 40 00 00 3f cf e7 80 00 00 00 00 00 00 00 c1 a9 e5 81 81 00 42 04 0a 72 1e 04 00 00 02 80 d8 00 e0 80
+00 00 00 02 00 97 44 3e 80 00 42 bc 1e 98 00 00 00 00 00 00 08 00 2a 6d 6d 00 c0 00 01 00 a0 40 22 c0 00 04 28 02 00 00 00 00
+00 00 00 82 03 a4 00 60 04 16 08 16 c3 00 80 00 00 00 00 00 00 00 02 9c 18 19 00 10 00 f5 38 00 20 30 00 00 00 00 39 ca 00
+00 00 00 08 00 fe 80 3d 00 48 40 80 00 08 00 00 00 00 00 00 04 00 00 14 2c 50 a0 01 20 0f a0 b8 04 00 00 00 00 00 00 90 40 00
+00 00 00 2a 50 00 60 00 00 41 00 1d d0 00 00 00 00 00 00 00 40 10 20 55 d5 81 00 08 00 09 1b de 00 00 00 02 bd 58 50 00 00
+00 00 00 02 5a 02 c0 00 00 02 00 06 6d 00 08 00 00 00 00 00 00 00 01 28 18 00 80 00 c0 00 0d 34 e0 00 00 00 01 41 c3 8c 00 00
+00 02 00 21 f5 68 60 00 00 00 10 ce 90 0f 00 80 00 00 00 00 00 10 11 dd b5 8c 00 00 00 ff 32 00 3a 00 01 02 2d 7e 00 a0 00
+01 00 00 02 0f 7f c0 2d 00 00 01 a2 fc 00 d0 10 00 00 00 00 00 00 02 14 3f 00 00 00 00 4a f0 2c 04 10 00 20 02 80 d0 10 00 00
+00 00 00 68 05 be 00 00 00 10 33 c5 a1 01 00 00 00 00 00 00 20 00 30 9f e8 00 00 00 90 05 70 60 00 00 00 10 29 4c 38 00 00
+00 00 20 02 00 b2 cc 00 00 00 03 fc 2e 00 a0 00 00 00 00 00 00 00 03 01 ec d0 e0 00 00 00 a0 34 43 c0 00 00 02 81 00 0b 00 00
+00 00 09 0e f5 a2 00 00 00 00 10 ce e8 0e 00 80 00 00 00 00 00 10 00 07 f3 9c 00 02 04 af 3e a4 00 00 00 00 00 00 00 00 00
+00 00 00 00 ff 7f cc 00 02 00 02 4e ee b0 00 10 00 00 00 00 00 00 01 28 3c 08 00 00 00 0a f0 80 e0 00 00 00 00 00 00 00 10 00
+00 00 00 00 00 02 00 68 00 10 18 dd 91 0f 00 00 00 00 00 00 00 00 3b cf d7 08 00 00 00 04 93 c0 00 00 00 02 bd 48 00 00 00
+00 00 00 00 00 00 0c 31 00 00 02 8c 1d 18 d0 14 00 00 00 00 00 04 02 fd d8 08 00 00 28 00 05 b4 02 40 00 00 01 42 c0 00 00 00
+00 00 08 21 75 80 00 00 02 30 39 ce e8 00 00 00 00 00 00 28 10 00 00 00 03 88 00 0c 40 ef 7b 40 20 00 05 02 2d 5e 00 e0 02
+00 00 00 03 2b fb 80 00 40 20 03 7c 39 b0 01 00 00 00 00 00 02 00 00 00 00 f9 90 00 c0 0f f0 74 00 00 00 00 02 82 d0 00 00 20
+00 00 10 ac 75 a4 02 c0 00 00 5a 45 80 00 00 80 00 00 00 00 00 80 3b f5 a0 00 00 00 00 47 76 c0 06 01 00 0a 94 ea 81 8a 04
+00 00 00 1a c2 12 00 60 00 09 01 a4 10 00 00 84 00 00 00 00 00 00 23 ff 48 90 e0 00 00 08 11 a4 03 40 20 00 a9 a6 fd 0f 40 80
+00 00 10 28 51 bc 02 c0 55 00 48 44 c5 00 00 00 00 00 00 00 50 02 3f c0 08 00 01 58 40 47 58 2c 20 30 00 09 1d e9 80 18 01
+40 00 00 9a ad 12 80 7c 02 40 11 20 0d 08 a0 04 00 00 00 00 00 00 13 fc 00 10 00 00 08 08 b0 3b c7 00 02 04 b0 c7 d1 0a 40 10
+00 00 00 aa 51 bd 42 80 00 00 48 45 f7 8a 00 00 00 00 00 00 00 10 b0 c0 00 00 00 00 00 af 56 5e 05 00 00 0a 95 4e 10 10 00
+00 00 00 82 95 56 02 40 00 02 01 20 08 09 00 00 00 00 00 00 00 00 6b 0c 00 00 a0 00 00 00 50 60 23 08 00 00 aa 83 f1 88 1c 00
+00 02 00 6a 71 bc 67 80 00 00 5a 45 e0 00 00 00 00 00 00 00 00 00 00 16 97 00 4c 00 08 0a 38 60 60 05 80 0a bd 68 11 b4 00
+00 00 00 06 25 16 34 2c 00 02 01 a4 10 00 b0 00 00 00 00 00 30 00 02 80 2a 00 98 00 00 00 50 ab c3 90 28 04 82 80 f0 88 00 00
+00 00 00 20 57 f0 00 40 00 00 48 45 a3 9f 80 00 00 00 00 00 20 90 00 15 e8 08 80 20 04 0a 56 80 02 00 00 0a 95 5b 00 00 00
+00 00 20 03 5f 06 00 30 70 00 01 20 0b 08 d4 00 00 00 00 00 05 08 00 04 1d 71 00 02 00 00 a0 00 c0 00 00 00 aa 82 f0 0e 00 00
+00 00 11 2a 71 ac e6 00 40 00 48 44 a0 00 b4 80 00 00 00 00 00 05 00 06 80 00 14 00 00 af 53 c0 79 00 00 0a bc 69 10 08 08
+00 00 00 02 1a 17 00 00 00 00 01 20 0c 00 05 10 00 00 00 00 50 00 00 10 ea 00 90 00 00 00 50 a3 c0 08 00 02 82 80 a0 89 4d 00
+00 00 08 6a 55 fe 66 00 00 00 08 45 e0 1e 00 00 00 00 00 00 00 80 00 17 f0 00 00 80 10 a0 5f 20 28 00 02 0a 04 1f 90 00 00
+00 00 00 92 95 5e 04 00 00 08 01 20 1e 00 00 04 00 00 00 00 00 00 12 80 1b 00 00 00 00 0a 00 00 46 00 00 00 b6 fc 91 80 00 40
+00 00 10 aa 71 ee 00 40 22 00 00 00 01 00 50 00 00 00 00 11 00 52 00 04 80 00 00 0c 80 9d fb 5c 00 00 00 02 ad 5b f0 04 00
+c0 00 00 1a 25 16 c4 20 41 b0 00 00 00 78 e2 08 00 00 00 02 00 0a 00 04 2a 90 00 00 80 0a dd e0 00 00 00 20 02 d7 f1 8f bc 08
+00 00 01 25 53 00 00 40 00 00 03 2e a0 01 00 00 00 00 00 02 00 40 91 dd 90 19 00 00 0e 8d b0 40 70 00 00 09 1d fa 18 10 00
+00 00 00 03 aa 02 00 20 00 00 41 39 78 10 e0 00 00 00 00 00 38 00 0b 0c 69 00 80 00 20 24 e1 ae 46 01 00 80 b0 c4 e0 08 80 00
+00 00 01 25 a0 00 00 0a 05 00 a2 f4 00 0a 00 14 00 00 00 00 00 40 b1 ce a7 8e 00 54 00 f0 18 06 38 60 48 09 1d ef 00 10 01
+40 00 00 03 a5 03 1c 00 61 50 69 1c 6f 00 b0 01 00 00 00 00 00 00 0b 08 4f 78 a0 09 00 8f 00 03 c7 c0 04 00 b0 cc a9 08 00 10
+00 00 00 00 0b 68 00 00 00 00 01 fe b1 88 00 08 00 00 00 00 00 01 89 47 b1 0e 20 80 00 af 3a 00 00 80 00 1a 3d db 00 81 12
+00 00 00 80 02 92 00 00 00 00 00 3d 58 d9 00 00 80 00 00 00 82 00 0a 9d 6c 00 00 10 08 00 a0 24 00 10 00 20 83 9e d0 00 00 80
+00 02 01 0a f1 a0 00 04 20 10 10 9f d0 08 01 00 00 00 00 02 00 00 01 5c f0 09 10 40 00 00 00 16 72 00 00 09 1c 6f 18 01 14
+00 00 00 00 af 08 1c 28 00 00 00 28 1d 01 a0 00 00 00 00 00 00 00 02 bc 1e 01 f0 00 00 00 00 02 40 11 20 20 b0 e6 a0 08 10 00
+00 00 00 00 55 80 06 00 00 15 a1 56 e7 01 00 00 00 00 00 00 00 30 22 ce c0 0b 00 00 00 af 76 5c 04 00 04 19 1e da 79 90 00
+00 00 20 00 0a 0a 00 30 00 0c 7b 7c 1a 58 c0 00 00 00 00 00 00 00 03 6c 2b f1 c0 00 00 00 a0 31 63 40 20 00 b0 c6 e0 8c 00 00
+00 00 00 0f 51 a0 e3 80 20 00 11 a7 a1 80 00 00 00 00 00 00 20 40 ab df 97 80 00 00 40 ab 1b 56 78 77 00 48 97 4f 11 8a 08
+00 00 00 00 f5 08 02 70 05 00 03 09 cb 10 e0 00 00 00 00 00 01 00 08 28 09 00 f0 00 00 00 b0 f4 06 68 30 01 96 d4 c9 8c 15 40
+00 00 00 05 f5 80 03 80 00 10 02 8e d0 0e 00 00 00 00 00 00 00 00 01 57 ef 98 00 00 c0 83 5e 00 04 05 02 0a 3d fb 80 80 00
+00 00 00 00 af 0a 00 40 00 00 00 04 3d 10 00 00 00 00 00 00 00 00 00 14 00 f0 00 40 00 06 70 f4 03 80 00 00 83 9e f1 30 10 00
+00 00 08 0a bb 7c 06 84 03 34 82 9c c0 19 40 0c 00 00 00 00 50 10 22 cc a0 18 00 88 00 83 b7 c0 72 85 20 0a bd 7f f1 f0 00
+c0 00 00 00 0b 33 40 40 00 22 58 74 1f 00 8a 00 80 00 00 00 02 00 01 08 3c 00 c0 00 c0 00 1f 23 c4 10 23 00 81 42 d1 1e 00 08
+08 00 00 80 55 3a 00 00 00 00 28 1d 99 00 00 00 00 00 00 02 20 00 00 15 d0 01 00 00 00 e7 1a 60 6c 82 00 01 1d dc 80 00 01
+00 00 00 00 af 0a 54 00 00 00 00 00 1c 10 e0 00 00 00 00 00 00 00 60 10 d9 00 80 00 20 0e f7 be c6 c0 50 00 20 66 b5 0c 00 00
+00 00 00 04 29 a5 c0 40 00 10 38 06 95 00 08 10 00 00 00 00 20 87 2b c6 c8 00 1c 01 00 a0 76 76 78 00 01 01 1d 61 00 0a 02
+00 00 00 00 84 97 80 28 02 00 01 00 3c 30 a0 05 00 00 00 00 01 00 02 bc 20 70 00 00 28 00 00 67 44 00 50 80 22 c0 f0 00 00 00
+00 00 04 04 a3 e8 07 00 40 15 a1 57 f0 00 00 0c 00 00 00 00 00 91 03 0c b1 00 20 00 40 89 76 e0 00 01 00 02 bd 4e 71 c0 00
+00 00 00 00 a5 02 9c 40 00 08 4b bc 0b 00 00 00 c0 00 00 00 40 02 00 70 0e 08 f1 00 00 04 a0 f0 c3 80 00 00 01 42 a7 90 00 00
+00 02 00 8a 01 70 00 42 00 01 81 5f b1 1f 40 80 00 00 00 00 00 10 09 cf a9 8a ac 00 40 05 13 20 00 00 00 10 92 00 01 90 04
+00 00 00 00 a0 08 00 20 20 00 69 7c 1d 00 d0 00 00 00 00 00 50 00 00 9c 00 51 04 08 00 0e 70 ad c0 03 00 00 06 0c e5 0f 00 80
+00 00 04 04 73 e4 00 00 40 05 a1 5e 90 01 00 00 00 00 00 28 00 10 01 5f e8 0e 40 00 40 83 77 20 78 00 00 10 29 5c 00 12 00
+00 00 20 00 05 0e 1c 00 00 02 4b bc fb 00 d0 00 00 00 00 00 00 00 03 6c 28 10 fa 01 00 06 70 75 47 c6 00 00 02 82 0b 0d 00 00
+00 00 00 03 09 a6 67 c0 50 00 06 87 df 99 00 00 00 00 00 08 00 10 22 57 f3 0b 01 c1 40 07 3a 6c 04 00 00 02 bc e9 01 d8 00
+00 00 00 00 50 97 8e 64 00 00 02 75 c9 f8 80 00 00 00 00 01 00 00 03 1c 3e 09 e0 08 00 00 10 a0 63 87 00 00 02 80 b0 1d 40 00
+00 00 04 08 03 f0 00 06 00 00 04 66 f9 00 00 00 00 00 00 00 00 10 00 d6 00 00 20 01 00 cf 1b 00 69 00 04 01 01 60 80 10 00
+00 00 00 00 d0 07 40 34 00 00 00 0b fc 10 80 00 00 00 00 00 02 00 10 0c 20 00 04 00 20 0e fb 38 42 a8 00 80 20 2c c1 0f 00 00
+00 00 08 00 0b a4 00 42 00 12 00 c7 c9 08 01 48 00 00 00 00 10 00 2b d4 d7 8f 01 00 04 05 30 06 00 01 0a 00 29 48 00 00 00
+00 00 00 1c 02 9f 80 24 00 00 03 cc 1e 50 80 08 c0 00 00 00 06 00 00 28 3c b1 f0 08 10 00 a0 28 00 01 20 40 02 82 09 00 01 40
+00 00 00 a4 73 62 07 46 00 40 a3 d5 f8 18 01 c0 00 00 00 00 00 00 21 6d 8d 81 01 40 00 07 b2 9e 2c 00 04 0b 1d fb 19 e0 10
+00 00 00 02 c3 3f 44 3c 00 00 48 38 ce b0 f0 04 00 00 00 00 68 00 03 ab fe 78 f0 00 10 00 1d a3 62 42 00 00 b0 8d d0 1c 18 80
+00 00 00 a4 77 6b e0 50 04 00 91 d4 d7 99 40 90 00 00 00 01 00 00 23 ed 87 9b 18 00 00 47 b0 60 71 10 00 0a bd dd 71 e4 03
+00 00 00 02 c3 df ee a2 b0 40 2f 0c 4e 08 88 05 00 00 00 02 00 00 01 14 4d 31 e0 00 00 08 b5 23 c3 a8 00 00 81 41 d0 9f 20 14
+00 00 00 2a 5b 20 67 00 00 00 a3 dd e1 89 20 00 00 00 00 20 00 00 20 44 c7 8e 10 00 40 42 32 60 04 00 08 0a bd d8 f9 ef 48
+00 00 00 1a 59 72 4c 40 00 00 28 38 ef 01 8a 00 00 00 00 00 00 00 01 7e 7c 01 00 00 00 08 b0 6a 43 c0 00 00 82 81 e3 80 81 40
+00 02 00 68 f5 69 e6 17 50 02 a3 f4 d1 80 00 00 00 00 00 02 20 14 20 ce a0 01 80 01 40 81 1a 16 78 00 00 1a 95 5c 01 d4 00
+01 80 00 02 0e fe 02 00 82 00 0c 39 ec 00 00 00 00 00 00 00 41 00 01 9c 3d 00 f0 00 00 00 a0 37 43 c1 00 00 95 43 95 18 90 00
+00 00 08 6c 7b b2 c7 c0 00 04 91 ef 80 09 00 00 00 00 00 00 00 00 28 4c ef 00 40 00 00 05 18 0c 24 80 02 0a bd 69 00 18 00
+00 00 20 02 c2 13 9c 20 60 82 0b 0c 59 00 e0 00 00 00 00 00 04 00 01 5d 7c f0 ca c0 00 00 a0 24 07 d0 20 00 82 80 d0 08 40 00
+00 00 08 28 f5 ae 07 c0 50 44 91 f5 f0 08 10 80 00 00 00 10 20 10 20 cc e8 01 00 00 40 8b 3e 20 04 41 00 02 87 68 11 e0 00
+00 00 00 02 0d f2 44 7e 71 00 0b 0c 59 00 f0 00 00 00 00 00 05 00 01 9c 3d d0 f0 00 00 04 20 e3 c3 ce 20 00 15 cc b1 00 00 00
+00 00 00 2c 79 bf c3 00 20 00 a9 5d f9 00 0c 80 00 00 00 03 20 00 29 4d b7 18 00 80 00 47 da 40 00 62 01 02 0d 69 01 90 08
+00 00 00 82 c2 be 5c 00 04 00 1a a8 1e 18 80 10 00 00 00 00 04 00 41 54 29 f8 00 04 00 05 f3 a4 00 07 40 00 19 c1 a0 0d 00 00
+00 00 00 28 df 80 67 80 03 20 a3 f6 cf 88 00 0c 00 00 00 00 00 00 39 4e 97 80 21 40 40 05 7e 94 00 07 01 00 1d ff 58 c1 80
+80 00 00 8a 4e fb 7c 40 00 20 48 39 ec 19 c8 00 80 00 00 00 00 00 11 16 4a 08 00 40 00 0e 70 ac 20 00 30 00 2a c2 80 1e 10 08
+00 00 00 0a b3 34 06 28 00 40 b1 c6 e1 01 00 00 00 00 00 00 00 81 00 24 81 0a 18 80 0a c7 1a 7c 02 84 00 00 14 ce 51 c0 80
+00 00 00 00 0b d7 b4 35 00 00 4b 08 7c 00 80 c0 00 00 00 00 00 00 00 11 6e 09 00 10 00 2c 13 6c 43 d0 00 00 17 c0 80 8a 00 80
+00 00 04 08 35 a0 00 10 20 00 91 cd e3 80 00 94 00 00 00 00 00 80 39 e0 18 20 80 02 02 a5 da 00 24 80 55 03 6c f8 81 c8 04
+00 00 00 00 67 0f 40 3c 80 00 4b 0c df 00 00 01 40 00 00 00 00 00 03 6d cf f0 04 00 00 25 91 b0 06 10 05 00 22 c2 ab 1f 00 80
+00 00 00 0a b3 35 62 a2 00 00 91 c4 f1 bc 00 00 00 00 00 06 50 94 01 16 80 1f 00 10 02 47 36 66 00 20 00 10 14 4b 00 e0 00
+00 00 00 00 0b 16 80 01 00 02 0b 0e ef 00 81 c0 00 00 00 00 02 08 00 10 20 01 c0 00 00 ac 39 af c0 04 00 00 22 d6 80 0f 18 00
+00 02 04 08 33 2b e3 00 00 04 a3 d5 f1 99 50 80 00 00 00 00 00 40 01 55 b8 1c 8c 00 02 8f d6 ce 00 02 00 40 29 61 70 8a 1c
+00 00 00 00 67 03 56 00 02 00 08 3b fb 90 80 00 00 00 00 02 00 00 01 7c 0c f1 00 00 08 20 e1 e8 03 a8 40 00 01 40 80 00 20 00
+00 00 04 0a 37 a0 e7 40 00 24 a3 d7 98 18 00 00 00 00 00 00 00 80 28 0d f0 08 04 00 02 a5 d6 dc 64 00 00 02 95 4d 59 e0 00
+00 00 20 00 a3 00 02 70 00 00 08 39 5c 10 90 00 00 00 00 00 00 00 41 68 1f 01 00 00 00 25 9d a0 02 28 00 00 15 41 90 80 00 00
+00 00 05 0c 03 e4 00 68 50 01 a3 f6 b8 00 08 00 00 00 00 02 00 00 24 3f b0 1c 1c 00 00 05 56 44 05 71 03 02 2d c0 80 00 16
+00 00 00 00 ca 02 c0 38 01 00 18 3a 4b 70 81 80 00 00 00 00 05 00 01 41 ef 01 00 00 08 0a f0 b4 03 60 20 00 11 c2 ef 00 00 00
+00 00 10 02 75 81 c0 07 00 00 ab df b0 0e 00 00 00 00 00 07 00 10 30 0d f0 18 00 00 00 05 37 00 20 00 00 02 95 49 78 0a 80
+00 00 00 00 1b fa 40 00 00 00 08 14 3d 90 f0 00 00 00 00 00 00 02 03 28 0a 00 00 00 00 00 50 40 04 00 00 00 15 40 b0 08 00 00
+00 00 00 00 00 00 03 b0 20 01 a3 f6 af 1c 00 0c 00 00 00 00 00 80 01 1f 8d 80 80 82 00 05 30 40 00 50 31 02 2d e0 01 a0 00
+00 00 00 00 00 00 00 3e b0 00 08 3a 6a 19 00 00 c0 00 00 00 00 00 10 00 fa 38 81 04 00 00 a0 34 00 02 02 00 11 c0 e0 10 a0 00
+00 00 00 2e 37 e4 e6 40 00 00 22 5d e7 01 00 00 00 00 00 10 00 40 11 1e d7 1f 18 01 00 01 3a dc 00 00 00 49 1d 7e 81 91 c0
+00 00 00 0a 43 16 ae a0 80 80 03 2c fb 08 80 00 00 00 00 02 ec 00 01 20 4c 01 c0 00 00 08 37 a8 00 30 00 40 b0 c6 c1 08 14 00
+00 00 00 2c 35 77 e0 00 75 00 29 e7 d0 00 00 80 00 00 00 00 40 00 28 0e 10 00 80 80 00 af 56 40 24 04 04 0b 1c d9 00 14 01
+40 00 00 82 8b 12 46 bd 05 40 00 67 ce 90 90 00 00 00 00 00 02 00 01 40 0e 00 00 d0 00 00 50 a8 07 01 20 00 b0 45 e9 08 21 14
+00 00 00 22 ff 61 c7 05 00 10 28 df b3 8a 00 00 00 00 00 00 00 14 30 44 c7 00 00 00 40 01 56 ae 24 40 00 0b 1c ff 01 80 00
+00 00 00 02 0b 3e c0 00 00 00 02 4c 3d 10 0a 00 00 00 00 00 00 00 02 00 28 00 d0 00 00 0a 70 3a c2 80 00 00 b0 a6 90 00 00 00
+00 02 00 ec 3f f6 03 80 00 10 31 4c 80 0f 00 00 00 00 00 0a 00 00 01 4e 80 00 00 80 40 c5 5f 86 76 07 00 00 14 4b 01 8a 00
+00 00 00 02 8b d2 7c 02 00 00 03 14 20 f1 d0 00 00 00 00 00 00 00 01 7c 28 00 09 50 00 0c 50 40 03 90 30 00 2b c2 c1 00 40 00
+00 00 00 2c 33 a4 e0 00 00 14 30 16 cb 80 00 00 00 00 00 00 00 02 29 7e 89 08 00 00 40 ab 53 b6 00 00 00 0a 97 ed 00 80 08
+00 00 22 82 47 77 7c 3c 70 00 03 14 1e 78 e0 14 00 00 00 00 04 00 00 84 d8 78 c0 00 00 00 70 aa c0 00 08 80 96 7c 80 08 00 00
+00 00 01 20 d9 74 66 f8 20 00 22 cf 88 01 08 00 00 00 00 20 20 00 01 4c 80 01 00 00 40 89 5a 84 00 01 00 0a 3f 7f b8 e0 00
+00 00 00 02 4f 9b 3c 7d 80 02 02 2e f0 50 d0 00 00 00 00 01 00 00 01 7c 2d f2 b0 40 00 0c b0 a4 20 08 20 01 83 6c e1 9d 18 00
+00 00 00 2c 3b 66 02 00 00 80 19 d5 f5 88 1c 00 00 00 00 00 00 30 36 d4 c0 00 10 c0 40 47 7e 00 78 00 00 0b 1e fe 71 c0 08
+00 00 00 02 47 9f 04 40 00 00 01 0f fa 19 00 00 00 00 00 00 00 00 02 2c 0b 02 00 14 00 04 70 80 02 44 00 80 b0 ae f0 10 01 00
+00 00 00 20 55 b4 03 c0 02 00 23 7c a0 00 01 40 00 00 00 00 30 00 2b de c7 00 20 00 00 af 33 b6 00 00 00 40 9e e1 38 90 00
+c0 00 00 06 5f 07 40 3c 01 20 41 37 e9 10 82 08 00 00 00 00 00 00 00 14 29 08 8c 00 00 00 a0 b5 c0 00 00 00 06 ce f3 8d 00 08
+00 00 00 a4 71 fc 07 47 00 00 31 ce e8 01 00 00 00 00 00 00 70 00 2b 44 95 98 00 80 02 04 9f c0 04 00 10 02 84 cf 18 e1 88
+00 60 00 02 c3 17 00 20 00 00 01 1b ce f0 80 c2 00 00 00 00 03 00 02 24 6f 08 d0 14 00 21 c3 e0 02 00 00 00 2a e4 87 08 00 00
+00 00 00 aa f7 3e c3 40 05 00 20 4c e0 01 00 00 00 00 00 00 00 00 20 4c 90 00 00 00 02 80 ba 4e 04 05 51 02 25 f8 80 19 40
+00 00 00 02 0a 06 3e 30 00 40 02 be de 00 d8 00 00 00 00 02 01 00 01 7c ea 00 00 00 00 2e 07 3d 42 00 05 00 31 c1 cf 08 40 00
+00 00 00 20 51 b8 00 00 00 10 20 dc f3 80 00 80 00 00 00 00 00 00 39 74 c3 80 04 00 02 04 f7 a0 60 75 01 00 14 4a 38 10 00
+00 00 00 02 5f 07 40 00 00 00 22 6c 2c 08 00 00 00 00 00 00 00 00 01 15 df b0 d0 00 00 21 c3 e9 40 08 20 00 10 82 80 0d 00 00
+00 02 00 6a f1 b8 60 00 00 00 2b fe 80 01 40 80 00 00 00 28 00 10 31 4c 00 1a 01 00 02 80 3b 66 78 01 00 00 07 5c 00 06 04
+00 00 00 02 0a 0e 00 00 00 00 22 07 ce 00 ea 00 00 00 00 00 60 00 03 28 0e 01 d0 00 01 2e 03 7c 40 00 20 00 29 f6 ef 00 00 40
+00 00 00 0a bb 66 07 a8 00 00 20 56 e3 01 00 00 00 00 00 06 00 10 30 15 df 0c a0 00 02 04 d7 f4 32 84 00 00 0d dc 78 80 00
+00 00 20 00 0b f6 c4 7d 00 00 01 7f 4f 50 a0 00 00 00 00 00 00 00 23 28 2a f8 e0 00 00 21 c3 f8 44 00 00 00 09 ee b9 00 00 00
+00 00 04 08 33 b6 00 40 20 11 20 de c7 88 14 80 00 00 00 00 00 80 2b df b3 9c 00 c0 02 02 bf 40 00 40 00 03 55 5c 00 90 10
+00 00 00 80 67 0e 44 3c 00 00 01 9c 3e 59 e0 04 00 00 00 00 00 00 00 14 0d 09 00 02 00 21 af ad 42 40 40 00 36 87 df 09 0c 80
+00 00 00 2a 57 26 e6 28 10 00 01 6e e9 1e 00 00 00 00 00 07 00 00 2a d6 a7 89 00 80 02 04 b7 e0 7e 80 00 00 00 00 80 04 04
+00 00 00 02 55 0b 5c 01 02 00 03 6c 6f 51 f0 00 00 00 00 00 00 02 00 2f 4e 00 80 10 00 21 c3 ef 43 10 40 00 00 00 0f 09 00 00
+00 00 00 2a f5 e3 c3 84 53 10 20 c5 cd 8a 00 00 00 00 00 00 00 00 00 00 05 a8 54 00 02 00 1f 60 60 00 20 00 00 00 01 80 00
+00 00 00 02 05 0b ce 00 00 30 11 9c 3e 50 00 00 00 00 00 02 80 00 00 00 00 09 00 00 00 20 27 bc c2 04 23 00 00 00 00 00 04 00
+00 00
+11 03
+01 01
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 70 00 40 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 38 00 80 00 00 00 00 00 02 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 30 00 00 00 40 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 08 00 00 00 00 00 00 20 00 00 00 00 08 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 08 00 00 00 00 00 00 20 00 00 00 00 0c 00 00 00 00 00 00 30 00 00 00 00 00 00 40 00 00 00 00 00 03 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 30 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 03 00 00 00 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 00 00 00 00 00 00 00 00 00 00 00 00 00 28 00 02 00 00 00 00 00 00 08
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 00 00 00 00 00 00 08 00 00 00 00 00 00 20 00 00 00 00 00 00 80
+00 00 00 00 00 00 00 00 00 00 00 18 00 00 00 00 00 08 00 00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 00 00 01 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 04 00 00 02 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 3c 02 f0 08 00 0c 00 f0 06 40 00 00 00 01 e0 5b 00 00 00
+80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 3c f8 00 10 00 80 00 f5 bc 06 80 00 00 12 fd d0 1c 00 0c
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0b 10 00 00 00 f0 0a c4 00 00 00 0b 69 5e 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 81 80 00 00 00 f7 26 60 00 00 00 b0 36 90 08 14 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 8c 02 d9 08 00 00 00 33 b6 42 00 00 04 08 94 19 10 80 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 01 e0 00 00 00 00 00 00 01 09 e9 6f 98 10 00 00 0c c9 6d c0 00 00 10 8b 9e 88 1c 00 00
+00 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 21 42 87 10 00 00 00 69 d4 14 28 00 00 03 00 0a 00 c4 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 14 ec 81 80 00 00 16 99 72 06 c0 00 10 30 8e 90 00 a0 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 b5 00 00 00 00 69 b0 14 00 00 00 01 54 0b b0 80 00
+00 00 20 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 15 6b d8 e0 00 00 16 99 7b 42 80 00 10 33 06 b8 0b 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 8c 0f e0 00 00 08 00 69 b4 02 28 00 00 03 c2 ee 00 00 00
+c0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 09 eb 7c 01 a0 00 c0 16 91 68 e0 40 00 00 38 77 83 98 01 08
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ae 1c d0 0a 00 00 00 69 34 00 00 00 00 09 4e 4a 00 90 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 09 63 cb 00 10 01 80 16 91 29 40 00 00 01 a8 de 10 19 00 18
+00 00 00 00 00 00 00 00 00 04 3c 00 00 00 00 00 00 00 00 00 00 00 b9 c6 e0 0a 00 00 00 69 30 00 00 05 00 49 fc de 50 04 00
+00 00 00 00 00 00 00 00 00 00 03 c0 e0 00 00 00 00 00 00 00 00 00 0b dc fe 00 10 00 00 16 90 28 06 00 20 00 8f d6 91 8a 80 00
+00 00 00 00 00 00 42 20 02 00 06 7c d1 90 00 08 00 00 00 08 00 00 19 c1 80 10 00 0e 02 22 0a 02 00 00 30 0b c0 00 00 00 00
+80 00 00 00 00 00 20 05 00 22 02 9c cf 10 e0 00 c0 00 00 00 00 05 02 0d 58 00 80 00 8c 2d d3 64 67 00 03 40 bc 1c 00 20 00 0c
+00 00 01 26 90 40 02 00 00 00 19 fd b9 00 00 00 00 00 00 00 00 00 11 46 c9 90 20 00 00 87 0c 04 01 04 00 03 25 69 01 00 00
+00 00 01 06 69 17 80 64 00 04 00 97 5d 01 80 00 00 00 00 00 04 00 02 3d ca 10 84 00 04 08 71 3a 00 00 20 00 0d 95 80 08 00 00
+00 00 09 a6 90 00 00 00 00 40 17 ad f0 8f 00 00 00 00 00 00 00 00 06 47 ff 00 00 00 00 0f 0b c6 00 00 00 02 5a 6d 00 b0 00
+00 00 00 03 69 16 80 00 00 02 00 31 f9 30 10 00 00 00 00 00 00 00 02 9c dc 80 00 00 00 0a 51 2b 40 00 00 00 0f 27 b5 81 00 00
+00 02 00 66 90 03 c0 00 00 04 0b a7 e0 0f 00 00 00 00 00 00 00 20 2b 47 91 09 04 00 00 dd 0e c4 00 00 00 00 cc 39 00 00 00
+00 00 01 07 69 17 80 00 00 08 00 96 df 78 10 00 00 00 00 00 00 00 00 32 6a 80 02 10 04 02 25 be 00 00 00 30 33 0d c5 80 00 00
+00 00 00 a6 90 40 00 00 00 00 80 00 a9 09 00 00 00 00 00 00 00 80 16 d7 b0 9c 00 00 00 87 0b 54 2c 00 00 03 50 4b 50 00 00
+00 00 20 93 69 12 80 60 00 00 18 15 e9 d0 10 00 00 00 00 00 00 00 00 0f 68 38 90 00 04 04 b7 86 60 00 00 00 3a 34 00 0a 00 00
+00 00 01 a6 90 40 40 00 02 00 80 02 e0 08 00 08 00 00 00 00 00 00 80 02 f3 0c 20 0c 00 f0 08 00 40 40 30 03 c0 3a 51 01 40
+00 00 00 13 69 12 a6 00 00 30 28 14 d9 00 10 00 80 00 00 00 00 00 08 14 7a 18 a4 00 80 0f 01 80 c2 80 02 00 03 cf b0 0a 00 00
+00 00 09 26 90 00 03 80 00 00 80 00 bb 90 00 00 00 00 00 00 00 80 80 00 9b 8c 00 00 00 22 5e 00 6c 00 00 03 e8 1d 59 00 00
+00 00 00 13 69 13 80 04 00 60 08 15 e9 99 80 01 80 00 00 00 00 00 08 14 7f b8 10 01 80 0d db b4 62 80 06 00 17 d7 95 1c 00 18
+00 00 0b 26 90 00 00 04 00 00 80 03 ef 0e a8 00 00 00 00 08 a0 00 80 02 e7 09 00 00 00 00 00 36 00 00 00 4b c0 20 d0 00 00
+00 00 00 93 69 13 80 00 00 00 08 14 d9 00 04 c0 00 00 00 00 00 00 18 14 7a 00 80 00 00 00 00 01 40 00 00 00 bc 0e 00 00 00 00
+00 00 01 a6 90 40 02 05 02 00 80 0d e0 00 20 08 00 00 00 00 00 04 34 4f b0 00 00 0e 00 67 0e 40 7c 00 30 03 48 10 70 00 00
+80 00 00 03 69 17 86 04 00 30 0a 06 1e 58 a4 00 80 00 00 00 00 08 02 87 f8 38 e0 04 c4 08 31 f4 e2 00 03 10 34 97 ed 00 00 0c
+00 00 00 a6 90 40 22 00 00 00 80 00 c0 2f 00 00 00 00 00 00 00 00 05 cd 81 0e 40 00 00 43 36 80 30 00 00 00 3c 2d 10 e0 00
+00 00 01 17 69 16 8e 64 80 04 08 15 dc 50 b0 00 00 00 00 00 00 04 00 9e 6f 80 10 00 00 06 7b 60 02 00 00 40 3c 1c e8 18 00 00
+00 00 08 26 90 00 03 82 00 00 80 8c e5 0a 00 00 00 00 00 17 20 80 24 ec e0 99 00 00 10 67 9a cc 3c 00 00 00 e4 2f 00 90 00
+00 00 01 17 69 16 80 00 20 04 08 07 c0 01 c0 c0 00 00 00 02 85 00 02 8c e8 19 80 00 00 02 5b 70 02 00 00 10 32 4c 80 00 00 00
+00 02 09 66 90 00 00 00 00 04 80 00 d5 0a 00 00 00 00 00 00 00 40 2b 67 f0 00 00 02 00 67 02 c4 00 60 08 02 80 2d 90 d2 00
+00 00 00 97 69 17 80 00 00 00 08 15 dc 00 00 00 00 00 00 00 40 04 00 32 eb 78 00 00 04 08 37 76 06 00 00 00 01 5c e8 01 40 00
+00 00 00 66 90 40 40 00 00 00 80 8e e0 00 00 00 00 00 00 03 00 00 12 b7 d7 00 00 00 00 89 72 56 30 10 02 01 7c 2f 00 00 00
+00 00 20 03 69 12 a0 60 50 02 08 07 c0 00 00 02 00 00 00 00 60 00 42 2e 5f 30 c0 00 00 0c 79 a5 c0 00 00 00 2b cc 00 18 00 00
+00 00 01 26 90 40 40 00 03 04 80 00 c0 00 00 28 00 00 00 00 00 00 80 03 ab 10 10 0c 02 05 0b 94 32 80 20 09 38 ee 00 80 0a
+00 00 00 03 69 12 a6 00 00 30 08 15 dd 00 00 02 80 00 00 00 05 00 08 14 fa 99 e0 00 80 20 05 a8 02 90 02 00 a3 5c 00 01 00 60
+00 00 01 26 90 00 00 00 00 00 80 8c e0 0d 00 00 00 00 00 00 00 00 80 02 d7 1b 00 00 02 00 06 ee 28 00 00 08 28 0a 00 00 00
+00 00 00 03 69 13 80 00 00 60 48 07 e0 00 10 01 80 00 00 00 00 00 08 14 7b 00 b0 01 80 2a 07 7f c0 00 06 00 ab dc c0 00 00 18
+00 00 02 26 90 00 00 00 00 00 80 00 df 00 00 00 00 00 00 00 00 00 80 03 bb 08 00 00 02 05 0b bc 20 00 00 0a bc 2c 00 90 08
+00 00 01 03 69 13 80 00 00 00 48 15 dd 80 00 00 00 00 00 00 00 00 08 14 fb 80 12 00 00 20 05 ea 00 40 00 00 81 5e a0 00 01 40
+00 00 00 26 90 40 02 00 23 00 81 43 e0 00 00 0c 00 00 00 00 00 00 80 01 90 0c 00 08 10 00 07 82 34 00 30 0a a8 10 01 00 00
+80 00 00 03 69 17 86 74 00 34 08 01 ca 78 00 00 80 00 00 00 00 00 0a 80 f9 38 10 00 90 0a 03 f8 60 40 22 00 aa 9f a0 08 00 0c
+00 00 00 26 90 40 00 16 20 80 82 82 80 8e 00 00 00 00 00 00 00 00 82 82 a0 00 08 01 00 00 03 c2 38 84 00 09 37 6e 10 04 00
+00 00 00 03 69 16 86 62 01 00 08 00 ce 78 01 00 00 00 00 00 05 00 08 00 7f 30 00 00 20 00 57 7d e0 10 20 00 a3 b6 18 18 a0 00
+00 00 00 26 90 00 00 08 00 00 81 43 e0 09 00 00 00 00 00 00 00 00 80 00 93 0c 09 41 00 a0 07 80 34 00 0a 03 fc 3b 00 f0 00
+00 00 00 03 69 16 80 01 00 02 08 01 c8 00 00 00 00 00 00 00 80 00 0a 80 eb 80 18 08 00 00 03 f8 40 40 00 50 3b d6 b0 01 00 00
+00 02 01 26 90 00 00 00 04 00 82 82 8f 80 00 10 00 00 00 00 00 80 82 82 d0 0d 00 10 02 01 0a 1c 00 00 40 02 bc 10 00 00 01
+00 00 00 03 69 17 80 00 04 00 08 00 cf 78 00 00 00 00 00 00 01 00 08 00 7f 00 10 00 04 20 23 80 00 00 00 00 2b d4 e0 00 00 00
+00 00 00 26 90 40 40 08 00 00 81 43 e0 00 00 00 00 00 00 00 10 80 80 00 90 10 00 02 14 05 07 80 00 00 00 08 3d 6f 10 01 40
+00 00 20 03 69 13 a0 61 70 00 08 00 6e 01 c0 00 00 00 00 02 00 00 0a 80 ed 01 e0 00 00 00 03 f8 02 28 00 00 a3 94 e9 80 00 00
+00 00 00 26 90 40 40 00 03 04 82 82 a0 90 00 08 00 00 00 00 00 00 82 82 80 10 08 0c 02 05 0a 00 00 00 30 0b 30 20 00 80 00
+00 00 00 03 69 12 bc 00 00 20 08 00 ce 10 80 00 c0 00 00 00 00 04 08 00 7e 01 e0 00 c0 20 01 60 00 00 03 10 b3 1c 01 81 00 00
+00 00 00 26 90 00 20 08 00 04 81 43 e9 09 18 00 00 00 00 05 00 80 80 01 97 0f 00 00 02 00 06 40 66 20 00 00 00 1b 00 00 80
+00 00 00 03 69 13 9e 01 00 60 08 01 ee 00 00 01 80 00 00 00 00 00 0a 80 ff 58 10 01 80 2a 01 b0 03 80 06 00 01 5f b0 00 08 18
+00 00 00 26 91 40 02 00 00 40 82 82 c1 08 00 00 00 00 00 00 80 04 82 82 99 08 a0 02 10 ff 02 00 24 00 00 08 3c 1e 00 00 00
+00 00 00 03 69 06 00 04 20 00 08 00 cf 00 00 00 00 00 00 00 00 00 08 00 7e 00 00 00 01 0a f7 78 60 00 00 00 aa 94 e0 00 00 00
+00 00 00 00 00 00 c7 50 40 04 19 c0 90 9e 00 00 00 00 00 00 00 04 18 c2 87 18 00 08 02 00 02 00 00 00 20 02 00 1a 70 f0 00
+80 00 00 00 00 00 00 70 02 01 02 0d ed 38 80 00 00 00 00 00 00 01 02 8d e9 10 80 00 80 aa 07 2d c0 00 02 10 00 0e bf 8a 00 08
+00 00 00 00 00 01 e3 40 00 00 06 6c c0 0d 00 00 00 00 00 00 00 00 09 bf e1 8e 00 00 06 05 02 24 42 00 00 02 80 00 00 00 00
+00 00 00 00 00 00 0c 38 00 00 02 9d cb 38 10 00 00 00 00 00 70 00 02 9e e9 b8 f0 00 00 20 01 f1 c2 10 00 00 28 1f c0 00 00 00
+00 00 08 80 00 72 c3 88 10 04 19 c0 90 0b 00 00 00 00 00 00 00 04 24 df f0 90 1c 00 02 00 06 1c 41 40 08 11 78 5c 01 f0 00
+00 00 00 00 a5 03 20 01 30 01 02 0d 5b 00 14 c0 00 00 00 00 30 00 02 8d fa 70 a0 00 08 2a 07 74 0f 00 00 00 03 3e b0 1f 00 00
+00 00 00 0f f3 a9 e3 42 04 00 31 8e 89 0e 00 10 00 00 00 00 00 04 19 c2 f7 00 00 10 02 05 06 00 00 00 40 00 94 19 00 04 01
+00 00 00 00 ef 77 ee 74 00 00 03 16 7b 00 00 00 00 00 00 00 40 01 02 0d 69 80 00 00 08 20 01 b8 00 00 00 50 29 4d b3 9e 20 00
+00 00 00 0f ff 60 03 08 00 00 26 c3 80 0b 40 80 00 00 00 00 00 00 06 5d 9d 90 00 00 12 00 06 00 02 01 00 02 bc 0a 10 c0 00
+00 00 00 00 ef fe 40 3d 00 01 42 0c 4c 78 c0 14 00 00 00 00 00 00 02 9f 6a 51 e0 10 00 2a 07 7c 00 38 20 00 17 ce 18 00 00 00
+00 00 00 8f f0 60 00 00 00 00 31 8f b0 98 00 00 00 00 00 00 00 00 82 81 f0 8f 00 0a 02 05 06 24 3d 00 30 08 00 1e 08 02 00
+80 00 00 4c ef 5a 40 00 00 00 03 16 68 19 e0 00 00 00 00 00 20 00 08 00 fe 78 10 00 c0 20 01 a8 07 a0 03 20 81 47 f5 80 40 08
+00 00 00 0f f0 77 66 08 40 04 19 c3 90 89 00 00 00 00 00 00 00 00 90 14 c0 1d 00 00 02 00 06 00 78 d0 00 28 00 18 70 d0 00
+00 00 00 40 ef 77 14 2d 02 01 02 0d fb 10 10 00 00 00 00 00 00 00 0a 01 c1 00 b0 01 90 2a 07 24 02 80 06 00 81 5f f0 1d 00 18
+00 00 00 0f ff b0 00 00 00 00 31 8e ff 90 00 00 00 00 00 28 00 00 82 81 9f 08 00 00 12 05 02 3c 3c 00 02 08 00 1e f0 00 00
+00 00 00 00 ef 1b c6 00 00 00 03 16 7e d0 e0 40 00 00 00 01 00 00 08 00 fe 91 90 10 00 20 01 a8 00 40 00 00 81 46 d8 00 00 00
+00 00 00 20 0f 3b c4 00 03 00 18 c3 90 8e 00 00 00 00 00 00 00 20 80 01 d0 00 40 4c 82 00 0b ec 3c 30 30 08 3c 20 b1 b0 00
+80 00 00 02 24 82 20 38 20 25 02 8c f8 59 e0 00 00 00 00 00 00 00 08 15 7c 01 c0 08 c0 20 53 be 00 40 12 20 83 d6 00 1d 1c 0c
+00 00 01 20 a0 70 03 c0 20 00 06 6e f7 0f 00 00 00 00 00 00 00 80 80 02 90 00 20 02 02 00 0f 42 40 01 00 0b c0 20 98 00 00
+00 00 00 02 00 77 80 05 04 00 02 9e e9 00 00 00 00 00 00 01 00 00 08 14 d9 00 00 00 00 20 57 a4 42 00 00 00 bc 1c 03 80 00 00
+00 00 00 20 8f b8 c3 50 40 40 26 c3 e9 90 00 00 00 00 00 10 00 00 80 a4 d7 00 00 00 12 00 0f fc 00 00 00 00 25 fc 00 c0 00
+00 00 00 06 04 90 00 00 02 01 02 0d 7c 39 c0 00 00 00 00 02 80 08 08 07 60 00 00 00 00 20 53 a6 00 00 00 02 01 7c a0 00 00 00
+00 02 00 20 a0 62 c3 20 00 00 06 6c f5 0f 00 00 00 00 00 00 00 00 80 03 a0 80 00 00 06 00 0b 40 00 00 00 01 00 0f 30 00 00
+00 00 00 02 00 77 e0 00 00 00 02 9e eb 81 b0 00 00 00 00 00 00 00 18 14 db 38 00 08 00 20 57 fc 00 00 00 50 21 5e c3 98 00 00
+00 00 00 20 8f b8 04 10 10 00 18 c2 bf 0b 00 00 00 00 00 00 00 80 80 a4 df 80 10 00 02 00 0f c0 40 00 00 01 4c 0d 10 04 00
+00 00 20 02 04 b8 00 38 f2 09 02 8c ed b0 12 00 00 00 00 00 00 00 08 05 60 79 c0 00 00 60 53 e4 02 00 50 10 28 de 0b 00 00 00
+00 00 00 20 a0 78 00 12 23 00 06 6e f0 09 41 40 00 00 00 20 00 00 80 02 80 90 40 0c 02 00 0b 5c 00 00 30 00 14 3d 30 00 00
+00 00 00 02 00 77 de 01 a4 20 02 9f cd 00 1a 00 00 00 00 00 00 08 08 14 d9 71 ee 0a 80 60 57 a6 00 10 03 00 2b de a1 80 00 00
+00 00 00 20 8f b8 03 c8 00 04 18 c2 a3 80 00 00 00 00 00 00 00 00 80 00 d7 0f 00 00 02 00 0b fc 3c 02 00 02 8c 10 00 00 00
+00 00 00 02 04 b0 00 01 00 61 02 8c ff 3a 02 00 00 00 00 00 00 00 28 15 6a f9 d0 01 80 60 53 e4 08 00 56 10 28 df a0 0e 00 18
+00 00 00 20 a0 71 c3 80 00 00 09 ad d0 90 00 00 00 00 00 00 80 01 80 02 b0 80 00 80 02 00 0f 7e 00 01 00 00 14 1d 00 00 00
+00 00 00 02 00 77 c0 04 02 00 02 9f f8 71 80 00 00 00 00 00 00 00 08 14 d9 78 00 10 00 a0 57 ad c7 80 00 00 2b c7 a0 00 80 04
+00 00 00 20 00 f0 20 05 02 00 2b f6 89 0d 00 00 00 00 00 00 00 04 09 85 cb 1d 10 08 00 cb 0b 74 00 00 20 00 00 00 00 00 00
+00 00 00 02 05 36 4c 00 00 32 02 04 d8 58 00 00 00 00 00 00 00 00 00 97 cb f0 80 10 c4 08 93 bb e7 00 03 00 00 00 03 80 00 00
+00 00 08 0f f1 e1 c0 00 00 00 19 c1 a7 0e 00 00 00 00 00 00 00 00 29 c5 ab 89 00 00 00 e7 0b 82 20 00 00 00 2d 4f b1 00 00
+00 00 00 00 ef b7 3c 00 00 01 02 0d 58 80 10 00 00 00 00 00 60 00 00 04 fb f9 91 02 04 00 55 29 c2 04 40 00 2a cc 89 08 00 00
+00 00 08 20 00 b0 03 8a 20 00 09 86 d3 19 00 20 00 00 00 00 00 00 01 41 c0 0d 00 40 00 e2 07 ec 74 00 00 01 7c 28 11 00 00
+00 00 00 02 05 32 5c f9 30 00 02 9c f8 50 c0 00 00 00 00 00 00 04 02 bc 6d 00 90 00 04 08 15 b6 43 40 00 02 01 5f 90 08 00 00
+00 02 08 20 00 69 e0 00 00 00 19 c3 ab 0a 00 00 00 00 00 20 20 00 81 42 ef 1d 00 00 00 5f 0e dc 38 05 00 23 28 2f 91 80 00
+00 00 00 02 05 3b ac 00 00 01 02 0d de 58 00 00 00 00 00 00 05 00 0a bc 5f 01 94 00 00 00 55 f6 e0 00 00 10 30 1d d0 08 00 00
+00 00 00 20 00 b0 00 00 00 00 22 44 80 0e 00 80 00 00 00 00 50 80 82 82 8d 1e 00 00 00 6e 9a 4e 00 00 00 03 14 20 00 00 00
+00 00 20 02 05 36 40 00 45 00 03 1e ec 00 10 14 00 00 00 00 02 00 0a bd fe 80 90 00 00 08 59 31 c7 80 00 10 31 44 80 1c 00 00
+00 00 00 20 00 74 00 17 03 02 19 c0 a9 1e 40 00 00 00 00 00 00 04 81 42 e0 00 00 0c 02 0a 02 0c 38 01 30 03 2c 0c 01 0a 00
+00 00 00 06 05 3b 00 38 80 31 02 0d da 01 88 00 00 00 00 00 00 00 0a bd cf 10 00 00 c0 20 03 ba 00 00 03 10 22 46 80 0c 00 00
+00 00 00 20 2b b2 c3 85 00 00 19 c6 e0 1c 80 40 00 00 00 00 00 00 82 80 a0 18 20 00 12 08 73 02 00 00 00 01 5e 6c 01 e8 00
+00 00 00 02 01 b0 60 00 00 60 00 95 f9 79 f0 00 00 00 00 00 00 00 0a bc df 00 94 81 80 20 47 85 c0 00 06 00 28 4c e5 9f 00 00
+00 00 00 20 00 7c 03 80 00 20 06 55 80 10 0c 00 00 00 00 00 00 00 81 42 e0 18 00 00 02 0a 03 c6 38 60 00 01 3e ea f1 80 00
+00 00 00 02 05 3b c0 00 00 00 02 9c fd 01 80 00 00 00 00 01 40 00 0a bd ed 59 b0 08 10 20 03 bf c0 40 00 00 11 66 9d 89 04 00
+00 00 08 20 a0 f0 47 80 03 00 01 42 b0 80 20 08 00 00 00 03 00 00 00 00 00 8c 00 00 10 c5 00 34 00 00 02 0a 9c 39 b0 00 04
+80 00 00 02 af 5e 20 38 10 32 02 bd 6e 10 04 00 80 00 00 00 00 00 00 00 00 50 10 00 04 0c 55 a8 40 13 50 30 89 55 b8 00 00 8c
+00 00 00 60 50 b0 44 00 00 00 81 41 c7 0a 40 00 00 00 08 10 00 00 00 82 ef 09 80 40 00 45 de 02 7c 00 00 40 14 10 00 00 00
+00 00 00 02 af 7b 20 78 00 00 0a bc c8 71 90 00 00 00 00 02 00 01 00 1c d8 10 84 00 00 0e 53 f8 43 c0 00 20 01 47 e7 00 10 00
+00 00 00 60 a0 38 04 00 08 40 01 42 b1 00 00 40 00 00 00 10 00 00 31 c1 eb 8c 44 00 10 5f 0f 00 42 00 00 28 3a d9 19 ea 00
+00 00 00 02 af 5b 40 68 00 00 02 bc e8 f0 00 00 00 00 00 02 00 01 02 24 7d f8 10 00 00 00 55 bd c3 80 00 40 a3 d7 c9 09 00 00
+00 02 01 20 50 30 c7 c0 00 00 81 42 cb 8a 80 00 00 00 00 00 00 00 19 ce d1 8b 00 00 10 50 02 ee 00 00 00 0b 0c 5d 18 04 00
+00 00 00 02 af 5f 00 68 00 00 1a bc ea 11 f0 80 00 00 00 00 02 00 00 97 4e b8 10 04 00 0a 03 07 c7 00 00 01 91 f4 dd 98 80 00
+00 00 00 20 a0 e4 02 00 10 20 81 43 e0 0b 00 00 00 00 00 10 40 00 00 6f 87 00 40 00 00 aa 0b 86 78 70 00 08 3a fc 00 00 00
+00 00 20 06 af 56 06 64 00 00 0a bd d8 78 06 00 00 00 00 00 02 00 02 0d f9 00 0b 80 00 8a 05 e0 42 00 50 01 a3 c7 d1 98 a1 10
+00 00 00 20 50 f0 02 00 00 04 81 43 c7 0e 1c 08 00 00 00 18 08 00 20 43 9b 00 0c 00 00 05 f2 36 40 00 04 4b 0e fd 01 90 00
+00 00 00 12 af 72 06 74 00 00 0a bd d8 02 10 00 80 00 00 02 00 01 02 2c fa 80 00 40 00 8e 7f 6f c7 00 00 00 91 ce d5 9c 00 00
+00 00 01 ac 21 ba c0 00 05 00 81 43 ed 8e 00 00 00 00 00 00 00 00 17 c2 9d 0e 10 00 00 17 df 7c 30 24 08 2b 0c fd f9 81 01
+40 00 00 0a c7 32 e0 00 02 50 0a bd ec 70 14 43 80 00 00 00 60 00 00 15 cc 01 c0 00 00 02 71 b2 00 43 08 00 91 d5 cb 9d 00 30
+00 00 00 a0 d5 74 00 00 08 00 81 41 cb 88 00 80 00 00 00 00 c0 00 02 a6 89 af 00 80 00 2b 7e 4e 3c 02 0c 38 23 eb 00 00 40
+00 00 00 0a 8f 52 0e 60 00 00 0a bd 6c 78 10 04 00 00 00 01 52 08 02 2d ce 58 00 04 00 02 71 6a c8 68 00 61 80 0d 87 00 00 00
+00 00
+62 00 3f
+72 00 80
+11 00
+82 00 00
+01 03
+00 00 00 00 c0 00 00 d7
+00 00 00 00 c6 66 00 d7
+00 00 00 00 cc cd 00 d7
+00 00 00 00 d3 33 00 d7
+00 00 00 00 d9 9a 00 d7
+00 00 00 00 e0 00 00 d7
+00 00 00 00 e6 66 00 d7
+00 00 00 00 ec cd 00 d7
+00 00 00 00 f3 33 00 d7
+00 00 00 00 f9 9a 00 d7
+00 00 00 00 00 00 00 d8
+00 00 00 00 06 66 00 d8
+00 00 00 00 0c cd 00 d8
+00 00 00 00 13 33 00 d8
+00 00 00 00 19 9a 00 d8
+00 00 00 00 20 00 00 d8
+00 00 00 00 26 66 00 d8
+00 00 00 00 2c cd 00 d8
+00 00 00 00 33 33 00 d8
+00 00 00 00 39 9a 00 d8
+00 00 00 00 40 00 00 d8
+00 00 00 00 46 66 00 d8
+00 00 00 00 4c cd 00 d8
+00 00 00 00 53 33 00 d8
+00 00 00 00 59 9a 00 d8
+00 00 00 00 60 00 00 d8
+00 00 00 00 66 66 00 d8
+00 00 00 00 6c cd 00 d8
+00 00 00 00 73 33 00 d8
+00 00 00 00 79 9a 00 d8
+00 00 00 00 80 00 00 d8
+00 00 00 00 86 66 00 d8
+00 00 00 00 8c cd 00 d8
+00 00 00 00 93 33 00 d8
+00 00 00 00 99 9a 00 d8
+00 00 00 00 a0 00 00 d8
+00 00 00 00 a6 66 00 d8
+00 00 00 00 ac cd 00 d8
+00 00 00 00 b3 33 00 d8
+00 00 00 00 b9 9a 00 d8
+00 00 00 00 c0 00 00 d8
+00 00 00 00 c6 66 00 d8
+00 00 00 00 cc cd 00 d8
+00 00 00 00 d3 33 00 d8
+00 00 00 00 d9 9a 00 d8
+00 00 00 00 e0 00 00 d8
+00 00 00 00 e6 66 00 d8
+00 00 00 00 ec cd 00 d8
+00 00 00 00 f3 33 00 d8
+00 00 00 00 f9 9a 00 d8
+00 00 00 00 00 00 00 d9
+00 00 00 00 06 66 00 d9
+00 00 00 00 0c cd 00 d9
+00 00 00 00 13 33 00 d9
+00 00 00 00 19 9a 00 d9
+00 00 00 00 20 00 00 d9
+00 00 00 00 26 66 00 d9
+00 00 00 00 2c cd 00 d9
+00 00 00 00 33 33 00 d9
+00 00 00 00 39 9a 00 d9
+00 00 00 00 40 00 00 d9
+00 00 00 00 46 66 00 d9
+00 00 00 00 4c cd 00 d9
+00 00 00 00 53 33 00 d9
+00 00 00 00 59 9a 00 d9
+00 00 00 00 60 00 00 d9
+00 00 00 00 66 66 00 d9
+00 00 00 00 6c cd 00 d9
+00 00 00 00 73 33 00 d9
+00 00 00 00 79 9a 00 d9
+00 00 00 00 80 00 00 d9
+00 00 00 00 86 66 00 d9
+00 00 00 00 8c cd 00 d9
+00 00 00 00 93 33 00 d9
+00 00 00 00 99 9a 00 d9
+00 00 00 00 a0 00 00 d9
+00 00 00 00 a6 66 00 d9
+00 00 00 00 ac cd 00 d9
+00 00 00 00 b3 33 00 d9
+00 00 00 00 b9 9a 00 d9
+00 00 00 00 c0 00 00 d9
+00 00 00 00 c6 66 00 d9
+00 00 00 00 cc cd 00 d9
+00 00 00 00 d3 33 00 d9
+00 00 00 00 d9 9a 00 d9
+00 00 00 00 e0 00 00 d9
+00 00 00 00 e6 66 00 d9
+00 00 00 00 ec cd 00 d9
+00 00 00 00 f3 33 00 d9
+00 00 00 00 f9 9a 00 d9
+00 00 00 00 00 00 00 da
+00 00 00 00 06 66 00 da
+00 00 00 00 0c cd 00 da
+00 00 00 00 13 33 00 da
+00 00 00 00 19 9a 00 da
+00 00 00 00 20 00 00 da
+00 00 00 00 26 66 00 da
+00 00 00 00 2c cd 00 da
+00 00 00 00 33 33 00 da
+00 00 00 00 39 9a 00 da
+00 00 00 00 40 00 00 da
+00 00 00 00 46 66 00 da
+00 00 00 00 4c cd 00 da
+00 00 00 00 53 33 00 da
+00 00 00 00 59 9a 00 da
+00 00 00 00 60 00 00 da
+00 00 00 00 66 66 00 da
+00 00 00 00 6c cd 00 da
+00 00 00 00 73 33 00 da
+00 00 00 00 79 9a 00 da
+00 00 00 00 80 00 00 da
+00 00 00 00 86 66 00 da
+00 00 00 00 8c cd 00 da
+00 00 00 00 93 33 00 da
+00 00 00 00 99 9a 00 da
+00 00 00 00 a0 00 00 da
+00 00 00 00 a6 66 00 da
+00 00 00 00 ac cd 00 da
+00 00 00 00 b3 33 00 da
+00 00 00 00 b9 9a 00 da
+00 00 00 00 c0 00 00 da
+00 00 00 00 c6 66 00 da
+00 00 00 00 cc cd 00 da
+00 00 00 00 d3 33 00 da
+00 00 00 00 d9 9a 00 da
+00 00 00 00 e0 00 00 da
+00 00 00 00 e6 66 00 da
+00 00 00 00 ec cd 00 da
+00 00
+82 00 80
+01 03
+00 00 00 00 f3 33 00 da
+00 00 00 00 f9 9a 00 da
+00 00 00 00 00 00 00 db
+00 00 00 00 06 66 00 db
+00 00 00 00 0c cd 00 db
+00 00 00 00 13 33 00 db
+00 00 00 00 19 9a 00 db
+00 00 00 00 20 00 00 db
+00 00 00 00 26 66 00 db
+00 00 00 00 2c cd 00 db
+00 00 00 00 33 33 00 db
+00 00 00 00 39 9a 00 db
+00 00 00 00 40 00 00 db
+00 00 00 00 46 66 00 db
+00 00 00 00 4c cd 00 db
+00 00 00 00 53 33 00 db
+00 00 00 00 59 9a 00 db
+00 00 00 00 60 00 00 db
+00 00 00 00 66 66 00 db
+00 00 00 00 6c cd 00 db
+00 00 00 00 73 33 00 db
+00 00 00 00 79 9a 00 db
+00 00 00 00 80 00 00 db
+00 00 00 00 86 66 00 db
+00 00 00 00 8c cd 00 db
+00 00 00 00 93 33 00 db
+00 00 00 00 99 9a 00 db
+00 00 00 00 a0 00 00 db
+00 00 00 00 a6 66 00 db
+00 00 00 00 ac cd 00 db
+00 00 00 00 b3 33 00 db
+00 00 00 00 b9 9a 00 db
+00 00 00 00 c0 00 00 db
+00 00 00 00 c6 66 00 db
+00 00 00 00 cc cd 00 db
+00 00 00 00 d3 33 00 db
+00 00 00 00 d9 9a 00 db
+00 00 00 00 e0 00 00 db
+00 00 00 00 e6 66 00 db
+00 00 00 00 ec cd 00 db
+00 00 00 00 f3 33 00 db
+00 00 00 00 f9 9a 00 db
+00 00 00 00 00 00 00 dc
+00 00 00 00 06 66 00 dc
+00 00 00 00 0c cd 00 dc
+00 00 00 00 13 33 00 dc
+00 00 00 00 19 9a 00 dc
+00 00 00 00 20 00 00 dc
+00 00 00 00 26 66 00 dc
+00 00 00 00 2c cd 00 dc
+00 00 00 00 33 33 00 dc
+00 00 00 00 39 9a 00 dc
+00 00 00 00 40 00 00 dc
+00 00 00 00 46 66 00 dc
+00 00 00 00 4c cd 00 dc
+00 00 00 00 53 33 00 dc
+00 00 00 00 59 9a 00 dc
+00 00 00 00 60 00 00 dc
+00 00 00 00 66 66 00 dc
+00 00 00 00 6c cd 00 dc
+00 00 00 00 73 33 00 dc
+00 00 00 00 79 9a 00 dc
+00 00 00 00 80 00 00 dc
+00 00 00 00 86 66 00 dc
+00 00 00 00 8c cd 00 dc
+00 00 00 00 93 33 00 dc
+00 00 00 00 99 9a 00 dc
+00 00 00 00 a0 00 00 dc
+00 00 00 00 a6 66 00 dc
+00 00 00 00 ac cd 00 dc
+00 00 00 00 b3 33 00 dc
+00 00 00 00 b9 9a 00 dc
+00 00 00 00 c0 00 00 dc
+00 00 00 00 c6 66 00 dc
+00 00 00 00 cc cd 00 dc
+00 00 00 00 d3 33 00 dc
+00 00 00 00 d9 9a 00 dc
+00 00 00 00 e0 00 00 dc
+00 00 00 00 e6 66 00 dc
+00 00 00 00 ec cd 00 dc
+00 00 00 00 f3 33 00 dc
+00 00 00 00 f9 9a 00 dc
+00 00 00 00 00 00 00 dd
+00 00 00 00 06 66 00 dd
+00 00 00 00 0c cd 00 dd
+00 00 00 00 13 33 00 dd
+00 00 00 00 19 9a 00 dd
+00 00 00 00 20 00 00 dd
+00 00 00 00 26 66 00 dd
+00 00 00 00 2c cd 00 dd
+00 00 00 00 33 33 00 dd
+00 00 00 00 39 9a 00 dd
+00 00 00 00 40 00 00 dd
+00 00 00 00 46 66 00 dd
+00 00 00 00 4c cd 00 dd
+00 00 00 00 53 33 00 dd
+00 00 00 00 59 9a 00 dd
+00 00 00 00 60 00 00 dd
+00 00 00 00 66 66 00 dd
+00 00 00 00 6c cd 00 dd
+00 00 00 00 73 33 00 dd
+00 00 00 00 79 9a 00 dd
+00 00 00 00 80 00 00 dd
+00 00 00 00 86 66 00 dd
+00 00 00 00 8c cd 00 dd
+00 00 00 00 93 33 00 dd
+00 00 00 00 99 9a 00 dd
+00 00 00 00 a0 00 00 dd
+00 00 00 00 a6 66 00 dd
+00 00 00 00 ac cd 00 dd
+00 00 00 00 b3 33 00 dd
+00 00 00 00 b9 9a 00 dd
+00 00 00 00 c0 00 00 dd
+00 00 00 00 c6 66 00 dd
+00 00 00 00 cc cd 00 dd
+00 00 00 00 d3 33 00 dd
+00 00 00 00 d9 9a 00 dd
+00 00 00 00 e0 00 00 dd
+00 00 00 00 e6 66 00 dd
+00 00 00 00 ec cd 00 dd
+00 00 00 00 f3 33 00 dd
+00 00 00 00 f9 9a 00 dd
+00 00 00 00 00 00 00 de
+00 00 00 00 06 66 00 de
+00 00 00 00 0c cd 00 de
+00 00 00 00 13 33 00 de
+00 00 00 00 19 9a 00 de
+00 00 00 00 20 00 00 de
+00 00
+11 01
+82 00 00
+01 03
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00
+82 00 80
+01 03
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00
+11 02
+82 00 00
+01 03
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00
+82 00 80
+01 03
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00
+11 03
+82 00 00
+01 03
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00
+82 00 80
+01 03
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00
+22
+3a 5f
+01 06
+
diff --git a/fpga/SX1301_FPGA_200K_NOTCH_LBT_SPECTRAL_SCAN_915_v33.hex b/fpga/SX1301_FPGA_200K_NOTCH_LBT_SPECTRAL_SCAN_915_v33.hex
new file mode 100644
index 0000000..55bea37
--- /dev/null
+++ b/fpga/SX1301_FPGA_200K_NOTCH_LBT_SPECTRAL_SCAN_915_v33.hex
@@ -0,0 +1,1659 @@
+ff 00
+4c 61 74 74 69 63 65 00
+69 43 45 63 75 62 65 32 20 32 30 31 35 2e 30 34 2e 32 37 34 30 39 00
+50 61 72 74 3a 20 69 43 45 34 30 4c 50 31 4b 2d 43 4d 34 39 00
+44 61 74 65 3a 20 4f 63 74 20 31 37 20 32 30 31 36 20 31 31 3a 33 30 3a 32 32 00
+00 ff
+7e aa 99 7e
+51 00
+01 05
+92 00 20
+62 01 4b
+72 00 90
+82 00 00
+11 00
+01 01
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 40 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 02 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 30 00 30 00 00
+00 00 00 00 00 04 00 00 00 00 00 00 10 00 00 00 00 00 00 40 00 00 00 00 10 00 00 00 00 00 00 40 00 00 00 00 00 01 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 04 00 00 00 00 00 00 10 00 00 00 00 00 00 40 00 00 00 00 10 00 00 00 00 00 00 40 00 00 00 00 00 03 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 f0 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 03 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 08 00 00 00 10 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 04 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 08 00 00 00 00 00 00
+00 00 00 00 00 0f 22 13 00 00 00 00 3e 00 02 00 00 01 00 d8 00 00 40 00 21 c5 00 00 00 00 0c 32 21 30 00 00 0c 01 78 f5 20
+00 00 00 00 00 00 70 04 90 80 00 00 02 c0 a5 00 00 00 18 0b 81 00 00 00 01 50 a0 00 00 00 00 03 80 49 48 00 00 00 0e 0a 00 00
+00 00 18 00 00 0f 22 13 00 00 00 03 0f a5 00 01 81 8f 80 78 00 00 00 00 0d a0 50 01 80 50 00 5a 21 30 00 47 2c 00 6a f5 00
+00 00 00 00 09 00 f0 04 90 00 00 00 00 20 50 00 00 00 78 0b 01 00 00 00 00 00 05 00 00 02 00 07 00 49 40 08 02 c0 1d 0a 00 00
+00 00 30 00 01 9d 22 13 00 00 00 00 1e ea 50 00 00 05 88 38 00 00 40 00 21 e5 00 03 00 00 00 7a 21 30 00 00 00 32 cc 80 02
+00 00 01 00 00 08 78 04 90 00 00 00 03 e0 55 00 00 00 00 01 01 00 40 00 01 40 a0 00 10 00 00 03 00 49 00 00 00 00 3d 0e 52 00
+00 02 00 00 19 9d 22 13 00 00 00 c0 0e e5 00 04 00 00 01 f0 00 00 03 c0 01 a0 50 00 00 05 80 02 61 30 00 00 00 05 ce 50 00
+00 00 00 00 00 08 f8 04 90 00 00 00 00 20 50 00 00 00 90 af 80 40 00 3c 32 c0 0a 00 00 00 00 07 30 49 00 00 08 03 41 05 00 80
+00 00 00 00 00 0f a2 13 00 00 00 00 26 00 00 00 00 08 1c f0 10 04 08 06 b7 cf 50 00 00 00 0f 12 21 30 00 00 3c 30 40 00 00
+00 00 20 00 00 09 70 04 90 00 00 00 02 e0 a5 20 00 00 51 03 80 00 00 14 01 60 a0 00 00 00 70 c3 80 49 00 00 01 60 1c 0a 50 00
+00 00 00 00 00 0d a2 13 00 00 01 e0 00 00 00 00 00 09 01 50 10 00 01 c6 97 e5 00 00 00 19 00 3a 21 32 00 00 00 01 dc 50 00
+00 00 00 00 00 00 f0 04 90 00 00 02 24 00 00 00 00 04 50 a1 00 00 00 34 00 10 50 00 00 02 58 07 00 49 00 00 82 40 00 05 02 00
+00 00 00 00 98 0d a2 13 00 00 00 42 2e 00 00 00 00 00 1b 18 10 00 00 00 21 be 20 00 00 00 0a 7a 21 32 00 00 2e 20 00 24 00
+00 00 00 00 01 00 78 04 90 00 00 2c 02 c0 a5 00 00 00 00 ad 00 00 00 00 01 4e d1 00 00 00 70 03 80 49 00 08 01 40 34 e1 80 00
+00 00 10 00 90 0d a2 11 01 00 02 00 00 00 00 01 00 07 00 b0 10 00 02 e3 97 c5 00 03 00 0f 81 72 21 30 00 00 00 70 0f 03 00
+00 00 01 00 01 08 f8 04 90 00 00 1c 24 00 00 00 10 00 08 a5 00 40 00 16 40 00 50 00 30 00 b0 a7 80 49 00 00 00 04 00 b0 30 00
+00 00 00 00 81 9f f3 d5 00 00 00 00 2e ba 44 00 00 01 80 90 01 0a 02 03 8c 00 00 00 00 07 8b fa 21 30 00 00 20 7b 68 a5 00
+00 00 00 00 01 08 9c 28 10 00 00 34 2f fa 80 40 00 00 78 09 00 00 40 2c 00 40 a5 00 00 00 09 f7 80 49 10 00 c2 40 3f 05 50 04
+00 00 1a 80 80 09 7a 81 00 60 01 42 bd ba 14 01 80 08 01 b0 08 00 00 02 05 e5 00 01 80 00 18 d2 21 30 00 00 00 02 0c 50 00
+00 00 00 10 01 0f d0 3d 50 00 00 02 42 ca 02 40 00 00 90 9d 00 00 00 00 40 00 50 00 00 00 01 03 80 49 00 00 00 00 15 0a 01 00
+00 00 30 00 00 0f b3 d5 00 c0 00 12 8e da 44 00 00 50 01 70 00 00 03 60 1c 00 00 01 00 00 1a 92 21 30 00 82 00 69 7c 50 00
+00 00 01 00 00 00 90 28 10 04 00 3c 6b fa 80 40 00 20 00 d1 80 40 00 3c 00 60 a5 00 10 00 00 07 80 49 00 04 00 00 01 05 00 00
+00 02 00 00 00 01 62 95 00 00 02 40 25 b8 54 00 00 03 0c d8 00 00 00 00 04 a5 00 00 23 11 00 82 21 30 00 00 20 02 1c 50 00
+00 00 00 00 0d 0f bc 15 50 00 00 2c 02 e9 40 40 00 00 00 ef 02 00 00 00 00 00 50 00 01 02 08 03 34 49 00 00 02 c2 54 0a 00 00
+00 00 00 00 19 af 23 d5 00 00 06 03 2f 9a 44 00 08 09 00 b8 01 00 25 60 3e 8f 52 00 00 00 09 ba 21 30 00 00 00 7d 7e 50 00
+00 00 20 00 00 0e 9c 28 10 00 00 2c 6d ea 80 40 01 00 50 01 80 00 00 00 02 f0 a0 00 00 00 00 a7 80 49 00 00 00 06 41 05 00 10
+00 00 00 00 19 89 ba 81 00 00 02 06 24 da 44 00 00 05 1a f0 01 00 02 00 05 e5 00 00 10 03 98 b2 21 30 00 00 20 7a 0a 50 08
+00 00 00 00 09 00 d0 3d 50 00 00 2c 3a cf 40 40 00 00 f0 03 02 00 a0 14 20 10 50 00 00 80 01 03 80 49 00 00 03 c4 15 0a 00 00
+00 00 00 00 d8 1f 73 d5 00 00 11 c3 8e ba 44 00 10 25 81 d0 01 0a 00 00 55 8f 50 00 00 00 00 92 21 38 00 00 00 00 de f5 00
+00 00 00 00 05 0a 90 28 10 10 00 80 03 6a 80 40 02 84 00 ad 82 00 00 00 28 50 a0 00 00 00 00 07 00 49 00 00 00 00 07 0a 00 00
+00 00 30 00 d8 18 62 81 00 c0 00 c3 ad c0 50 03 00 05 81 78 00 00 01 66 c5 c5 00 01 20 03 81 fa 21 10 00 00 00 34 00 00 00
+00 00 01 00 05 0a 54 14 10 04 00 1e 25 f0 5a 00 10 00 00 a3 02 00 00 00 34 00 50 00 31 00 00 d9 00 85 00 00 00 03 c0 00 00 00
+00 00 00 00 00 d0 70 14 00 00 01 40 00 12 40 00 00 00 00 00 00 00 01 42 b5 ea 02 80 00 50 00 f7 bd 40 00 00 34 2c 5a e3 60
+c0 00 00 00 00 1f 90 02 80 00 08 02 01 ca 18 00 00 40 00 00 00 00 00 36 6d e0 f5 00 00 00 00 0b 82 80 00 00 63 e6 3c 84 34 00
+00 00 18 00 80 0f f9 58 00 04 00 06 a1 ea 00 00 00 00 00 00 00 10 c0 02 06 8a 00 00 00 00 00 7e b4 40 82 00 14 04 6e a1 40
+00 00 00 00 07 00 b7 08 00 00 20 00 02 50 50 08 00 00 00 00 00 00 00 34 00 10 a0 00 00 00 00 00 03 44 80 a0 e3 62 0d 87 a6 8c
+00 00 30 00 80 00 70 04 08 00 00 00 20 12 40 00 00 00 00 00 00 00 01 40 20 de 20 80 08 01 00 7b 81 40 00 00 04 00 58 c1 50
+00 00 01 00 01 00 90 00 84 40 00 74 01 ca 18 00 00 02 00 00 00 00 00 02 2d db d1 01 01 00 00 90 80 14 40 00 00 20 3c 9c b6 08
+00 02 00 00 18 07 b8 b8 00 0e 01 c0 21 a0 50 00 00 00 00 00 00 00 11 42 95 ea 52 00 00 01 81 02 81 40 00 00 06 02 ee e5 40
+80 00 00 00 00 00 36 6f 40 00 a0 02 02 c0 0a 00 00 00 00 00 00 00 00 02 6d c0 55 00 00 00 00 93 00 28 00 00 03 42 c7 8a 46 14
+00 00 00 00 30 1d 38 41 08 00 00 00 05 8a 02 00 00 00 00 00 00 02 00 e2 21 8a 02 00 00 07 81 32 bd 40 00 a0 06 00 fe a0 40
+00 00 20 00 00 08 50 0c 10 00 00 24 00 10 a0 00 0a 00 00 00 00 00 40 00 00 d0 50 00 00 00 70 cb 42 80 00 04 00 00 04 0f ac 10
+00 00 00 00 30 d7 fc 00 00 02 01 e2 3d ca 50 00 10 20 00 00 00 00 c0 00 1f af 50 00 00 00 09 d3 34 40 80 00 16 01 6e a1 61
+80 00 00 00 00 0e 37 40 40 00 00 0e 43 e0 55 00 00 84 00 00 00 00 00 2c 00 c0 50 08 00 00 70 db 02 80 00 00 00 03 45 9b 54 00
+00 00 00 00 01 eb 76 00 00 00 00 47 86 aa 00 00 10 00 00 00 00 40 00 60 24 98 00 00 00 18 01 02 94 00 00 00 00 20 5b c1 60
+00 00 00 00 03 00 f7 80 00 00 0a 02 40 20 a0 00 80 82 00 00 00 04 00 24 01 5b 00 00 00 00 f0 e5 42 80 20 00 00 04 3d 9c b4 08
+00 00 10 00 79 eb a1 00 09 00 e0 42 ad ca 50 00 00 20 00 00 00 00 01 c0 24 e8 00 30 00 01 00 d7 74 40 4c 00 24 63 ee e5 41
+00 00 01 00 00 10 3c 34 00 00 00 02 64 c0 aa 00 00 05 00 00 00 00 00 24 03 40 00 00 00 00 90 fb 2e 80 00 c0 00 40 37 8a 46 90
+00 00 00 00 18 0d 2a 95 00 00 02 00 5c ca 04 00 00 00 00 00 00 00 02 07 de 8b 7c 80 11 83 1a db bd 40 00 01 26 00 40 ff 40
+00 00 00 00 00 0a 34 17 d0 00 00 3c 20 c0 fa 40 00 00 00 00 00 00 00 04 61 68 12 42 02 00 f1 05 02 80 00 00 03 c0 0c 00 0c 00
+00 00 18 00 f8 01 73 c1 00 60 03 c6 c0 8e 24 00 00 00 00 00 00 60 02 02 9c 99 5c 00 00 00 00 5b a0 04 8a 00 4e 60 00 5a 40
+00 00 00 00 01 80 18 3e 90 00 00 2e 29 dc d1 40 00 00 00 00 00 00 00 04 6f cf 56 40 00 08 00 f1 43 94 00 a0 02 64 04 0a 5c 00
+00 00 00 00 81 85 70 15 02 00 00 c7 80 ec 54 00 03 80 00 00 00 c0 01 46 1e 8b 7c 00 00 40 1e 12 61 40 10 00 40 00 59 01 10
+00 00 00 00 01 0a bc 17 d0 00 00 00 02 48 ca 41 01 00 00 00 00 04 80 36 00 e9 12 40 00 07 01 0f 72 00 00 00 00 00 0c b0 00 00
+00 02 00 00 01 8d 62 81 00 00 00 00 24 8c f0 00 00 00 00 00 00 00 00 66 14 99 5c 00 00 2f 00 03 81 42 00 80 20 61 6c f5 00
+00 00 00 00 00 40 18 3d 52 00 00 0c 00 5f 4b 00 00 00 00 00 00 00 01 00 02 6f 56 40 80 05 f0 07 40 28 00 00 11 c4 02 0f 50 00
+00 00 00 00 80 19 fa 81 00 00 d2 60 16 c8 70 20 10 80 00 00 00 00 00 00 3e 9b 7c 00 00 00 0e fb bd 40 00 00 20 38 18 a0 00
+00 00 20 80 05 08 14 3e 98 02 00 c4 00 00 87 00 02 80 00 00 00 02 80 1c 3b e8 12 48 08 00 00 05 42 80 00 00 08 44 0d 05 00 00
+00 00 00 00 80 85 62 80 00 00 01 c0 14 c8 70 20 00 00 00 00 00 00 0a 00 56 99 5c 00 28 07 80 1b a0 00 80 00 40 01 6c fa 00
+00 00 00 00 0b 10 08 28 0c 00 08 02 00 00 87 00 00 00 00 00 00 00 01 6c 21 4f 56 40 01 00 98 01 c3 94 80 00 08 00 02 0f a0 00
+00 00 00 00 00 09 fb d5 00 00 02 00 4f 88 70 20 00 50 00 00 00 04 00 60 3e 9b 7d 00 00 00 0e 37 3e c0 00 02 04 00 18 fa 00
+00 00 00 20 00 00 d4 14 12 00 00 1c 38 10 87 00 00 00 00 00 00 00 20 00 22 6d 12 40 00 00 11 81 af fc 00 00 00 00 0d 0f 50 00
+00 00 30 00 10 1d b2 81 00 40 00 00 15 88 70 20 00 00 00 00 00 c0 80 03 f6 9d 14 00 00 00 00 83 81 40 04 80 04 00 5f 85 00
+00 00 03 00 00 88 18 3d 50 04 00 00 00 30 87 08 00 00 00 00 00 04 00 00 6b e9 47 40 01 08 f0 05 40 28 20 44 b0 00 2c ad 50 00
+00 00 80 30 d1 88 73 45 00 00 e0 40 26 ec 10 00 00 80 00 00 00 00 02 00 01 ea 00 00 00 0f 01 72 21 30 00 02 1e 03 fd fd 00
+00 00 20 00 01 8d 56 b8 90 00 02 02 00 de c7 00 00 00 00 00 00 00 08 14 01 c0 50 00 00 00 f0 f5 24 49 0c 00 00 00 34 f5 80 80
+00 00 18 00 00 01 6a 95 00 00 21 40 0c ee 22 20 00 00 00 00 00 00 00 07 9e ea 00 01 80 08 01 f2 21 30 00 00 0e 29 ec f5 00
+08 00 04 00 00 00 50 15 50 00 40 02 00 10 e2 00 00 00 00 00 00 10 00 00 00 20 a0 00 00 00 f0 eb 20 49 04 00 00 20 3c 05 00 00
+00 00 10 00 50 ad b3 d5 00 00 00 00 3e cf 50 80 00 00 00 00 00 00 00 00 16 aa 50 0b 00 05 18 12 61 38 00 04 00 2f f8 81 02
+00 00 01 00 05 1b 50 28 10 00 00 00 00 e0 a0 00 00 00 00 00 00 00 00 64 00 40 55 00 10 00 08 05 20 49 00 00 60 06 bc 0d 10 00
+00 01 00 00 38 03 6a 95 00 00 00 00 1e c0 50 80 03 00 00 00 00 00 03 e0 3e ef 52 00 00 01 80 d2 21 30 00 00 60 2b 5e e5 00
+00 00 00 00 0d 80 18 15 50 00 00 00 00 00 05 00 00 00 00 00 00 40 00 1c 03 d0 ff 00 00 00 00 0b a0 49 00 10 0b c4 1f 88 02 00
+00 00 00 00 18 db 23 d5 00 04 03 e2 c1 fb 10 10 00 00 00 00 00 00 01 e0 26 cf 00 00 00 03 81 12 6d f0 00 00 a0 3a fa 05 00
+08 00 00 80 00 18 5c 28 10 02 00 0e 2a cc 72 00 08 01 00 00 00 42 00 00 00 e0 a5 00 08 28 08 c1 33 7b 01 00 11 44 0c 05 50 10
+00 00 00 00 99 83 e8 15 00 00 03 60 1e c0 50 00 00 00 00 00 00 12 00 00 57 c8 70 a0 00 08 1d da 21 30 00 20 9e 04 ee f7 00
+00 00 00 03 01 00 00 01 50 00 00 0c 00 20 05 08 00 00 00 00 00 00 00 24 3c 10 87 00 00 00 10 8b 20 49 00 00 10 63 ef bf f0 00
+00 00 01 02 00 0d 73 d5 00 0c 11 e7 e5 ca 00 08 00 50 00 00 00 00 01 c6 80 18 10 00 00 09 80 12 61 30 00 40 00 72 7c a7 02
+08 00 00 00 40 00 58 28 18 00 a0 80 34 c0 f5 00 00 00 00 00 00 00 00 02 01 cc 42 00 00 80 10 05 34 49 00 08 00 06 4e 0a 20 80
+00 00 30 00 90 0d aa 81 00 00 01 42 c0 c0 50 08 00 00 00 00 00 04 0b 62 5d ca 00 03 28 07 80 1a 2d f0 00 20 1c 7a 1e f5 00
+00 00 03 00 87 80 74 3e 90 00 00 24 2a c0 0a 00 00 00 00 00 00 40 a1 1c 68 10 a0 00 31 00 08 03 a3 7b 80 04 01 c4 1d 0f a2 10
+00 00 00 00 38 87 67 fc 00 00 00 00 56 e5 f4 00 00 00 00 00 00 00 06 00 1c ca 54 00 00 28 00 9a 2d d0 00 80 06 03 6e e2 41
+00 00 00 00 00 00 3b be c0 40 00 00 20 10 5f 60 00 00 00 00 00 40 00 04 34 59 6a 40 00 00 10 03 a3 7b 10 04 00 02 67 9c 35 84
+00 00 18 00 50 08 01 f9 08 60 01 e0 66 8c 10 01 80 00 00 00 00 70 0a 00 45 8f 50 01 90 00 0e 07 03 c0 0a 04 14 06 7e e2 40
+80 00 00 00 00 8b b0 2f 50 00 00 24 35 7f 42 08 00 00 00 00 00 80 01 04 3d c0 ff 01 02 80 01 00 00 3c 20 20 02 63 76 8c 34 00
+00 00 30 08 50 0f 71 41 00 c0 00 07 d5 85 00 00 00 00 00 00 00 00 00 00 01 a2 00 31 00 00 0e 00 00 00 00 00 00 23 6e e3 40
+00 00 03 00 00 80 98 29 50 0c 00 00 78 20 50 00 00 00 00 00 00 80 00 00 34 c0 10 00 30 30 00 00 00 00 00 00 00 04 1e d4 34 08
+00 02 00 00 00 07 b0 01 00 00 01 40 2d 8a 50 20 00 00 00 00 00 00 21 c0 05 8e 70 00 00 00 00 00 00 00 00 a0 46 71 cc a0 00
+00 00 00 00 0d 00 f2 42 10 00 00 2e 01 50 80 00 00 40 00 00 00 00 00 1c 00 ce d3 01 00 00 00 00 00 00 00 00 00 02 c5 0f a0 00
+00 00 00 00 00 03 e9 69 00 00 02 00 75 a0 20 00 00 00 00 00 00 00 00 47 4c bc 74 00 09 80 00 00 00 00 01 00 00 05 db e3 40
+00 00 20 00 03 0a 5b 56 d0 00 00 1c 36 6b 00 08 00 00 00 00 00 40 00 be 20 78 c2 40 01 00 00 00 00 00 00 00 00 42 3d c4 36 00
+00 00 00 00 51 80 79 54 00 00 00 00 0f fd 10 00 00 00 00 00 00 00 08 40 05 9f 70 00 10 00 00 00 00 00 00 00 20 07 5a f1 40
+00 00 00 00 09 00 f0 2a 80 00 00 3c 03 ca d2 00 00 00 f0 00 00 00 01 40 01 ca ff 00 00 80 d0 00 00 00 00 00 00 42 36 eb 06 04
+00 00 00 00 00 89 70 14 08 00 00 06 20 fd 10 00 08 00 00 00 00 00 01 c0 1c c4 50 20 00 20 00 00 00 00 00 c0 1c 77 6f e3 40
+00 00 00 00 00 0a 94 21 42 00 00 00 3d dc e2 00 01 01 00 00 00 40 00 0e 02 c0 85 00 00 04 00 00 00 00 00 0a 01 e3 76 d4 34 04
+00 00 30 00 50 07 b7 bc 00 40 01 c0 2d a5 20 23 00 00 00 00 00 40 00 00 3d 85 b0 33 00 01 00 00 00 00 04 0c 04 03 dc a0 00
+00 00 01 00 00 00 f2 3f c0 24 00 00 01 60 51 00 10 00 00 00 00 0c 00 00 00 d0 02 00 30 00 08 00 00 00 00 40 00 00 05 0f a0 00
+04 00 00 00 50 08 02 95 04 10 03 c6 ec b7 47 80 00 00 00 00 08 80 00 00 1e ef a0 00 10 55 00 5e 3d 40 00 40 00 64 cb 00 70
+c0 00 00 00 00 8b d0 16 90 11 00 44 2e 58 50 40 00 00 00 00 00 00 02 00 00 10 fa 00 03 00 58 b0 43 d4 00 00 00 02 3e b1 05 9c
+00 00 18 00 70 07 a3 e8 00 60 82 02 95 ac 00 00 00 00 00 00 00 a0 16 00 0c a8 10 20 10 05 1e 9a bd c0 02 46 26 05 4e e2 40
+40 00 00 00 00 80 04 3e 80 00 00 2c 33 fe fc 00 00 00 00 00 00 1a 0c bc 03 40 8b 10 02 80 08 b3 e3 fc 00 a0 00 43 97 cc 34 08
+00 00 00 00 00 01 3b fc 48 c0 01 42 ed a4 77 b0 00 00 00 00 00 00 01 40 5f a8 00 00 00 08 0b 5e 17 c0 00 20 04 79 4e e2 40
+40 00 00 00 00 00 34 3b c0 4c 00 3e 7a 50 42 41 00 00 00 00 00 40 00 00 20 1f 80 00 00 00 b1 d0 41 7c 00 04 03 e4 35 9c 34 00
+00 02 00 00 79 83 33 fc 40 10 00 02 c4 aa 00 00 00 00 00 00 00 00 a0 00 40 0f 04 00 00 00 00 3b 3d 40 80 40 00 75 5c e2 40
+00 00 00 00 00 80 14 3d 40 01 00 00 7f ca db 00 00 00 00 00 00 80 00 00 2c 00 f0 c0 40 00 d0 97 82 04 00 02 01 c7 57 9c 34 04
+00 00 04 00 80 11 63 d4 00 00 e5 40 05 89 10 20 00 00 00 00 00 00 02 00 37 ef 70 00 20 09 80 1b 3f c8 c0 0a 06 25 5b e2 40
+00 00 20 40 05 0a 00 3d 40 00 00 02 2c 50 e3 00 00 00 00 00 00 40 04 bc 03 ef ff 01 80 00 10 09 03 dc 40 00 00 06 f5 8c 34 18
+00 00 03 80 00 00 32 bc 00 00 00 00 26 ea 35 24 28 00 00 00 00 00 10 00 5d c0 50 80 00 07 01 13 bd c0 00 80 2e 01 4d e2 40
+00 00 00 18 00 00 10 17 c8 00 00 3c 03 60 03 48 41 00 00 00 00 40 01 00 20 30 05 00 00 00 00 ed 2b fc 02 04 01 c2 17 8c 36 00
+08 00 00 00 00 11 63 d4 00 02 03 47 dc cf 50 00 00 00 00 00 08 00 00 e2 1f af 52 00 00 09 01 5b a8 00 00 00 00 25 6c a0 00
+00 00 00 00 00 0a 90 3f c0 00 00 06 60 60 ff 00 00 00 00 00 00 00 40 02 3c d0 ff 08 00 02 70 f0 c2 80 04 00 00 07 01 0a 02 10
+00 00 10 00 58 00 03 fc 04 c0 14 00 04 c5 04 20 00 00 00 00 00 40 02 47 9d e2 00 20 00 20 00 00 00 00 0c 00 00 02 6e a4 42
+00 00 03 00 00 00 00 3f c8 14 00 80 02 70 10 40 80 00 00 00 00 44 00 3c 40 20 20 00 80 04 00 00 00 00 00 50 04 00 0f 0e 56 08
+40 00 00 00 91 81 22 80 00 00 00 00 40 aa f6 00 00 00 1e 80 00 00 04 06 01 af 04 00 00 00 08 72 21 30 00 00 00 01 5c 85 00
+00 00 20 00 09 0e 14 00 00 00 02 00 2b c0 5f 40 00 00 00 03 00 00 00 00 00 00 f0 40 00 00 01 03 00 49 0c 00 00 02 dc 9e a0 00
+00 00 18 00 80 09 b8 0d 0d 60 01 40 24 e0 00 01 80 00 00 80 00 60 02 60 00 cf 04 01 82 00 00 72 21 30 00 00 1f 03 6e c1 02
+08 00 00 00 01 00 30 28 d8 20 02 2c 00 7d 2e 00 00 00 00 05 00 01 00 04 00 00 f0 40 00 00 00 09 00 49 00 00 00 03 cf 0e 60 00
+68 04 30 00 80 c3 b9 09 25 c0 02 00 4d 8f 00 80 00 00 00 80 00 02 00 07 80 cf 04 0b 00 00 19 52 21 30 00 44 26 7b 7d a7 00
+03 82 83 00 0b 10 76 62 d2 04 00 3c 2a 60 aa 00 00 20 00 c5 00 00 00 00 40 00 f0 40 10 00 00 83 80 49 00 02 02 40 16 ea 20 00
+00 73 00 00 18 0d ab 04 00 00 04 07 20 82 00 00 04 0f 00 00 00 00 62 00 00 af 04 00 10 01 99 52 21 30 00 00 86 31 5c c5 02
+00 00 00 00 00 8c f7 f9 40 00 00 80 00 5d 10 00 00 00 d8 09 00 00 80 1c 00 10 f0 40 00 82 00 89 80 49 00 00 00 32 c1 0c 50 00
+00 00 00 00 00 07 6b e8 00 00 10 03 c6 aa 00 00 00 07 00 00 00 00 02 60 00 8f 04 00 00 50 01 7a 21 30 40 00 00 05 ce 03 02
+00 00 20 00 00 00 0c 3e 80 00 00 80 78 10 a0 00 00 00 08 0f 00 00 00 04 00 10 f0 40 00 02 90 f3 00 49 00 00 00 03 f5 05 31 00
+48 00 00 00 18 01 6b d4 00 00 08 00 00 85 00 00 80 00 00 00 00 00 e0 c0 41 8f 04 10 00 00 00 5a 21 30 00 06 04 28 00 00 00
+00 c0 00 00 01 00 10 3f c0 00 00 40 02 d0 a0 08 00 00 90 0d 00 00 00 02 20 00 f0 61 40 00 00 09 00 49 00 00 00 26 00 00 00 00
+00 00 00 00 18 f1 3c 08 00 00 00 e2 06 b1 f0 10 00 07 9e 00 00 00 00 03 01 8f 04 00 00 49 80 5a 21 30 01 0c 04 26 f8 f5 00
+08 02 c0 00 00 08 16 85 40 00 00 00 43 d8 1a 00 00 00 08 07 00 00 00 00 40 00 f0 41 00 02 10 03 80 49 00 10 00 63 ee 0a 00 00
+40 00 30 00 00 00 39 6d 08 c0 03 c0 3d a8 10 23 00 01 00 00 00 c0 c1 c0 7d da 50 03 00 09 00 5a 21 12 40 00 14 00 d8 42 02
+00 00 01 00 00 09 50 29 d0 4c 00 04 01 d0 d1 00 30 00 08 03 00 0c 00 02 3b fc 85 01 30 04 10 09 80 49 05 00 00 00 1f 0e 21 00
+00 00
+11 01
+01 01
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 40 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 04 00 00 00 00 00 00 10 00 00 00 00 00 01 c0 00 00 00 00 10 00 00 00 00 00 00 40 00 00 00 00 0d 01 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 00 00 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 81 00 00 00 00
+00 00 00 00 00 04 00 00 00 00 00 00 10 00 00 00 00 00 00 00 00 00 00 80 30 00 00 00 00 00 00 40 80 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 05 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 30 00 00 00 00 00 00 00 00 00 00 00 00 00 80 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 04 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 02 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 05 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 10 00 00 8b c3 d5 00 40 00 02 06 0f 54 00 00 00 00 00 00 40 00 02 25 0a 04 03 00 00 08 38 3d 52 0c 00 00 22 d0 a0 40
+00 00 03 00 00 19 fe a8 10 04 00 00 05 7a a0 40 00 00 00 00 00 0c 00 06 04 5a f5 40 30 00 10 15 ba 81 00 40 00 60 47 af 54 00
+00 00 00 00 00 85 c1 41 00 00 00 42 35 d7 24 00 00 00 00 00 00 00 00 02 2f 0f 54 00 00 00 08 b8 3d 50 00 00 00 61 f0 50 48
+00 00 00 00 01 81 bf bd 50 00 00 26 06 1e b1 40 02 80 00 00 00 00 00 06 07 ee a0 40 00 00 18 1f ea 81 00 00 00 67 ed ef 54 00
+00 00 00 00 11 05 35 c9 00 00 00 00 16 05 04 00 00 00 00 00 00 00 02 c2 e5 0f 54 00 00 00 0f 30 3d 50 00 00 00 01 60 50 40
+00 00 00 00 00 0e 86 ec 50 00 00 00 02 da f5 40 00 38 00 00 00 00 00 20 01 ec a0 40 00 00 01 a5 e2 81 00 00 00 00 3d ef 54 00
+00 02 00 00 00 0d 81 41 00 00 00 02 b4 d7 24 00 20 00 00 00 00 00 00 02 9e 05 04 00 00 00 80 b0 3d 50 00 00 00 43 60 50 40
+00 00 00 00 00 00 3e bd 50 00 00 00 00 1a b1 40 00 00 00 00 00 00 00 00 04 5a f5 40 00 00 70 0d aa 81 00 00 00 07 8d af 54 00
+00 00 00 00 10 0f 75 c9 00 00 00 40 3f 05 04 00 00 00 00 00 00 00 00 40 27 0f 54 00 00 01 00 fc 14 10 00 00 04 03 f0 50 40
+00 00 20 00 09 8a 02 ec 50 00 00 26 60 ca f5 40 00 00 00 00 00 00 00 20 61 5a a0 40 00 00 99 8b ab d5 00 00 03 c6 1c af 54 00
+00 00 00 00 00 07 c1 41 00 00 01 40 1d d7 24 00 00 00 00 00 00 00 00 40 2d 0a 04 00 00 01 00 d4 14 10 00 00 04 01 f0 50 40
+00 00 00 00 00 18 3b bd 50 00 00 20 60 0e b1 40 00 00 00 00 00 00 00 20 62 4e f5 40 00 00 81 83 3b d5 00 00 02 06 0c ef 54 00
+00 00 00 00 00 0b 43 d5 00 00 02 c0 1e 05 04 00 00 00 00 00 00 00 00 00 3e 05 04 00 00 05 00 30 3d 50 00 00 1c 01 60 50 40
+00 00 01 80 00 00 f7 a8 10 06 00 20 00 ce f5 40 00 00 00 00 00 06 00 00 02 ee f5 40 1a 00 80 07 6a 81 00 60 00 02 9c ef 54 00
+00 00 00 00 10 01 c3 e9 00 00 00 00 2c 0f 54 00 00 00 00 00 00 00 01 44 1e 05 04 00 00 00 00 b4 3d 50 00 00 00 03 d0 f5 40
+00 00 00 00 08 00 3f a8 10 00 00 04 01 ca a0 40 00 10 00 00 00 00 00 14 7a 4a f5 40 00 00 00 0d 72 81 00 00 00 00 15 8a 04 00
+00 00 10 00 00 8f c1 41 00 40 00 02 3d 05 04 00 00 00 00 00 00 40 00 02 06 0f 54 01 00 0f 08 78 3d 50 0c 00 02 23 f0 50 40
+00 00 01 00 00 01 b6 bd 50 04 00 00 06 fa f5 40 00 38 00 00 00 0c 00 00 65 fa a0 40 10 00 00 1d ea 81 00 c0 01 c0 7d af 54 00
+00 00 00 00 00 85 75 c9 00 00 00 02 15 c7 24 00 00 00 00 00 00 00 00 42 16 0f 54 00 00 00 08 38 3d 50 00 00 00 61 70 50 40
+00 00 00 00 01 81 87 ac 50 00 00 06 06 1f b1 40 00 00 00 00 00 00 00 26 65 ea a0 40 00 00 18 1f ea 81 00 00 00 67 e7 ef 54 00
+00 00 00 00 00 05 81 41 00 00 02 40 14 05 04 00 00 00 00 00 00 00 03 c0 3c 05 04 00 00 0f 00 f0 14 10 00 00 00 01 60 50 40
+00 00 00 00 00 00 b6 bd 50 00 00 00 02 fa f5 40 00 00 00 00 00 00 00 00 01 5a f5 40 00 00 00 0b eb d5 00 00 00 00 3d af 54 00
+00 02 00 00 00 ed 35 c9 00 00 00 00 34 c7 24 00 38 00 00 00 00 00 00 00 3c a7 24 00 00 00 00 d0 14 10 00 00 00 03 60 50 40
+00 00 00 00 00 01 06 ac 50 00 00 00 00 1b b1 40 01 00 00 00 00 00 00 00 00 1a b1 40 00 00 58 07 eb d5 00 00 00 00 07 af 54 00
+00 00 00 00 10 0f c1 41 00 00 00 42 fd 05 04 00 00 00 00 00 00 00 00 40 07 0f 54 00 00 01 00 f4 14 10 00 00 04 03 f0 50 40
+00 00 20 00 09 98 32 bd 50 00 00 26 60 ea f5 40 00 00 00 00 00 00 00 26 29 ca a0 40 00 00 99 83 ab d5 00 00 02 66 1c af 54 00
+00 00 00 00 10 07 75 c9 00 00 00 40 1d c7 24 00 00 00 00 00 00 00 13 64 16 0f 54 00 00 01 00 38 3d 50 01 0a 06 03 d0 a0 40
+00 00 00 00 08 18 03 ac 50 00 0c 20 60 0f b1 40 04 10 00 00 00 00 00 9e 29 da a0 40 00 00 81 8f 32 81 00 10 02 e6 04 ef 54 00
+00 00 00 00 90 05 81 41 00 00 00 c0 14 05 04 00 00 00 00 00 00 00 60 00 05 0f 54 00 00 07 0a 74 3d 50 00 00 14 42 40 f5 40
+00 00 01 80 00 0a 33 bd 50 06 00 20 00 ee f5 40 00 00 00 00 00 06 00 00 01 da a0 40 18 00 80 0f 62 81 00 60 00 06 bd 8a 04 00
+00 00 00 00 00 0b 43 d5 00 00 00 00 0d 0f 54 00 04 00 00 00 00 00 00 20 15 0f 54 00 00 00 00 d0 14 12 00 00 00 01 60 50 40
+00 00 00 00 00 00 56 28 10 00 00 00 03 5a a0 40 02 80 00 00 00 00 00 1e 01 de a0 40 00 00 00 0f ab d5 00 00 01 60 06 af 54 00
+00 00 10 00 01 8f c1 41 00 40 00 02 0e 0f 54 00 00 00 00 00 00 40 00 02 3d 05 04 03 00 00 8d 07 2c 58 0c 00 1c 21 e0 f5 40
+00 00 03 00 00 0f fe bd 50 0c 00 00 05 78 a0 40 00 00 00 00 00 0c 00 00 06 7a f5 40 30 00 10 11 ea c5 00 40 02 60 77 ca 04 00
+00 00 00 00 00 85 7d c9 00 00 00 02 15 f7 24 00 00 00 00 00 00 00 00 02 01 8b 14 00 00 05 00 b4 3e 90 00 00 00 61 d0 50 40
+00 00 00 00 01 81 87 ec 50 00 00 06 26 1e b1 40 00 00 00 00 00 00 00 06 04 ff b1 40 00 00 18 0b 7a 81 00 00 00 03 ff ef 54 10
+00 00 00 00 98 05 81 41 00 00 02 c0 16 05 04 00 00 00 00 00 00 00 02 c0 14 c4 24 00 00 00 18 30 3d 50 00 00 2c 01 d0 f5 40
+00 00 00 00 05 80 fe bd 50 00 00 20 03 da f5 40 00 38 00 00 00 00 00 26 02 61 e7 40 00 00 00 b5 ba 81 00 00 02 00 3e 8a 04 00
+00 02 00 00 00 0d 3d c9 00 00 00 20 34 f7 24 00 00 00 00 00 00 00 00 00 34 87 24 00 00 00 88 10 3e 90 00 00 00 23 c0 50 40
+00 00 00 00 00 00 06 ec 50 00 00 04 00 1a b1 40 00 00 00 00 00 00 00 00 00 1b b1 40 00 00 71 bb 3a 81 00 00 00 00 1f af 54 00
+00 00 00 00 10 0f c1 41 00 00 00 40 3f 05 04 00 00 00 00 00 00 00 00 40 3d 05 04 00 00 00 00 38 3d 50 00 00 06 03 f0 50 40
+00 00 20 00 09 98 7a bd 50 00 00 26 61 ca f5 40 00 00 00 00 00 00 00 20 60 6a f5 40 00 00 19 85 6a 81 00 00 02 46 06 af 54 00
+00 00 00 00 10 07 7d c9 00 00 00 40 1d f7 24 00 00 00 00 00 00 00 00 40 1d 87 24 00 00 00 00 b4 3e 90 00 40 04 02 50 a0 40
+00 00 00 00 08 18 03 ec 50 00 00 21 60 0e b1 40 00 00 00 00 00 00 00 20 60 0f b1 40 00 00 01 83 32 81 00 02 16 06 34 ef 54 00
+00 00 00 00 00 05 81 41 00 00 01 44 16 05 04 00 00 00 00 00 00 00 01 c4 14 05 04 00 00 01 00 03 2c 50 00 40 2c 24 00 f0 40
+00 00 01 80 00 00 7b bd 50 06 00 00 29 ce f5 40 00 00 00 00 00 06 00 20 60 6e f5 40 18 00 80 01 3a c5 00 62 02 02 81 8f 04 00
+00 00 00 00 00 0f 03 d5 00 00 00 00 3d 0f 54 00 28 00 00 00 00 00 00 00 05 0f 54 00 00 01 00 14 3e 90 00 00 00 2a d0 f5 40
+00 00 00 00 00 00 d7 28 10 00 00 00 01 58 a0 40 01 10 00 00 00 00 00 00 03 58 a0 40 00 00 80 03 72 81 00 00 00 60 45 8a 04 00
+00 00 10 00 00 8f c1 41 20 40 02 42 1f 0f 56 00 00 00 00 00 00 c0 00 03 b7 05 04 01 00 00 08 fc 14 10 04 00 00 3c c0 5a 40
+00 00 03 00 00 01 b6 bd 50 0c 00 00 07 78 a0 40 00 00 00 00 00 0c 00 0e 06 5a f5 60 30 00 00 1b 6b d5 00 c0 00 00 00 0a 54 00
+00 00 00 00 00 85 75 c9 00 00 00 02 07 0f 54 00 00 00 00 00 00 00 80 02 15 97 24 00 00 00 08 57 5c 90 00 00 00 00 10 0f 40
+00 00 00 00 01 81 87 ac 50 00 00 06 05 f8 a0 40 00 00 00 00 00 00 00 06 06 1a b1 40 00 00 00 18 7a c5 00 00 00 06 01 e0 f4 00
+00 00 00 00 70 05 81 41 00 00 00 c0 3c e7 24 00 00 00 00 00 00 00 00 00 16 05 04 00 00 07 00 58 14 10 00 00 36 24 7a 82 00
+00 00 00 00 0d 80 b6 bd 50 00 00 00 02 1b b1 40 00 00 00 00 00 00 00 00 02 5a f5 40 00 00 80 0b 6b d5 00 00 07 60 1d b8 10 08
+00 02 08 00 00 cd 35 c9 00 20 00 00 34 05 04 00 00 00 00 00 00 20 00 00 34 97 24 00 80 07 0c d3 5c 90 02 01 00 27 40 80 00
+00 00 00 00 00 01 06 ac 50 00 00 00 01 fa f5 40 00 00 00 00 00 00 00 00 00 1a b1 40 00 00 00 10 6a c5 00 00 08 e0 25 ae 00 a0
+00 00 00 00 10 0f c1 41 00 00 60 43 fd e7 24 00 00 00 00 00 00 00 00 42 3f 05 04 00 00 01 00 fc 14 10 00 00 2c 40 30 d1 00
+00 00 00 00 09 98 32 bd 50 00 00 26 60 0b b1 40 00 00 00 00 00 00 00 26 64 4a f5 40 00 00 99 83 2b d5 00 00 00 03 0c ad 10 20
+80 00 00 00 10 07 75 c9 00 00 00 40 1d 05 04 00 00 00 00 00 00 00 00 40 1d 97 24 00 00 01 00 07 6c 50 00 00 24 3a e0 aa 00
+00 00 00 00 08 18 03 ac 50 00 00 20 61 ee f5 40 00 00 00 00 00 00 00 20 60 0e b1 40 00 00 81 81 3a c5 00 00 00 07 35 ca 50 00
+80 01 00 00 00 05 81 41 00 00 c0 06 d4 e7 24 00 00 00 00 00 00 00 00 00 16 05 04 00 00 00 00 18 3e 90 00 00 00 20 d0 ca 00
+08 00 01 80 00 00 33 bd 50 06 02 00 28 0f b1 40 00 00 00 00 00 06 00 01 00 4e f5 40 18 00 00 03 32 81 00 60 20 00 40 cc 50 20
+10 02 00 00 00 0b 02 81 00 00 80 40 05 0f 54 00 04 00 00 00 00 10 40 02 25 0f 54 00 00 00 10 b4 3d 50 10 00 00 02 40 55 00
+00 00 00 00 00 00 3a bd 50 00 00 00 01 5a a0 40 00 00 00 00 00 00 00 00 01 5e a0 40 00 00 18 a5 22 81 00 80 00 60 35 ca 50 00
+00 00 00 00 00 00 00 00 00 40 00 00 05 00 f0 00 00 00 00 00 00 c0 00 40 26 01 24 02 00 00 00 56 3f c2 08 00 00 00 1c 03 00
+00 00 00 00 05 80 00 00 00 04 00 00 03 68 f0 00 00 00 00 00 00 0c 00 3c 01 68 84 40 30 00 58 0d f3 dc 00 c0 00 00 00 80 30 00
+00 00 00 00 00 00 00 00 00 00 00 04 36 d0 c4 00 00 00 00 00 00 0a 20 40 16 01 24 00 80 50 88 b4 15 70 02 00 00 02 40 ff 00
+00 00 00 00 00 00 00 00 00 00 00 00 22 fa 5e 40 00 00 00 00 00 00 40 26 01 68 84 c0 00 02 11 b9 ea 95 02 00 00 07 0c 0a 50 00
+00 00 00 00 00 a1 2f 30 00 00 00 00 2f 00 c4 00 00 00 00 00 00 00 00 00 24 01 24 00 00 00 08 1b d6 10 00 00 00 01 4c 42 00
+00 00 00 00 00 01 da 0c c0 10 00 00 63 78 5e 42 00 00 00 00 00 00 00 00 01 68 84 c0 00 00 00 1f 3b 95 00 00 00 00 00 08 10 00
+00 02 08 00 50 00 aa 58 80 20 00 02 07 0a 10 00 00 00 00 00 00 20 00 03 14 01 24 00 80 00 80 d8 3e b0 02 00 00 00 00 f5 01
+00 00 00 00 0d 80 52 65 a0 00 00 00 04 7c a0 02 00 00 00 00 00 00 00 00 05 e8 84 c0 00 00 70 05 ea 81 00 00 00 60 14 cf 50 00
+00 00 00 00 78 00 2e 58 00 00 00 40 05 04 00 00 00 00 00 00 00 20 00 02 26 01 24 00 80 01 09 fb 2d 50 02 00 00 01 4c 7e 00
+00 00 20 00 01 80 7a 25 a0 00 00 34 28 18 80 02 00 00 00 00 00 00 00 06 65 48 84 c0 00 00 d0 15 3a 85 00 00 00 00 00 0b d0 00
+00 00 00 00 b0 d0 36 58 00 c0 00 02 95 00 f0 00 00 00 00 00 00 40 00 02 16 01 24 00 00 01 00 94 2a b0 0c 00 04 00 00 fa 10
+00 00 00 00 08 01 5a 65 a0 0c 00 16 06 4a f0 00 00 00 00 00 00 0c 06 1e 65 48 84 c0 00 00 99 88 39 55 00 c0 02 00 14 cf a0 00
+00 00 00 00 08 00 b2 58 00 00 02 e2 95 d0 c4 00 00 00 00 00 00 00 00 00 24 01 24 02 00 00 09 58 3e b0 18 00 00 00 1c cc c0
+00 00 00 00 01 80 12 25 a0 06 00 3e 2b 5b 5e 40 00 00 00 00 00 06 00 00 01 c8 84 c0 2a 80 18 11 aa 81 20 a0 00 00 00 8c c4 00
+00 00 00 00 00 e0 32 58 00 00 01 42 b6 8f 34 00 00 00 00 00 00 00 00 00 14 01 24 20 00 00 00 7b 9c 10 00 00 00 2a 40 f0 c0
+01 00 00 00 00 00 50 25 a0 00 00 36 02 fa fb 40 00 00 00 00 00 00 00 00 71 c8 84 c0 00 00 18 07 2f c5 00 00 00 00 4c aa a4 00
+00 00 10 00 00 d0 01 2c 00 40 03 47 7d e4 40 00 00 00 00 00 00 08 00 02 97 ff 70 02 00 01 0a 13 ff c2 08 00 00 00 10 e4 c8
+04 00 03 00 05 9d 7e 92 c0 84 00 06 66 49 bb 00 00 00 00 00 00 00 00 00 03 d9 e7 00 b0 00 80 a1 eb dc 02 c0 00 00 05 ae 46 20
+86 00 00 00 00 81 43 c0 00 00 00 24 1e 00 f0 00 00 00 00 00 00 00 00 03 e5 0f f0 00 00 45 08 58 3f ca 00 40 00 2d 6e ff 00
+00 00 00 00 01 81 5b 83 c0 00 0c 14 7a cc f0 00 00 00 00 00 00 00 00 00 6b 7c f7 02 80 02 00 1f 6b d4 04 00 00 60 1c af 70 10
+08 00 00 00 10 ff 82 70 00 00 00 00 3d e4 44 04 28 00 00 00 00 00 08 02 83 0f 50 00 00 00 0a 78 3e b0 00 00 02 00 30 a0 01
+04 00 00 00 00 00 7e 24 c0 80 00 06 02 49 bb 40 01 00 00 00 00 00 00 40 68 ee f5 00 00 00 00 1b ea 81 00 00 00 e0 16 8a 00 00
+00 02 00 08 00 01 40 28 00 00 10 06 c5 07 70 00 00 00 00 00 00 00 14 07 bd af f0 00 08 05 00 d7 29 90 00 00 00 3a 4b 81 00
+00 00 00 00 00 00 5b a8 00 00 00 06 28 f8 44 02 00 00 00 00 00 00 20 94 24 de f7 00 01 00 18 0f fa 95 00 00 00 00 40 14 20 00
+00 00 00 00 b0 0f 03 e8 00 00 00 00 17 05 a0 00 00 00 00 00 00 00 09 c6 f5 0f a0 00 00 0d 10 3c 3e b0 20 00 3c 23 50 50 c0
+00 00 10 00 09 80 06 3d 40 00 00 00 69 fa f0 00 00 00 00 00 00 00 01 20 2a 1a f5 00 00 00 1d e3 aa 81 00 00 02 06 60 aa 04 00
+00 00 00 00 10 07 75 c9 00 c0 00 40 01 0e 10 00 00 00 00 00 00 00 00 26 c5 00 20 80 00 41 00 b4 3d 70 00 40 b6 02 e0 fa d0
+00 00 00 00 08 00 03 ec 50 0c 00 20 01 4c e1 02 00 00 00 00 00 00 00 1c 2a 68 00 02 00 02 81 8d 3a 81 00 00 01 46 17 aa 06 00
+80 00 00 02 b0 05 81 41 00 00 02 c0 01 0e 10 00 00 00 00 00 00 00 03 63 c5 b0 00 02 00 2d 00 3f 9e 90 08 02 00 00 0b fc 40
+00 00 01 80 18 00 3b bd 50 06 00 20 29 cc e1 02 00 00 00 00 00 00 00 14 00 4a 80 00 28 00 00 07 ea 85 00 a0 00 00 00 ff c4 00
+00 43 01 05 50 0b 43 d5 00 00 10 42 00 00 f0 00 04 00 00 00 00 00 03 62 67 df f0 00 00 00 80 d3 d9 50 00 40 04 20 5d 4a 40
+00 07 00 28 00 00 d7 a8 10 00 00 a0 04 1c 0f 00 00 00 00 00 00 00 00 14 60 ce f7 00 00 04 50 0d 3e 95 00 00 02 00 4e ee 54 00
+00 00 30 00 10 a9 a0 78 00 c0 00 03 7f 86 30 00 00 00 00 00 00 40 00 00 15 8c 30 03 00 07 80 f6 b9 40 04 00 00 03 e9 20 00
+40 00 01 00 0d 81 3e 74 80 0c 00 1c 04 4c 6c 00 00 00 00 00 00 0c 00 1e 03 c8 e3 11 b0 00 90 a1 7a 3c 00 40 00 00 1c d0 00 00
+00 00 00 00 00 07 e0 b9 00 00 14 02 56 d7 80 00 00 00 00 00 00 00 00 20 04 ff f0 00 00 50 0a fb 3f c0 40 00 00 74 c0 1a 01
+00 00 00 00 01 9a fb 09 50 40 00 80 06 7d 4b 00 00 00 00 00 00 00 00 1e 78 5c f7 00 81 02 00 ef 2f dc 00 00 00 07 81 a2 50 20
+00 00 00 00 50 8b 82 91 00 00 00 22 c7 0c c0 00 00 00 00 00 00 00 02 e0 05 00 00 14 00 0d 0d 50 36 c0 00 02 80 03 f0 ff 08
+00 00 00 00 05 81 77 9d 10 c0 00 14 03 48 33 02 00 00 00 00 00 00 00 2e 01 c8 40 02 00 00 00 b0 03 9c 08 00 10 60 1c aa f0 00
+00 02 04 00 00 ab 80 0c 80 00 00 02 ed 05 f0 00 08 00 00 00 00 02 14 02 04 ff 00 00 00 0f 00 f7 3b c0 00 00 1c 02 4b 1a 08
+00 00 00 40 00 19 7f 10 c0 80 00 01 00 4e 50 00 01 00 00 00 00 00 40 80 04 ea e0 00 00 00 80 09 3f fc 00 00 0a 00 2f b1 50 00
+00 00 00 00 08 09 02 a8 00 00 00 20 0e 00 f0 00 00 00 00 00 00 00 00 40 00 0f 04 00 00 01 00 f4 3d 40 00 01 1c 03 40 5a c0
+00 00 20 00 01 00 77 0c c0 80 00 14 02 fa f0 00 00 00 00 00 00 00 00 20 00 1e f0 40 00 10 80 03 fa 94 00 20 0a 03 80 0a 54 00
+00 00 14 00 00 01 74 3c 00 00 00 04 2c 0a f0 00 00 00 00 00 00 00 03 c0 34 05 a4 03 00 5d 00 90 36 c8 00 00 04 3c 10 f0 c0
+00 00 01 40 00 00 9a 61 c0 00 20 00 2a 7c fa 00 00 00 00 00 00 00 0c 20 60 00 a5 40 30 02 81 85 fb dc 08 00 22 03 00 8f 04 00
+00 00 00 00 d0 b7 37 29 04 00 00 20 00 00 f6 00 00 00 00 00 00 00 00 00 03 05 05 08 00 00 00 f3 40 00 00 00 24 7d 60 50 00
+80 00 01 80 01 80 87 b1 50 06 00 14 68 1a 0f 40 00 00 00 00 00 06 00 00 00 ca 50 40 18 00 00 03 b4 40 00 60 00 03 c4 c0 00 00
+04 00 02 80 71 e7 a7 f9 04 00 00 02 81 0f 04 00 00 00 00 00 00 00 03 42 c0 0f 54 00 00 05 8f b2 e8 10 40 00 00 22 40 5a c0
+00 00 00 13 08 0a b7 ff 10 08 08 16 04 1e f0 40 00 00 00 00 00 00 00 06 00 5a f5 61 00 20 78 09 7a 01 00 00 e0 06 40 0a 54 00
+00 00 10 00 00 8f 41 41 00 40 00 43 c0 00 00 00 00 50 00 00 00 40 10 03 04 0a 52 00 10 2b 99 10 39 80 04 00 00 30 cc d0 00
+04 00 03 00 00 01 b6 bd 50 2c 00 20 04 00 00 00 00 00 00 00 00 04 00 86 04 00 5a 00 00 00 f1 d9 7b 04 08 c0 00 00 65 8d 50 00
+80 30 00 00 50 85 71 c9 00 00 00 40 00 00 00 00 00 00 00 00 00 80 00 04 25 05 20 10 00 00 1d 52 74 00 00 00 04 60 48 98 00
+00 00 40 00 00 01 87 ac 50 00 00 20 78 00 00 00 00 00 00 00 00 0c 20 00 22 e8 d1 02 00 00 00 c9 b7 54 00 00 02 02 7d ae 50 00
+0c 2c 00 00 90 e5 01 41 00 00 0a c3 fe 81 24 10 00 00 00 00 00 00 01 c0 35 05 a0 00 00 00 19 7c 00 00 00 01 0c 30 eb 6a 40
+04 40 40 00 00 01 b6 bd 50 00 00 40 07 69 84 40 00 00 00 00 00 00 00 14 33 4c ad 02 00 00 01 8b b1 00 88 00 0c 60 66 ba 55 00
+00 02 00 00 30 0d 31 c9 00 00 00 00 24 bd e4 00 00 00 00 00 00 00 00 43 ff 0f f0 00 00 00 8c f8 09 00 00 00 3c 03 da a6 40
+00 00 00 00 08 00 06 ac 50 00 00 06 03 e9 b7 e0 00 28 00 00 00 00 00 36 01 fa af 00 00 00 10 1f a9 40 08 00 c0 60 17 aa 54 04
+00 00 00 00 10 0f 41 41 00 0c 03 c0 3e 91 24 00 00 00 00 00 00 00 00 02 84 00 50 10 00 00 90 94 3e 82 00 40 04 3b 79 c3 40
+80 00 10 00 09 98 32 bd 50 00 60 20 3b 68 84 e0 00 00 00 00 00 00 0e 00 00 1c 0a 00 00 00 78 a8 3b d4 00 00 02 00 4f 8e 24 00
+30 00 00 00 10 03 42 81 04 c0 00 00 2c b1 24 00 00 00 00 00 00 40 00 00 1d 81 d0 10 28 01 00 f4 3e 80 00 a0 02 27 fd 70 48
+02 00 00 00 08 18 53 bd 50 0c 40 00 03 69 84 e0 00 00 00 00 00 04 00 1e 02 da 25 00 01 00 80 08 63 d4 80 04 01 c0 14 ff 14 00
+80 00 00 00 00 00 43 c1 00 00 00 03 7e c1 24 10 00 00 00 00 00 04 03 c3 0c 9a 10 00 00 00 9f 9f ff c0 02 01 24 34 df da 48
+00 00 05 80 00 00 02 3c 10 06 00 06 07 68 84 c0 00 00 00 00 00 06 00 20 26 df e2 10 00 00 10 9f 6b dc 00 a4 08 00 55 9a 44 00
+10 02 00 00 00 db 03 d5 00 00 20 00 2c 01 24 a0 04 00 00 00 00 00 03 67 cd c9 04 00 00 0f 00 fc 00 00 00 01 06 03 cd 70 40
+00 00 00 00 01 81 93 a8 10 00 00 00 63 c8 84 c0 00 00 00 00 00 00 00 14 3e 1c 60 40 40 00 00 01 f1 40 00 00 09 c6 04 ff 14 10
+00 00
+11 02
+01 01
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 20 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 04 00 00 00 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 08 00 00 00 00 00 00 20 00 00 00 00 08 0b 00 00 00 00 00 20 00 00 00 00 00 00 80 00 00 00 00 00 02 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 08 00 00 00 00 00 40 20 00 00 00 00 08 00 00 00 00 00 00 20 00 00 00 00 00 00 80 00 00 00 00 00 03 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 20 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 08 00 00 00 00 00 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 16 91 68 07 90 00 40 00 1f c1 80 00 00 00 00 00 00 08 02 29 fc 90 09 00 00 00 8d 3b ac 3e 85 00 0c 0c 68 00 b0 00
+00 00 00 c0 69 04 00 6e 00 00 00 04 f9 d0 00 00 00 00 00 00 08 00 13 fd ed 00 b8 00 00 00 cd 68 c2 90 20 02 83 04 00 18 00 00
+00 00 00 12 11 70 c0 00 00 00 00 2d c0 08 0d 00 00 00 00 00 00 00 02 ee f8 00 00 00 44 47 5f 80 30 00 04 05 a4 4a 00 b0 01
+00 00 00 00 48 02 f4 00 00 02 51 01 f9 01 00 00 00 00 00 00 00 00 00 af 5d 70 04 00 00 04 70 40 00 00 00 00 1a 41 00 1f 00 14
+00 00 00 12 11 38 00 00 00 40 00 1e 80 00 08 00 00 00 00 00 00 10 32 cd a0 00 00 00 00 af 16 9c 3c 00 00 05 a6 40 38 e0 00
+00 00 00 00 48 07 bc 00 00 02 40 14 3d 00 00 00 00 00 00 00 00 00 01 18 1f 00 00 00 00 00 50 a0 23 03 00 00 1a 4c 07 80 00 00
+00 02 00 16 91 22 03 00 20 00 28 0c 80 00 00 00 00 00 00 00 00 11 39 c7 e8 1c 20 00 00 0a 10 00 64 02 00 05 a4 5c 00 c0 00
+00 00 00 80 69 00 0c 2c 04 00 02 80 10 10 b0 00 00 00 00 00 00 00 03 7c 38 71 00 00 01 00 50 a0 03 00 50 00 1a 41 00 10 00 00
+00 00 10 12 11 75 40 40 40 30 30 57 b0 00 00 00 00 00 00 00 00 00 0c 2f d0 0e 00 00 10 0a 12 20 00 00 00 15 a4 4a 00 00 00
+00 00 20 00 48 06 42 30 02 00 02 00 1d f0 a0 00 00 00 00 00 00 00 00 91 6c 01 00 00 00 00 a0 82 c2 80 00 00 1a 41 00 00 00 00
+00 00 08 12 11 7c c0 08 00 80 0a 2c 91 80 00 00 00 00 00 00 00 11 00 86 81 08 00 20 00 af 33 00 28 00 00 15 a4 5a 00 80 00
+00 00 00 00 48 06 40 2c 00 00 00 30 5a 10 01 00 00 00 00 00 00 00 02 84 28 11 80 00 00 00 50 78 00 00 00 00 1a 40 05 1a 00 00
+00 00 00 02 11 34 03 80 00 02 03 f6 e0 00 00 00 00 00 00 00 00 00 00 00 09 00 a0 00 00 af 1a b4 00 00 04 05 a4 5e 00 0a 00
+00 00 00 00 48 07 b4 00 00 00 00 0e c9 00 a0 00 00 00 00 00 00 00 00 00 00 38 04 00 00 00 50 20 42 00 00 00 1a 40 00 00 00 00
+00 00 00 0e f3 6c e7 80 00 02 09 20 10 00 14 00 00 00 00 00 40 02 02 8f b1 9c 80 01 40 8b 72 84 00 00 82 05 a6 40 00 10 08
+80 00 00 00 ff 12 82 00 00 00 00 63 4a 30 c0 00 00 00 00 00 00 00 00 3c 0d 00 00 00 00 00 a0 e0 20 00 08 00 1a 4c 00 0e 0d 48
+00 00 10 2e 79 60 60 10 00 00 1d 3d d0 19 04 00 00 00 00 08 00 00 a3 f5 c0 18 00 00 02 c3 1f 60 3c 00 00 01 a4 5a 01 c1 00
+00 00 00 8e 8b fa 7c 02 00 00 02 b1 c8 01 c0 00 00 00 00 00 40 00 08 38 ce 00 00 08 08 a4 71 bb c2 00 20 88 1a 41 00 00 18 00
+00 00 00 00 a7 70 06 40 25 10 20 07 b0 01 00 10 00 00 00 10 20 41 91 c7 d8 00 00 11 02 8b d3 4e 04 00 d0 00 02 7d 01 e0 00
+00 00 00 00 0a 08 00 34 04 40 03 80 2a d0 80 01 40 00 00 00 84 00 0b 0c 6c b0 90 01 48 20 f9 30 23 c7 05 00 01 05 ef 0b 00 00
+00 00 04 08 15 75 c0 40 42 31 a1 55 e9 0e 00 0c 00 00 00 00 00 00 a9 4e af 1f 20 00 82 a5 3a 06 60 00 00 00 00 00 70 00 00
+00 00 00 00 85 03 40 20 02 34 0b 7c 38 91 00 00 c0 00 00 00 02 00 0a a8 3e 10 80 00 20 25 93 34 00 06 00 00 00 00 00 08 18 00
+00 02 04 04 77 6d 40 00 20 00 a2 ee 18 19 00 00 00 00 00 00 50 40 a9 55 e0 01 00 80 02 a5 12 c6 60 41 00 03 95 d8 78 04 00
+00 00 00 00 85 0f c0 00 41 0a 09 1f 6f 90 f0 00 00 00 00 00 52 00 0a a8 3b 00 80 04 00 2a a0 e4 00 07 20 04 11 5f 83 00 80 00
+00 00 00 08 05 7c 00 00 00 61 a9 de 80 01 00 00 00 00 00 06 00 00 a9 4f b0 1e 00 00 02 a5 7b a6 00 00 08 00 15 ca 00 00 04
+00 00 20 80 00 77 80 38 00 08 09 5e ee 70 a0 00 00 00 00 00 00 00 0a a8 29 00 00 00 00 aa a0 6c 63 80 00 00 17 c2 b0 00 10 80
+00 00 04 0a 03 f4 67 08 08 00 00 07 e0 1e 08 00 00 00 00 00 00 01 b9 c0 b7 09 41 40 02 a5 16 80 38 00 00 03 c1 60 00 00 00
+00 00 00 00 80 0b 74 71 00 00 00 14 0e 70 80 00 00 00 00 01 00 00 09 09 da 18 c2 08 00 2a a0 a0 02 00 00 00 3c 02 09 00 00 00
+00 00 00 0e fd 74 e7 80 00 00 04 7d b1 09 00 00 00 00 00 28 00 80 ab de c0 08 00 00 02 af 37 e0 38 00 00 00 00 00 b0 10 00
+00 00 00 00 fb 33 40 00 00 00 00 09 c8 00 a0 00 00 00 00 00 00 00 08 28 2e 00 e0 04 00 a0 a0 aa 40 20 00 00 00 00 03 8e 00 00
+00 00 00 04 27 7f c7 84 02 10 00 d4 d8 09 00 8c 00 00 00 30 50 01 2a cf fb 88 00 09 02 af 5e 40 70 00 30 00 00 00 00 00 00
+00 00 00 00 c1 53 ee 00 00 20 13 cc 2e f1 d0 00 80 00 00 02 00 00 00 2d 6f 18 00 00 80 20 a0 a4 02 00 02 00 00 00 00 08 00 00
+00 00 01 00 1f 7d 60 10 00 80 3b d7 d5 00 00 00 00 00 00 00 00 41 a3 d5 93 88 60 00 12 47 76 60 6e 02 00 18 80 cf 00 00 80
+00 00 00 00 10 da 00 2a 20 00 02 fe 4d 50 00 00 00 00 00 00 1a 00 48 38 cc f9 0e 00 00 2c 31 ef 46 10 10 00 80 3d 80 08 00 00
+00 00 00 0a 89 a3 40 00 00 00 21 67 b0 00 80 00 00 00 00 00 00 01 91 cf 90 0e 00 15 02 c7 37 8e 04 00 50 20 01 cf 00 10 01
+00 00 00 00 04 93 d6 2c 00 00 13 ab 5f 00 a4 00 00 00 00 00 00 00 0b 0f 58 71 00 01 40 2c 23 bf e3 87 04 80 10 3e a0 0a 00 10
+00 00 00 08 b9 78 e0 60 00 00 22 dc 11 81 00 00 00 00 00 00 10 04 91 c5 98 09 00 42 02 8f d3 a0 00 00 00 0a 94 00 18 10 00
+00 00 00 00 42 da 00 34 70 00 41 1d e8 b0 9a 00 00 00 00 00 30 02 0b 0e e9 f1 84 08 00 20 d7 b4 40 03 00 00 96 80 b0 0f 00 00
+00 02 04 04 a1 a9 40 07 00 00 28 05 c1 01 00 00 00 00 00 00 00 41 91 ff 99 80 00 00 00 05 76 de 38 04 00 08 7d 5e 00 10 00
+00 00 00 00 a5 0e 9e 00 00 80 02 80 20 90 ea 00 00 00 00 01 10 00 0b 0f 78 f0 05 80 00 0a f0 3c 27 c7 20 00 83 df c0 0a 00 00
+00 00 08 4a 07 e0 00 00 50 c0 02 94 c0 0a 00 00 00 00 00 20 00 40 91 c4 8f 9d 00 40 40 8b 5a 20 64 00 00 08 01 db 02 a0 10
+00 00 20 08 a0 04 00 00 52 00 00 00 2f 00 00 00 00 00 00 00 00 00 4b 0e 6c 19 d0 04 00 0d b0 3e c3 00 00 00 80 9c f0 1b 00 80
+00 00 00 01 09 a4 00 28 30 00 10 c7 d5 18 00 00 00 00 00 00 50 40 91 fe c8 18 60 00 0a af 17 20 00 00 00 03 bd de 00 02 00
+00 00 00 00 52 93 80 01 05 00 01 a1 4d f0 a0 00 00 00 00 00 02 00 2b 0c e8 10 99 00 00 20 a0 f8 c0 00 00 80 3f dd f0 00 58 00
+00 00 04 0c 07 66 e0 00 00 00 2b c4 cb 9c 00 00 00 00 00 00 00 20 91 ed 90 0e bd 00 00 05 57 8e 64 54 01 02 fd ea d0 a1 08
+00 00 00 00 ca 0e 26 00 00 02 12 bc 20 71 00 14 00 00 00 00 00 00 0b 0e e9 00 04 08 00 00 50 c1 c3 c5 20 02 2f c0 01 9b 00 00
+00 00 08 08 1f 24 00 40 00 72 01 14 10 01 a0 00 00 00 00 00 00 20 8b d6 a7 8e 00 0c 40 8b 1b a0 78 04 20 0b d4 de 19 da c2
+c0 00 00 00 af db 80 24 00 0a 00 20 2e 90 a4 80 00 00 00 00 00 00 08 2c ed 01 00 00 c0 04 20 e2 c4 00 02 00 c1 41 c0 18 00 2c
+00 00 00 0c 0d 25 60 00 00 00 08 0f e0 00 00 00 00 00 00 06 00 00 01 57 d1 0a 00 00 12 af 5b 80 06 b0 00 1a 3f 5f 01 88 00
+00 80 00 00 ca 96 3e 38 80 0a 20 01 ea 00 c0 00 00 00 00 00 02 00 02 bc 3d b0 00 00 00 20 50 fc 02 20 00 00 83 6d e0 00 1c 00
+00 00 01 24 7d 87 c0 48 24 00 29 ee 90 1c 00 20 00 00 00 00 00 10 31 55 80 01 00 00 00 00 00 34 7c 00 40 0b 1c fe f1 80 01
+40 00 00 12 8b 9b ac 20 00 40 01 47 cc 50 00 80 00 00 00 00 00 00 03 14 00 00 e0 00 00 00 00 02 c7 c0 0d 24 f0 86 e1 00 00 10
+00 00 00 08 3d 21 43 c0 03 10 28 de b0 19 00 20 00 00 00 10 00 00 01 5c 98 1b 00 01 00 af 5b 8c 3f 80 04 0a 3f 4d 81 f0 08
+00 00 00 00 c3 16 80 34 00 30 01 8c 0b 01 f0 02 00 00 00 00 f0 00 02 bc 0d f1 e1 80 01 00 a0 20 22 28 10 04 83 6e e1 18 01 40
+00 02 04 0e 03 ec ee 00 00 10 11 d7 e9 1c 00 20 00 00 00 07 20 10 22 c5 a8 0e 81 00 00 01 b6 3c 00 00 00 1b 1e fe 80 10 18
+00 00 00 00 80 0b 40 00 00 80 01 1c 00 99 00 08 00 00 00 00 01 00 02 2c 20 31 01 80 00 05 bf 6b e3 00 00 00 f0 b6 df 08 01 c0
+00 00 1d 68 53 7d 60 00 00 c0 33 fd b0 01 00 00 00 00 00 00 10 10 28 54 90 00 01 40 40 c5 30 5c 74 00 00 2a 3f 6f 19 94 00
+00 00 20 8a df 0b c2 00 00 00 03 bd d9 00 a0 00 00 00 00 00 00 00 02 ac 3c 00 b0 08 00 0c a0 a0 27 40 00 02 83 6d e0 9d 00 80
+00 00 00 08 e1 aa 60 50 00 80 30 26 d1 1f 00 80 00 00 00 00 50 10 22 5c cf 81 00 00 40 a1 5a c6 02 05 00 4a 86 ff 18 d0 00
+00 00 00 00 0c 52 64 34 10 02 23 80 6e 01 b0 14 00 00 00 02 82 00 03 1c 0b 38 90 00 00 0a b0 e4 00 03 20 40 96 ee 83 8d 00 00
+00 00 04 00 a3 f9 c0 28 00 00 01 5d e8 1b 00 00 00 00 00 00 00 90 11 dc a8 19 20 02 40 83 37 64 24 02 00 08 15 f9 80 15 c0
+00 00 00 00 02 0e 40 01 00 04 40 14 20 b0 80 00 00 00 00 00 00 00 01 1c 20 d0 95 00 00 06 70 6e e7 60 40 00 97 c3 99 09 20 00
+00 00 0d e0 a7 ae c3 40 03 00 00 00 08 19 00 80 00 00 00 00 20 00 00 00 00 00 00 20 00 25 76 40 72 20 30 1a 95 59 80 80 00
+c0 00 00 12 1d 07 a6 30 00 20 00 00 00 70 b0 40 00 00 00 00 01 00 00 00 00 00 00 02 00 00 1b 60 44 10 03 04 95 41 c3 00 00 08
+00 00 00 04 71 64 67 00 00 00 01 c4 91 9e 00 00 00 00 00 00 00 01 00 17 e0 00 00 00 00 e7 7a 60 61 01 04 0a 3d 49 99 e0 80
+00 00 00 00 05 be c0 00 00 00 02 af 6a 01 a0 00 00 00 00 02 08 04 00 0b de 00 00 00 00 00 5b 2f c0 00 00 00 83 8c b5 10 04 00
+00 00 04 08 b3 f9 c3 8a 00 10 01 46 97 1d a0 00 00 00 00 10 10 00 02 1c 07 8e 00 00 00 a1 5e 20 70 82 00 0a bd da 00 f0 01
+00 00 00 00 8b 08 00 28 00 00 01 08 0d 00 80 00 00 00 00 00 a2 00 00 13 6e 00 00 00 00 0a b7 fe c4 10 10 00 81 41 b0 1e 80 54
+00 00 00 0f f5 e4 00 20 00 00 2b d7 d7 00 00 00 00 00 00 05 00 11 00 07 ef 8e 00 00 00 67 be 40 3a 00 00 0a bd fa d0 f0 00
+00 00 00 08 5f 02 c0 00 00 00 00 28 0e 90 00 00 00 00 00 00 00 00 00 04 2a f9 00 00 00 08 39 2c 02 06 20 02 82 81 eb 18 14 40
+00 02 00 00 57 01 43 c0 20 10 28 56 f0 0b 40 00 00 00 00 00 00 00 09 ef e0 09 00 01 40 83 16 be 00 05 00 0a 94 da b8 f0 00
+00 00 00 00 0a 03 40 30 00 00 01 5c 09 30 f1 00 00 00 00 00 02 00 20 5c ff 01 e0 00 00 09 b0 f1 e0 00 20 80 95 43 9f 98 00 00
+00 00 00 40 0d a6 c6 00 00 00 01 5d 90 00 00 00 00 00 00 00 00 80 00 17 e0 00 00 20 00 67 d6 c0 30 04 02 0a bd 7d 80 08 00
+00 00 20 04 01 12 f4 00 00 00 01 7c 3f 00 90 00 00 00 00 00 04 08 60 21 df 00 00 00 00 08 39 6f c0 10 20 00 82 80 b3 09 40 00
+00 00 00 08 17 69 e0 42 20 00 01 5c d5 a8 3c 00 00 00 00 00 50 00 29 5c b0 08 00 02 40 a3 5b c4 32 b0 00 00 17 5d 01 e0 00
+00 00 00 00 5f fb be 24 84 00 02 bc 28 08 8c 00 00 00 00 00 02 00 11 54 18 31 00 00 00 06 30 b4 00 00 00 00 39 ff 81 20 00 00
+00 00 04 08 93 74 63 c8 00 00 20 f6 a3 1e 80 40 00 00 00 00 20 20 3b d4 e9 09 01 40 80 e7 80 20 3c 20 01 02 0d 69 51 84 00
+00 00 00 00 c7 06 be 25 50 00 00 04 f8 b8 04 00 00 00 00 00 74 04 03 ff ee d8 e0 0c 00 0d b9 2a c2 44 00 00 19 c1 a9 00 20 00
+00 00 04 00 33 80 06 00 00 00 00 00 07 98 10 00 00 00 00 00 00 10 08 15 a1 00 00 00 00 f5 56 80 04 05 01 20 1d c8 00 1a 40
+80 00 00 00 03 00 00 40 40 00 00 00 00 08 04 00 00 00 00 00 00 0e 20 80 00 10 80 00 08 0f 50 40 02 c0 20 00 2a c3 f1 0b 40 28
+00 00 00 20 49 fc 06 40 01 00 35 5f d3 80 00 00 00 00 00 00 00 00 29 56 80 18 80 00 00 af 3a 6c 60 01 00 02 15 5a 81 e0 14
+00 00 00 02 1c fa 00 20 00 00 03 94 6e 08 e0 14 00 00 00 00 60 00 01 54 0b 90 02 00 00 00 50 2b c0 00 00 01 3a bd eb 18 18 00
+00 00 00 20 4b a7 40 48 25 10 11 55 b3 9e 40 00 00 00 00 00 50 00 11 76 90 00 00 20 00 05 32 a0 00 50 00 02 9d ec 00 00 00
+00 00 00 02 2c bb 84 20 05 40 01 3c 39 0b 00 02 00 00 00 00 40 00 02 3f dd 00 00 00 00 05 f0 f1 40 00 00 00 06 56 8d 0d 00 00
+00 00 00 20 2b 27 67 00 00 10 01 46 db 3e 00 00 00 00 00 05 00 00 2a df d1 9c 00 00 00 47 5e cc 00 00 00 02 85 49 38 80 80
+00 00 00 02 25 33 d4 00 00 00 01 08 0c f1 00 00 00 00 00 00 00 00 00 2d 5f 00 01 40 00 05 f7 70 23 c0 00 00 2a e4 c0 8d 08 00
+00 02 00 60 4d 34 67 a3 10 00 20 5d c1 00 a0 00 00 00 00 02 20 10 20 dc d0 09 b0 00 40 05 36 be 3a 01 01 02 0d 5a 01 c0 00
+00 00 00 02 2c bf 80 02 00 00 00 17 6c 78 04 00 00 00 00 00 60 00 01 9c 3d 01 f0 00 00 0d b0 77 c7 d0 00 02 19 c2 af 1b 00 00
+00 00 00 20 4d 7f e6 00 08 04 39 7e 80 09 01 40 00 00 00 14 00 00 2a df d0 00 a0 20 00 47 56 dc a6 00 00 00 00 00 00 09 04
+00 00 20 02 1c fb 84 78 20 00 01 02 fd 90 f0 08 00 00 00 00 00 00 00 2d dd 70 00 00 20 00 5f 73 62 12 00 00 00 00 07 0d 00 00
+00 00 00 20 4f 67 e0 20 00 00 01 54 d0 19 00 80 00 00 00 00 40 10 20 df d1 1c 00 00 00 a5 5e 40 e8 00 08 02 bc d8 00 00 02
+00 00 00 02 2c b7 a4 34 00 00 01 7c 0b 90 b0 14 00 00 00 00 02 00 01 9c 0d f1 e0 00 00 05 50 7c 07 80 00 00 01 43 a0 09 00 00
+00 00 00 20 4f 7c 02 80 00 00 00 00 07 80 00 00 00 00 00 10 00 10 31 57 c5 8c 40 00 48 ab 32 64 78 85 00 02 95 5a 11 80 00
+00 00 00 02 1c fa f4 40 00 00 00 00 00 00 00 00 00 00 00 02 a0 00 03 14 00 09 0a 00 00 00 70 ed e4 12 30 00 15 40 a0 80 00 00
+00 00 00 20 05 7d e6 00 02 00 00 00 00 0e 60 00 00 00 00 00 00 00 00 00 01 1a 80 00 00 a5 5a 20 00 00 00 02 bc 68 38 00 00
+00 00 00 02 02 b7 80 34 00 30 00 00 00 10 04 00 00 00 00 00 02 00 00 00 00 91 80 00 10 0a a0 7f c0 00 00 80 01 40 80 80 18 00
+00 00 01 2a 53 b8 60 68 00 00 22 5e e0 01 00 80 00 00 00 08 20 00 2a df 8f 00 5c 00 00 a1 1a 00 7c 44 88 08 14 c8 b9 e3 d8
+00 00 00 12 9a ba 00 20 30 00 03 2c 7e 00 ea 04 00 00 00 01 08 00 00 1d dc f8 0a c0 00 0a bb 24 c7 80 20 00 97 c0 c7 88 00 00
+00 00 00 6a f5 68 e0 00 05 10 01 dd d8 1f 00 00 00 00 00 02 00 10 28 cd d5 8a 00 00 40 83 57 40 79 60 00 09 1d f9 00 f0 81
+00 00 00 0a 0a 03 82 34 00 50 00 08 3c b0 f0 00 00 00 00 00 00 00 42 4c 08 09 00 00 00 06 70 a0 00 08 00 04 b0 f6 b0 1e 00 10
+00 00 01 a8 df 04 06 00 00 00 20 cf 90 00 a0 00 00 00 00 00 10 00 29 5c d0 00 40 00 00 a1 1a 4e 70 00 00 0a 3d df 70 10 80
+00 00 00 02 4e 5b c0 00 00 00 00 07 ed f0 04 00 00 00 00 00 00 00 02 a8 0e 00 a2 00 00 0a b5 3c 00 00 08 00 83 b7 f7 8d 40 00
+00 02 10 2c 13 35 e7 a0 00 00 11 c6 c5 80 40 a0 00 00 00 00 00 10 30 16 c0 1e 00 00 40 83 3b 60 72 80 00 1b 1d ca 99 82 00
+00 00 00 0a c7 9b 42 00 40 00 00 17 7d 08 0a 00 00 00 00 00 20 00 43 28 1d 01 94 00 00 06 70 a2 44 02 00 40 b0 af a5 08 00 20
+00 00 00 2a 53 fe 00 00 00 10 01 4c f9 0f 00 00 00 00 00 09 00 00 2a de 83 8e 50 80 40 c5 30 00 38 00 00 09 1f d8 18 94 00
+00 00 20 82 65 bb ec 34 00 00 13 6c 1e 31 d0 00 00 00 00 01 00 00 00 1e 5c 71 8a 10 00 0c a0 38 c2 a0 00 20 b0 cc f0 08 00 40
+00 00 01 2c 3b b7 c6 07 00 00 28 7f 87 18 04 00 00 00 00 00 20 10 28 cd d8 00 60 00 40 42 72 60 00 00 00 0a 3f 6a 80 14 00
+00 00 00 12 47 3f 76 00 00 00 02 89 cd 78 00 00 00 00 00 00 00 00 02 4c 1a f0 94 04 00 44 70 b9 c3 40 00 04 83 bd c1 08 20 00
+00 00 00 2a f7 bf e7 40 00 00 35 6c e5 9f 0c 00 00 00 00 00 30 00 03 34 e8 0d 80 80 00 0c 5f c4 61 00 40 09 1f 78 90 10 00
+00 00 00 02 05 0a c6 7c 00 00 03 97 6c 18 e0 00 00 00 00 00 12 00 42 35 5d b0 e0 14 01 04 e1 a8 20 20 00 00 b0 ec f1 0e 00 00
+00 00 10 2e 78 3f e0 60 02 00 00 00 08 08 08 00 00 00 00 00 20 00 00 00 00 19 00 00 00 00 00 14 00 02 00 0a 94 5a 71 e2 08
+c0 00 00 0a 42 97 c4 20 00 20 00 00 00 11 c0 04 00 00 00 00 05 00 00 00 00 00 f2 00 00 00 00 00 03 00 50 80 aa 83 91 10 41 0c
+00 00 00 ac 73 e2 60 40 00 04 a3 f4 97 bf 00 10 00 00 00 06 40 00 b8 d7 d0 01 00 00 00 25 d2 2e 38 44 00 03 94 ff 00 00 08
+00 00 00 02 c2 37 84 3c 00 02 08 35 4b 38 e0 00 00 00 00 00 00 00 09 0c 6b 90 80 00 00 06 71 a0 c6 40 00 00 11 4d a0 00 00 00
+00 00 00 a8 fd 79 c0 40 04 01 91 c5 b8 08 00 10 00 00 00 00 00 00 83 75 f8 01 09 14 40 83 33 40 20 20 01 03 15 ea 00 01 00
+00 00 00 02 0e 92 c0 20 00 48 6b 0e f8 71 f0 01 00 00 00 00 00 00 4a 3c cb 10 81 8d 00 06 70 a8 07 c0 00 00 31 41 05 00 18 00
+00 00 01 24 73 e4 66 00 00 01 91 d4 d9 8f 04 00 00 00 00 00 00 40 b8 d7 d1 98 00 00 00 25 9a 24 78 22 01 23 89 4d 18 80 80
+00 00 00 82 c3 9f 9c 00 00 00 4b 0e ed b0 82 00 00 00 00 01 00 00 49 0e ef 00 00 00 00 06 71 27 40 00 50 00 20 41 d7 1e 80 00
+00 02 00 24 73 fc 00 00 00 01 ab d4 e7 89 00 00 00 00 00 00 10 80 83 74 99 18 88 00 40 83 73 c0 00 00 80 01 17 f9 00 e0 80
+00 00 00 12 c3 9a 40 00 00 00 08 28 38 09 80 00 00 00 00 00 02 00 0a 3c fb 78 01 c0 00 06 70 68 03 c0 08 00 23 f7 cd 00 04 00
+00 00 00 2c 7b bc 06 40 00 00 ab d7 c9 1a 00 20 00 00 00 00 20 00 b8 f7 c8 1e 80 00 40 47 37 a0 64 00 00 22 ae dc d0 e0 00
+00 00 20 02 c2 17 40 20 00 02 08 28 1a 19 0a 00 00 00 00 00 01 02 09 0c 6e 10 f0 00 00 04 70 02 43 40 00 00 02 cc ff 08 00 00
+00 00 00 00 55 64 c7 00 00 00 81 54 ed 80 00 00 00 00 00 00 20 00 83 77 d9 88 00 00 80 af 57 a0 70 60 00 41 0b dc 01 c0 d8
+00 00 00 10 af 0b bc 38 00 00 29 7c 1f f8 00 04 00 00 00 00 31 00 0a 3c db 70 f0 00 00 00 a0 a4 c4 00 50 00 11 dd a9 1f 00 80
+00 00 00 00 53 7a 03 80 00 40 a3 fe cd 80 00 00 00 00 00 07 00 04 b8 f6 c1 08 00 00 00 e5 df 16 61 00 00 00 95 4c 78 80 08
+00 00 00 80 05 00 1c 40 00 00 28 3a ea f8 00 10 00 00 00 00 02 00 0a 0e 6f 01 00 00 10 04 5b 28 04 0e 00 00 19 ee a0 80 01 40
+00 00 00 00 53 04 07 44 03 00 ab c6 e8 00 00 08 00 00 00 20 00 00 91 f6 17 8e 40 0c 00 00 00 00 74 00 00 00 00 00 d0 f0 10
+00 00 00 80 0a 03 80 2c 00 20 18 28 39 10 00 00 80 00 00 01 80 04 0a 2e ef f8 00 00 80 00 00 00 03 01 00 00 00 00 01 8a 00 00
+00 00
+11 03
+01 01
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 40 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 38 00 80 00 00 00 00 00 02 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 30 00 00 00 40 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 08 00 00 00 00 00 00 20 00 00 00 00 08 00 00 00 00 00 00 00 00 00 00 00 00 00 08 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 08 00 00 00 00 00 00 20 00 00 00 00 0c 00 00 00 00 00 00 30 04 00 00 00 00 00 40 00 00 00 00 00 03 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 03 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 30 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 00 00 00 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 00 00 00 00 00 00 00 00 00 00 00 00 00 20 00 02 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 00 00 00 00 00 00 08 00 00 00 00 00 00 20 00 00 00 00 00 00 80
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 08 00 00 00 00 00 00 00 00 00 00 00 00 00 88 00 00 00 00 00 00 20 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 08 00 00 00 00 00 00 00 00 04 00 00 02 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 02 00 03 00 00 00 00 08 00 00 00 00 00 00 00 00 b9 c0 90 00 00 0c 00 f0 0e 80 00 00 00 01 e3 5b 00 80 00
+80 00 00 00 00 00 00 3c 00 30 00 00 00 00 00 00 00 00 00 00 00 01 0b dd c9 00 80 00 c0 00 f1 ed 60 00 00 00 12 ff c0 19 20 0c
+00 00 01 66 90 00 02 00 00 00 00 00 01 00 00 00 00 00 00 01 00 00 21 42 80 10 00 00 00 f0 0a c4 00 00 00 09 d1 68 00 00 00
+00 00 01 06 69 16 80 64 00 00 00 00 00 01 a0 00 00 00 00 00 00 01 00 14 6c 79 80 00 00 00 f7 27 60 00 00 00 a9 05 97 18 40 00
+00 00 01 26 90 00 00 00 00 00 3f ec c0 0a 00 00 00 00 00 00 00 00 00 02 b1 00 00 00 00 33 b6 42 00 00 00 48 94 19 10 90 00
+00 00 01 83 69 16 80 00 00 00 03 bd dd 01 b0 00 00 00 00 00 00 00 00 14 cb 80 00 00 00 0c c9 6d c0 00 00 10 8b 86 88 00 00 00
+00 02 01 26 90 00 c0 00 00 00 00 00 00 0a 00 00 00 00 00 00 00 00 00 00 09 10 00 00 00 69 54 14 00 00 00 03 04 08 00 c0 08
+00 00 00 83 69 17 a0 00 00 00 00 00 00 58 10 00 00 00 00 00 00 00 00 00 00 81 80 00 00 16 91 62 06 80 00 90 10 86 90 00 00 40
+00 00 08 26 90 40 03 80 00 00 00 00 00 10 00 00 00 00 00 00 00 00 9d 0f 95 00 00 00 10 69 b4 14 20 00 00 01 dc 0b b0 00 00
+00 00 20 93 69 12 80 64 00 00 00 00 00 01 80 00 00 00 00 00 00 00 09 60 ed d8 00 00 00 16 99 3b 46 c0 00 10 11 1c 88 00 00 00
+00 00 08 26 90 40 40 00 02 00 00 00 00 00 00 00 00 00 00 01 00 00 ae 36 d0 00 00 0c 00 69 b4 00 28 00 00 03 c2 fe 71 00 00
+c0 00 00 13 69 12 a6 00 00 30 00 00 00 00 00 00 00 00 00 00 00 00 09 63 6d 01 a0 00 c0 16 91 68 06 c0 00 00 38 75 b0 08 00 0c
+00 00 00 a6 90 00 00 00 00 00 3f fc e0 00 00 00 00 00 00 00 00 00 9d 0e 90 00 00 00 00 69 30 14 00 00 00 09 4e 4e 00 a0 00
+00 00 00 93 69 13 80 00 00 60 03 bc db 00 00 00 00 00 00 00 00 00 09 60 eb 58 00 01 80 16 91 69 40 00 00 01 a8 c6 10 0a 00 18
+00 00 02 a6 90 00 00 00 00 00 00 00 00 00 04 00 00 00 00 04 00 00 00 00 00 0a 00 00 00 69 f0 00 00 00 00 49 fc d8 50 90 00
+00 00 01 13 69 13 80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 10 00 00 16 98 28 06 00 00 00 8f de 91 8b 00 00
+00 00 09 26 90 40 02 00 02 00 00 00 05 0a 00 00 00 00 00 00 00 00 80 04 90 00 00 0c 82 11 02 82 00 00 20 4b c0 00 01 00 00
+c0 00 01 87 69 17 86 04 00 20 00 00 00 00 10 00 00 00 00 00 00 00 18 92 18 00 00 00 84 2d d3 ec 60 00 02 00 bc 0c 00 1e 00 0c
+00 00 09 a6 90 40 22 00 00 00 00 00 05 0a 00 00 00 00 00 00 00 00 82 82 90 00 00 00 00 c3 07 02 00 00 00 03 25 79 90 01 c0
+00 00 00 07 69 16 9e 64 00 00 00 00 00 81 b0 00 00 00 00 00 04 00 48 00 59 00 80 00 04 0a 50 34 e0 00 00 00 0d 94 e8 00 00 00
+00 00 00 a6 90 00 00 10 00 00 01 40 05 00 00 00 00 00 00 00 00 00 80 04 97 00 00 00 00 87 08 06 20 00 00 02 5a 6d 00 00 08
+00 00 00 83 69 16 80 00 30 04 00 15 6c d8 00 00 00 00 00 00 00 00 18 92 08 80 00 00 04 08 71 2b 46 50 00 00 0f 27 95 80 00 00
+00 02 00 26 90 00 00 00 00 00 3f c3 d5 0c 40 80 00 00 00 00 20 00 82 82 90 00 05 00 00 f0 08 02 00 84 00 00 cc 39 90 e0 00
+00 00 00 87 69 17 80 00 00 01 03 bc ec 58 0a 14 00 00 00 00 00 00 18 00 58 00 00 08 00 0f 01 80 e0 10 20 10 33 0d cd 80 00 00
+00 00 00 26 90 40 48 08 40 00 3f ff f0 88 00 00 00 00 00 00 10 00 82 04 90 90 00 00 00 a5 0b 54 6c 00 00 03 e8 2b 50 00 00
+00 00 20 03 69 12 a0 61 02 00 03 bf 7c 18 90 00 00 00 00 00 02 02 08 13 c0 71 e0 00 00 00 f7 f6 62 80 00 00 02 8c a0 00 00 00
+00 00 00 26 90 40 40 05 03 24 3f c0 a0 10 00 00 00 00 00 00 00 00 82 82 a0 80 00 0c 00 f0 07 c0 40 00 30 03 c0 38 51 00 00
+00 00 00 03 69 12 a6 00 00 31 13 bd 78 00 a0 00 00 00 00 00 00 00 08 00 58 79 e0 00 80 00 f3 e0 c2 80 02 00 03 cf b0 0a 00 00
+00 00 00 26 90 00 03 00 00 00 3f dc e0 19 00 00 00 00 00 00 00 00 82 06 97 0e 00 00 00 22 5a 00 6c 20 00 03 e8 1d 58 a0 00
+00 00 00 03 69 13 80 00 30 60 03 bf d8 00 b0 00 00 00 00 00 00 00 08 13 60 81 d0 01 80 0d db f4 62 c2 06 00 17 c7 95 00 00 18
+00 00 02 26 90 00 00 01 00 00 00 00 00 00 00 a0 00 00 00 00 a0 20 82 82 df 0f 00 00 00 dd 3e f4 00 00 00 0b c0 20 d0 00 00
+00 00 00 03 69 13 80 00 70 00 00 00 00 00 00 14 00 00 00 00 80 00 08 00 59 b8 10 00 00 02 29 6c 60 00 00 04 bc 0e 00 00 00 00
+00 00 00 26 90 40 02 08 02 40 80 00 e0 10 00 0c 00 00 00 00 00 00 20 ec b0 18 00 0e 00 67 0a 40 00 00 30 03 48 10 00 00 00
+80 00 00 03 69 17 86 05 00 20 08 15 c8 01 c0 00 c0 00 00 00 00 08 01 9d c8 00 80 04 c4 08 35 bc 02 00 02 10 34 87 e5 00 00 0c
+00 00 00 26 90 40 00 00 40 00 00 00 00 1f 00 00 00 00 00 00 00 04 14 66 f0 88 00 00 00 9b 13 94 00 44 00 01 a4 e9 b0 00 00
+00 00 00 83 69 16 80 60 00 00 00 00 00 01 e0 00 00 00 00 00 00 00 02 9f 4e 31 90 00 00 02 53 24 02 80 20 40 25 94 08 18 00 00
+00 00 00 26 90 00 00 08 00 40 80 01 e0 09 00 00 00 00 00 00 00 24 22 e6 c9 00 00 00 00 67 9a c0 00 00 00 01 7c 2b 30 80 00
+00 00 00 83 69 16 80 00 40 00 08 15 c8 00 00 00 00 00 00 00 00 00 01 28 ea 80 80 00 10 02 5b 79 c0 00 00 20 2b c4 08 00 00 00
+00 02 00 26 90 00 00 28 00 04 80 00 8f 19 00 00 00 00 00 10 00 04 38 95 d0 90 00 02 00 63 0f 04 30 00 00 00 e4 39 00 e0 00
+00 00 00 03 69 17 80 01 00 00 08 15 cd 01 e0 00 00 00 00 00 80 00 02 84 c9 32 e0 00 04 0a 31 ba 06 00 40 10 32 54 e0 00 00 00
+00 00 00 26 90 40 40 08 00 80 80 01 e0 80 00 00 00 00 00 00 00 04 80 02 cf 0e 00 00 00 67 92 96 28 00 02 02 80 2b 00 f0 00
+00 00 20 03 69 12 a0 61 02 00 08 15 d8 10 00 00 00 00 00 00 00 00 08 14 eb 80 10 04 00 02 5d 7c 43 80 00 00 01 44 c0 01 20 00
+00 00 00 26 90 40 40 00 02 00 80 00 c0 00 00 08 00 00 00 00 00 00 80 00 df 1e 00 08 02 04 18 14 00 00 20 09 3a ce 50 80 00
+00 00 00 03 69 12 a6 00 00 20 48 15 cc 00 00 00 c0 00 00 00 00 00 08 15 5b 81 e0 00 80 20 4d e0 02 03 02 01 a3 76 08 01 00 00
+00 00 00 26 90 00 03 90 00 04 80 01 e9 09 00 00 00 00 00 00 00 00 80 02 e7 00 00 00 02 00 06 ce 70 00 00 08 28 1a 00 80 00
+00 00 00 03 69 13 80 00 70 60 08 15 da 00 00 c1 80 00 00 00 00 00 08 14 eb 80 00 01 80 2a 01 e7 c3 c0 06 00 ab dd c5 81 00 18
+00 00 00 26 91 03 c2 0e 00 04 80 00 c1 08 00 00 00 00 00 00 00 00 80 01 df 0a a1 01 02 05 0e 04 3a 80 00 0a bc 2d 10 00 00
+00 00 00 03 69 02 00 7c 00 00 08 15 cd 00 00 00 00 00 00 00 00 00 08 15 5b 70 04 08 00 20 05 f4 02 d0 00 00 81 46 b8 00 00 00
+00 00 01 20 00 ac 20 00 03 00 80 01 d0 90 00 0c 00 00 00 00 00 00 18 c0 c3 10 00 0d 00 0a 0a 02 00 30 30 0a a8 10 00 00 00
+c0 00 00 02 05 3e 4e 30 70 28 0a 81 5c 10 80 00 80 00 00 00 00 03 02 8c da b9 e0 00 d0 00 07 bc 67 07 03 00 aa 8f a0 00 00 08
+00 00 00 20 11 c0 24 00 00 20 81 42 a0 80 00 40 00 00 00 00 00 00 11 55 c1 8d 00 01 00 00 03 c0 00 00 00 09 37 6c 10 00 00
+00 00 00 02 01 df 1e 30 00 00 08 00 dc 10 00 08 00 00 00 00 00 00 02 3d ca b8 10 00 00 00 51 b4 03 80 40 00 a3 b6 18 18 00 00
+00 00 00 20 00 ae e0 00 00 20 90 2c d9 9d 80 00 00 00 00 10 00 00 10 de ff 00 00 00 00 00 0a 00 00 04 04 03 fc 3b 00 88 00
+00 00 00 02 05 7e 6c 38 00 00 0a 03 40 10 90 00 00 00 00 00 00 00 01 9d cc 01 c0 00 20 00 a7 bc 00 00 20 50 3b d6 b0 00 40 00
+00 02 01 20 00 a0 20 00 04 04 82 82 80 80 00 10 00 00 00 18 00 40 2b 6f 90 1e 14 10 02 01 0a bc 00 00 40 02 bc 10 00 00 15
+00 00 00 02 05 5b 4c 38 01 00 08 00 c9 78 00 00 00 00 00 03 00 00 10 32 5e 01 90 00 04 20 25 00 03 80 00 00 2b d4 e0 00 a0 80
+00 00 00 20 00 2e c0 00 00 04 80 01 d0 10 00 00 00 00 00 00 00 01 12 bf 90 80 00 00 04 05 0a 02 00 00 00 08 3d 6f 11 00 00
+00 00 20 02 05 7e 40 78 40 00 0a 81 4e 01 e0 00 00 00 00 00 00 00 01 1e e8 79 e0 00 00 80 07 bc 40 00 00 00 a3 94 e9 9e 00 00
+00 00 01 20 00 a0 00 10 03 00 82 82 e0 80 00 4c 00 00 00 00 00 00 80 02 8d 00 18 0c 02 05 0e 9c 00 02 20 0b 30 20 00 80 00
+00 00 00 02 05 5f 40 00 80 30 08 00 c9 71 e0 08 80 00 00 00 00 00 08 14 5c 19 80 00 80 20 01 62 03 80 43 10 b3 1c 01 81 00 00
+00 00 00 20 00 2c 03 c0 00 00 80 01 d0 09 00 80 00 00 00 20 00 00 80 03 90 00 00 00 02 00 06 40 40 00 00 00 00 1b 00 00 02
+00 00 00 02 05 76 40 04 00 60 0a 81 5e 00 00 11 80 00 00 00 00 00 08 14 fe 00 00 01 80 2a 05 69 c7 00 06 00 01 4f b0 00 00 18
+00 00 00 20 00 e0 00 00 00 00 82 82 c0 00 00 00 00 00 00 00 88 00 80 02 b1 08 14 00 00 ff 02 80 00 05 00 08 3c 1e 00 04 00
+00 00 00 02 05 5b 40 00 00 00 08 00 c9 01 e0 08 00 00 00 00 00 00 08 14 5d 58 00 00 29 4a f1 b0 60 00 20 00 aa 94 e0 00 a0 00
+00 00 00 05 17 bf c3 60 00 00 19 c0 b0 80 01 00 00 00 00 00 00 00 80 01 fd 80 00 0c 04 a7 16 80 00 00 30 02 00 0d 00 e0 00
+80 00 00 08 a7 37 e0 7d 00 05 02 0d cb 70 e0 08 00 00 00 00 00 00 2a 80 cf 70 80 00 c8 00 3b bc 03 80 03 10 00 0c a0 0b 00 08
+00 00 00 46 70 f7 42 c0 00 00 09 b5 df 0a 00 00 00 00 00 02 00 00 82 82 b0 8e a0 00 00 57 b6 42 40 00 00 01 40 2d 31 00 01
+00 00 00 40 83 72 20 00 80 00 02 9e cc 71 c0 00 00 00 00 00 00 00 08 01 ee 10 04 00 20 00 73 b0 43 80 00 00 28 0e 00 1e 00 00
+00 00 00 05 f5 ff e0 00 00 00 19 c2 b0 0f 00 00 00 00 08 00 00 00 80 01 f0 00 18 00 00 17 b2 8c 24 00 08 02 b5 58 00 00 00
+00 00 00 00 81 53 6e 00 30 05 02 0c 69 00 11 c0 00 00 00 00 00 00 0a 80 db 00 00 00 01 02 77 22 e2 c0 00 00 03 3e c3 00 00 00
+00 00 08 06 70 f4 e0 05 44 00 09 b5 c7 0e 0c 30 00 00 00 10 00 80 82 82 ab 0e 18 31 04 5e 3b c6 00 00 40 20 94 3e 10 e0 01
+00 00 00 40 83 56 2e 03 01 00 02 9f cc 78 a0 00 00 00 00 00 00 00 08 01 ee 80 01 d2 00 00 c9 ea e0 00 40 10 29 5d a7 80 00 00
+00 00 00 05 fb 7d 47 80 00 00 19 c3 bb 80 00 00 00 00 00 00 00 00 80 00 f0 00 00 00 04 2e 56 40 3c 20 00 02 bc 0d 10 a0 01
+00 00 00 00 81 5b 40 28 30 01 42 0c 4f 90 00 00 00 00 00 00 00 04 0a 80 db 79 e0 00 00 02 5b bc 00 40 00 00 17 cc 08 00 a0 00
+00 00 00 86 70 75 e3 92 00 00 20 fe bd 10 00 00 00 00 00 00 00 00 82 82 90 b0 00 08 02 01 3c 00 28 00 30 08 00 1e 08 00 00
+c0 00 00 40 83 5e 94 00 85 00 01 9f c9 01 80 00 00 00 00 00 00 00 18 01 ef 31 e0 00 c0 20 19 f0 60 40 02 00 81 57 97 1e 00 08
+00 00 00 05 fb ff 60 08 50 00 19 c0 b9 0d 00 00 00 00 00 00 00 01 80 01 ff 00 00 00 02 00 06 42 40 00 00 08 05 50 98 c0 00
+00 00 00 00 81 9b 4e 31 32 81 42 0c 7f 00 10 00 00 00 00 00 70 00 0a 80 c9 80 00 01 80 20 53 f5 42 81 06 80 80 7f 81 01 00 18
+00 00 00 88 9b 34 00 15 00 00 2b cf bb 19 04 00 00 00 00 02 00 01 82 82 ff 00 00 00 02 00 0b 14 60 00 00 08 00 0e 00 00 00
+00 00 00 00 c7 fe 14 02 81 80 02 07 4d 80 b0 00 00 00 00 00 00 00 08 01 ef 80 00 00 00 20 51 a6 03 c0 00 00 81 57 f0 1e 00 00
+00 00 00 20 29 bd e0 00 02 00 19 c0 d7 19 00 00 00 00 00 00 00 00 24 c0 a0 0f 00 0c 00 00 00 1e 00 00 00 11 3c 2e 01 80 00
+80 00 00 12 01 38 6c 30 04 25 02 0d fc 00 80 00 00 00 00 00 00 01 02 8d 48 10 80 00 80 00 00 00 e0 02 00 10 2b 9d f0 0f 00 08
+00 00 00 20 00 fc 24 08 00 00 06 7e e0 1d 00 00 00 00 00 10 10 00 14 6e c1 80 00 00 00 f0 08 2e 00 00 00 01 9c 08 10 00 00
+00 00 00 02 05 7a 16 30 01 00 02 9c 5c 38 f0 00 00 00 00 02 80 00 02 9d d8 79 80 02 08 0f 03 02 c0 10 50 10 20 d7 cf 8c 00 00
+00 00 08 20 29 3e c0 00 00 04 19 c0 d0 0a 00 00 00 00 00 00 40 00 05 fd b0 08 00 81 80 05 0c 2e 01 00 00 01 0f cc 01 80 00
+00 00 00 02 01 78 40 01 00 01 02 0c 7a 00 f4 00 00 00 00 00 02 00 00 9d fa 00 01 c0 00 80 53 fa e2 00 00 00 19 dc 80 0d 00 00
+00 02 00 20 00 e8 00 00 00 00 06 7c e5 0c 00 00 00 00 00 00 00 00 26 c1 ef 1b 00 00 00 00 0b fe 40 00 0a 48 64 0c b1 00 12
+00 00 00 02 05 7a 00 00 00 00 02 9d da b8 e0 00 00 00 00 00 00 01 02 0c ce 00 f0 00 10 40 a7 76 e7 00 20 13 91 94 98 1e 00 a0
+00 00 00 20 29 3c 00 00 00 00 19 c2 d0 1f 00 00 00 00 00 00 00 00 11 5d f0 0b 00 00 00 00 00 00 40 00 00 00 00 0f 00 d0 00
+00 00 20 02 01 70 40 3b 00 09 02 0d 4c 00 f0 c0 00 00 00 00 00 00 02 3e d8 79 d2 02 00 00 00 00 07 ad 00 00 29 40 80 01 80 00
+00 00 00 20 00 e8 00 00 03 00 06 7e e0 00 80 00 00 00 00 10 20 00 82 82 f1 88 00 0c 10 00 ba 96 28 00 08 08 14 09 00 90 00
+80 00 00 02 05 7a 5e 38 00 20 02 9d f8 50 00 00 00 00 00 02 05 00 08 00 5a f8 f0 08 a0 40 4b e7 e0 45 00 85 96 94 81 80 00 0c
+00 00 00 20 29 be c3 00 00 40 19 c3 d0 1a 20 00 00 00 00 00 00 00 80 00 9d 1b 00 00 00 2b ff 0c c0 40 04 49 1d 68 00 e0 00
+00 00 00 02 01 18 60 05 00 61 02 0c 4c 01 a4 80 00 00 00 00 00 00 0a 80 7c 00 b0 01 80 02 7b 60 03 80 00 00 a0 15 c0 00 00 18
+00 00 00 20 00 fc 00 00 00 00 06 7c e9 80 00 00 00 00 00 00 80 00 82 82 f0 89 00 00 00 0b fa c0 00 00 00 09 54 28 10 80 00
+00 00 00 02 05 7a 4c 00 00 00 02 9d ec 90 00 00 00 00 00 00 00 00 08 00 5b 70 01 00 01 0a b5 28 00 00 00 a5 aa 9c 08 19 20 00
+00 00 00 20 00 74 00 00 02 40 82 36 f0 00 00 08 00 00 00 00 08 00 29 cd b0 98 00 0d 00 c7 02 42 2d 00 20 02 94 2c 11 b1 80
+40 00 00 82 05 52 4e 01 00 20 08 11 c0 38 01 00 c0 00 00 00 00 84 00 07 df 58 90 10 c4 08 93 78 43 20 02 00 02 9c e9 0e 00 0c
+00 00 00 20 00 f0 23 40 00 04 82 83 8f 80 00 00 00 00 00 04 00 40 16 c5 90 8e 00 00 00 db 0e ee 64 00 00 0c 3c 20 09 00 14
+40 00 00 82 05 3a ce 74 00 80 08 01 ca 10 00 00 00 00 00 00 00 00 00 04 fb 71 91 00 04 00 55 21 e2 00 00 02 83 cc 07 9e 00 8c
+00 00 00 20 00 f4 c2 d6 20 00 82 34 f0 2e 00 20 00 00 00 00 00 80 20 5d c3 0d 00 00 00 81 0f 8c 6d 70 00 02 2c eb 10 00 00
+00 00 00 82 05 3a 5e 07 35 00 28 11 60 00 04 08 00 00 00 00 00 00 03 9e 0d b8 d0 00 04 08 b7 ba 0b 00 00 01 21 6c 89 8e 00 00
+00 02 00 60 00 fe c0 00 08 00 82 83 b0 09 1c 00 00 00 00 01 00 00 81 43 cf 1e b4 00 00 af 06 04 78 00 0a 40 00 3d 78 00 00
+00 00 00 02 05 3a c0 00 00 00 08 01 cb 02 00 00 00 00 00 00 50 00 0a bc 4a 00 b0 00 00 00 53 62 03 c0 20 21 28 1f 85 1e 00 00
+00 00 00 20 00 f4 00 00 00 00 82 36 f0 90 00 00 00 00 00 00 00 80 91 ec e1 2b 00 00 00 6e 9b c0 00 00 04 00 14 3f 00 00 00
+00 00 20 82 05 32 40 00 02 00 08 10 60 10 80 00 00 00 00 00 00 00 0a 2e e0 01 e0 10 00 08 5b 38 00 00 10 07 00 0d f0 00 00 00
+00 00 00 20 00 a4 c4 00 03 20 82 83 c1 10 a0 08 00 00 00 10 00 00 81 40 c7 00 00 0c 02 0a 02 9e 40 20 20 42 bc 2d 71 04 10
+00 00 00 02 05 3b a0 68 00 b0 08 01 ca 00 80 00 80 00 00 02 80 00 0a bc 6c 80 00 00 c0 20 03 f9 e3 80 02 a4 17 de 08 1e 80 90
+00 00 00 20 00 74 03 90 48 20 82 34 f9 00 9c 00 00 00 00 28 00 00 97 c2 a9 90 00 02 02 00 07 3e 39 40 00 23 00 20 00 00 00
+40 00 00 06 05 72 40 00 b2 60 08 11 40 00 01 41 80 00 00 01 00 00 08 14 ed 50 a0 01 80 2a 03 e5 c0 28 06 10 30 0e 01 00 00 14
+00 00 00 60 00 e0 c2 c0 00 00 82 83 f1 08 00 00 00 00 00 00 00 00 82 82 a0 08 10 00 02 0a 03 66 34 00 00 00 11 6e 00 80 00
+00 00 00 02 05 3a a0 04 00 00 18 01 cb 00 00 00 00 00 00 00 00 00 0a bc 6f 58 14 00 10 20 03 fd c0 00 00 00 00 0f f0 01 00 04
+00 00 08 08 b0 a0 23 c0 02 00 01 42 dd 90 00 88 00 00 00 00 00 40 11 c3 d9 00 1c 01 02 05 0a 40 30 e0 32 09 1e ed 00 90 02
+80 00 00 40 47 58 5c 01 00 20 02 bd 6e 90 c4 00 80 00 00 00 00 01 01 08 4f 00 01 80 00 2a f7 f8 67 40 02 01 b0 f5 80 00 00 ac
+00 00 00 00 50 3c 60 00 60 00 97 c2 cb 00 01 00 00 00 00 18 20 00 2a 80 b0 00 0c 00 06 55 0b 40 20 01 04 0b 0e 4d 09 00 10
+00 00 00 00 af 7e b6 60 01 00 08 15 ea f1 80 00 00 00 00 02 d4 00 02 94 e9 10 80 00 00 2a 51 7c 43 40 00 00 91 f7 f3 9e 00 80
+00 00 00 a0 50 67 c3 00 50 00 01 42 d1 8d 00 00 00 00 00 00 00 80 01 41 c9 00 00 00 80 67 0f 04 3a 80 00 48 39 d8 90 e1 00
+00 00 00 02 af 5b 00 00 02 04 02 bc e8 b8 10 00 00 00 00 00 00 00 02 bd cb 38 80 00 04 08 33 b2 03 80 00 00 a3 f7 d1 80 00 00
+00 02 00 60 a0 7d c0 11 00 00 82 82 db 9f 00 00 00 00 00 00 10 00 02 80 a0 00 00 80 00 0b 13 c6 02 62 00 2b 0c ed 08 f0 00
+00 00 00 02 af 5a 60 02 00 04 0a bd ca 10 c0 00 00 00 00 00 12 04 02 bd 5c 00 00 04 00 0a bb b7 43 90 00 01 91 d7 f7 00 00 00
+00 00 00 a0 50 a4 02 00 20 02 81 42 a0 00 80 00 00 00 00 00 00 00 00 00 07 80 00 00 02 0a 0b 80 00 04 08 0b 0e 7e 70 98 00
+00 00 20 12 af 57 16 64 54 00 0a bd fc 7a 00 14 00 00 00 00 00 00 00 00 00 f0 a0 00 00 2a f5 24 07 83 20 01 91 dd d8 18 00 00
+00 00 00 20 a0 f4 c2 38 00 04 82 82 b0 8a a0 28 00 00 00 04 40 00 20 43 f0 0a 00 80 02 5f 0f 40 01 10 00 0b 0e 6d f0 04 08
+00 00 00 8a af 72 e6 7c 01 00 0a bc ea 10 04 02 80 00 00 00 72 09 01 1d 7c 59 a0 00 10 20 53 20 67 88 00 80 91 d5 ff 80 21 00
+00 00 01 20 50 2c 03 c0 25 00 81 42 a7 09 00 40 00 00 00 00 02 00 01 41 c5 00 00 00 02 0a 0b 40 2c 01 50 0b 0c 7e 11 e0 01
+40 80 00 0a af 77 00 3c 03 40 0a bd de 80 00 09 80 00 00 00 20 00 02 bd 7d 00 00 00 20 2a f7 20 00 40 24 84 91 d5 df 89 00 14
+00 00 08 60 a0 60 23 c0 00 00 97 c0 97 08 0c 00 00 00 00 00 80 80 17 c2 9d 00 00 40 02 a7 3b 80 bc 00 04 0b 0c 6d 10 81 80
+00 00 00 02 af 52 96 04 00 00 08 14 cb 00 10 00 00 00 00 01 00 00 00 15 fd 00 a0 00 10 22 5b 38 e0 40 50 01 91 c7 f9 99 00 00
+00 00
+62 00 3f
+72 00 80
+11 00
+82 00 00
+01 03
+00 00 00 00 c0 00 00 e4
+00 00 00 00 c6 66 00 e4
+00 00 00 00 cc cd 00 e4
+00 00 00 00 d3 33 00 e4
+00 00 00 00 d9 9a 00 e4
+00 00 00 00 e0 00 00 e4
+00 00 00 00 e6 66 00 e4
+00 00 00 00 ec cd 00 e4
+00 00 00 00 f3 33 00 e4
+00 00 00 00 f9 9a 00 e4
+00 00 00 00 00 00 00 e5
+00 00 00 00 06 66 00 e5
+00 00 00 00 0c cd 00 e5
+00 00 00 00 13 33 00 e5
+00 00 00 00 19 9a 00 e5
+00 00 00 00 20 00 00 e5
+00 00 00 00 26 66 00 e5
+00 00 00 00 2c cd 00 e5
+00 00 00 00 33 33 00 e5
+00 00 00 00 39 9a 00 e5
+00 00 00 00 40 00 00 e5
+00 00 00 00 46 66 00 e5
+00 00 00 00 4c cd 00 e5
+00 00 00 00 53 33 00 e5
+00 00 00 00 59 9a 00 e5
+00 00 00 00 60 00 00 e5
+00 00 00 00 66 66 00 e5
+00 00 00 00 6c cd 00 e5
+00 00 00 00 73 33 00 e5
+00 00 00 00 79 9a 00 e5
+00 00 00 00 80 00 00 e5
+00 00 00 00 86 66 00 e5
+00 00 00 00 8c cd 00 e5
+00 00 00 00 93 33 00 e5
+00 00 00 00 99 9a 00 e5
+00 00 00 00 a0 00 00 e5
+00 00 00 00 a6 66 00 e5
+00 00 00 00 ac cd 00 e5
+00 00 00 00 b3 33 00 e5
+00 00 00 00 b9 9a 00 e5
+00 00 00 00 c0 00 00 e5
+00 00 00 00 c6 66 00 e5
+00 00 00 00 cc cd 00 e5
+00 00 00 00 d3 33 00 e5
+00 00 00 00 d9 9a 00 e5
+00 00 00 00 e0 00 00 e5
+00 00 00 00 e6 66 00 e5
+00 00 00 00 ec cd 00 e5
+00 00 00 00 f3 33 00 e5
+00 00 00 00 f9 9a 00 e5
+00 00 00 00 00 00 00 e6
+00 00 00 00 06 66 00 e6
+00 00 00 00 0c cd 00 e6
+00 00 00 00 13 33 00 e6
+00 00 00 00 19 9a 00 e6
+00 00 00 00 20 00 00 e6
+00 00 00 00 26 66 00 e6
+00 00 00 00 2c cd 00 e6
+00 00 00 00 33 33 00 e6
+00 00 00 00 39 9a 00 e6
+00 00 00 00 40 00 00 e6
+00 00 00 00 46 66 00 e6
+00 00 00 00 4c cd 00 e6
+00 00 00 00 53 33 00 e6
+00 00 00 00 59 9a 00 e6
+00 00 00 00 60 00 00 e6
+00 00 00 00 66 66 00 e6
+00 00 00 00 6c cd 00 e6
+00 00 00 00 73 33 00 e6
+00 00 00 00 79 9a 00 e6
+00 00 00 00 80 00 00 e6
+00 00 00 00 86 66 00 e6
+00 00 00 00 8c cd 00 e6
+00 00 00 00 93 33 00 e6
+00 00 00 00 99 9a 00 e6
+00 00 00 00 a0 00 00 e6
+00 00 00 00 a6 66 00 e6
+00 00 00 00 ac cd 00 e6
+00 00 00 00 b3 33 00 e6
+00 00 00 00 b9 9a 00 e6
+00 00 00 00 c0 00 00 e6
+00 00 00 00 c6 66 00 e6
+00 00 00 00 cc cd 00 e6
+00 00 00 00 d3 33 00 e6
+00 00 00 00 d9 9a 00 e6
+00 00 00 00 e0 00 00 e6
+00 00 00 00 e6 66 00 e6
+00 00 00 00 ec cd 00 e6
+00 00 00 00 f3 33 00 e6
+00 00 00 00 f9 9a 00 e6
+00 00 00 00 00 00 00 e7
+00 00 00 00 06 66 00 e7
+00 00 00 00 0c cd 00 e7
+00 00 00 00 13 33 00 e7
+00 00 00 00 19 9a 00 e7
+00 00 00 00 20 00 00 e7
+00 00 00 00 26 66 00 e7
+00 00 00 00 2c cd 00 e7
+00 00 00 00 33 33 00 e7
+00 00 00 00 39 9a 00 e7
+00 00 00 00 40 00 00 e7
+00 00 00 00 46 66 00 e7
+00 00 00 00 4c cd 00 e7
+00 00 00 00 53 33 00 e7
+00 00 00 00 59 9a 00 e7
+00 00 00 00 60 00 00 e7
+00 00 00 00 66 66 00 e7
+00 00 00 00 6c cd 00 e7
+00 00 00 00 73 33 00 e7
+00 00 00 00 79 9a 00 e7
+00 00 00 00 80 00 00 e7
+00 00 00 00 86 66 00 e7
+00 00 00 00 8c cd 00 e7
+00 00 00 00 93 33 00 e7
+00 00 00 00 99 9a 00 e7
+00 00 00 00 a0 00 00 e7
+00 00 00 00 a6 66 00 e7
+00 00 00 00 ac cd 00 e7
+00 00 00 00 b3 33 00 e7
+00 00 00 00 b9 9a 00 e7
+00 00 00 00 c0 00 00 e7
+00 00 00 00 c6 66 00 e7
+00 00 00 00 cc cd 00 e7
+00 00 00 00 d3 33 00 e7
+00 00 00 00 d9 9a 00 e7
+00 00 00 00 e0 00 00 e7
+00 00 00 00 e6 66 00 e7
+00 00 00 00 ec cd 00 e7
+00 00
+82 00 80
+01 03
+00 00 00 00 f3 33 00 e7
+00 00 00 00 f9 9a 00 e7
+00 00 00 00 00 00 00 e8
+00 00 00 00 06 66 00 e8
+00 00 00 00 0c cd 00 e8
+00 00 00 00 13 33 00 e8
+00 00 00 00 19 9a 00 e8
+00 00 00 00 20 00 00 e8
+00 00 00 00 26 66 00 e8
+00 00 00 00 2c cd 00 e8
+00 00 00 00 33 33 00 e8
+00 00 00 00 39 9a 00 e8
+00 00 00 00 40 00 00 e8
+00 00 00 00 46 66 00 e8
+00 00 00 00 4c cd 00 e8
+00 00 00 00 53 33 00 e8
+00 00 00 00 59 9a 00 e8
+00 00 00 00 60 00 00 e8
+00 00 00 00 66 66 00 e8
+00 00 00 00 6c cd 00 e8
+00 00 00 00 73 33 00 e8
+00 00 00 00 79 9a 00 e8
+00 00 00 00 80 00 00 e8
+00 00 00 00 86 66 00 e8
+00 00 00 00 8c cd 00 e8
+00 00 00 00 93 33 00 e8
+00 00 00 00 99 9a 00 e8
+00 00 00 00 a0 00 00 e8
+00 00 00 00 a6 66 00 e8
+00 00 00 00 ac cd 00 e8
+00 00 00 00 b3 33 00 e8
+00 00 00 00 b9 9a 00 e8
+00 00 00 00 c0 00 00 e8
+00 00 00 00 c6 66 00 e8
+00 00 00 00 cc cd 00 e8
+00 00 00 00 d3 33 00 e8
+00 00 00 00 d9 9a 00 e8
+00 00 00 00 e0 00 00 e8
+00 00 00 00 e6 66 00 e8
+00 00 00 00 ec cd 00 e8
+00 00 00 00 f3 33 00 e8
+00 00 00 00 f9 9a 00 e8
+00 00 00 00 00 00 00 e9
+00 00 00 00 06 66 00 e9
+00 00 00 00 0c cd 00 e9
+00 00 00 00 13 33 00 e9
+00 00 00 00 19 9a 00 e9
+00 00 00 00 20 00 00 e9
+00 00 00 00 26 66 00 e9
+00 00 00 00 2c cd 00 e9
+00 00 00 00 33 33 00 e9
+00 00 00 00 39 9a 00 e9
+00 00 00 00 40 00 00 e9
+00 00 00 00 46 66 00 e9
+00 00 00 00 4c cd 00 e9
+00 00 00 00 53 33 00 e9
+00 00 00 00 59 9a 00 e9
+00 00 00 00 60 00 00 e9
+00 00 00 00 66 66 00 e9
+00 00 00 00 6c cd 00 e9
+00 00 00 00 73 33 00 e9
+00 00 00 00 79 9a 00 e9
+00 00 00 00 80 00 00 e9
+00 00 00 00 86 66 00 e9
+00 00 00 00 8c cd 00 e9
+00 00 00 00 93 33 00 e9
+00 00 00 00 99 9a 00 e9
+00 00 00 00 a0 00 00 e9
+00 00 00 00 a6 66 00 e9
+00 00 00 00 ac cd 00 e9
+00 00 00 00 b3 33 00 e9
+00 00 00 00 b9 9a 00 e9
+00 00 00 00 c0 00 00 e9
+00 00 00 00 c6 66 00 e9
+00 00 00 00 cc cd 00 e9
+00 00 00 00 d3 33 00 e9
+00 00 00 00 d9 9a 00 e9
+00 00 00 00 e0 00 00 e9
+00 00 00 00 e6 66 00 e9
+00 00 00 00 ec cd 00 e9
+00 00 00 00 f3 33 00 e9
+00 00 00 00 f9 9a 00 e9
+00 00 00 00 00 00 00 ea
+00 00 00 00 06 66 00 ea
+00 00 00 00 0c cd 00 ea
+00 00 00 00 13 33 00 ea
+00 00 00 00 19 9a 00 ea
+00 00 00 00 20 00 00 ea
+00 00 00 00 26 66 00 ea
+00 00 00 00 2c cd 00 ea
+00 00 00 00 33 33 00 ea
+00 00 00 00 39 9a 00 ea
+00 00 00 00 40 00 00 ea
+00 00 00 00 46 66 00 ea
+00 00 00 00 4c cd 00 ea
+00 00 00 00 53 33 00 ea
+00 00 00 00 59 9a 00 ea
+00 00 00 00 60 00 00 ea
+00 00 00 00 66 66 00 ea
+00 00 00 00 6c cd 00 ea
+00 00 00 00 73 33 00 ea
+00 00 00 00 79 9a 00 ea
+00 00 00 00 80 00 00 ea
+00 00 00 00 86 66 00 ea
+00 00 00 00 8c cd 00 ea
+00 00 00 00 93 33 00 ea
+00 00 00 00 99 9a 00 ea
+00 00 00 00 a0 00 00 ea
+00 00 00 00 a6 66 00 ea
+00 00 00 00 ac cd 00 ea
+00 00 00 00 b3 33 00 ea
+00 00 00 00 b9 9a 00 ea
+00 00 00 00 c0 00 00 ea
+00 00 00 00 c6 66 00 ea
+00 00 00 00 cc cd 00 ea
+00 00 00 00 d3 33 00 ea
+00 00 00 00 d9 9a 00 ea
+00 00 00 00 e0 00 00 ea
+00 00 00 00 e6 66 00 ea
+00 00 00 00 ec cd 00 ea
+00 00 00 00 f3 33 00 ea
+00 00 00 00 f9 9a 00 ea
+00 00 00 00 00 00 00 eb
+00 00 00 00 06 66 00 eb
+00 00 00 00 0c cd 00 eb
+00 00 00 00 13 33 00 eb
+00 00 00 00 19 9a 00 eb
+00 00 00 00 20 00 00 eb
+00 00
+11 01
+82 00 00
+01 03
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00
+82 00 80
+01 03
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00
+11 02
+82 00 00
+01 03
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00
+82 00 80
+01 03
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00
+11 03
+82 00 00
+01 03
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00
+82 00 80
+01 03
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00
+22
+38 79
+01 06
+
diff --git a/fpga/SX1301_FPGA_NOTCH_PROG_SPECTRAL_SCAN_v31.hex b/fpga/SX1301_FPGA_NOTCH_PROG_SPECTRAL_SCAN_v31.hex
new file mode 100644
index 0000000..b15c4fc
--- /dev/null
+++ b/fpga/SX1301_FPGA_NOTCH_PROG_SPECTRAL_SCAN_v31.hex
@@ -0,0 +1,1659 @@
+ff 00
+4c 61 74 74 69 63 65 00
+69 43 45 63 75 62 65 32 20 32 30 31 35 2e 30 34 2e 32 37 34 30 39 00
+50 61 72 74 3a 20 69 43 45 34 30 4c 50 31 4b 2d 43 4d 34 39 00
+44 61 74 65 3a 20 53 65 70 20 31 20 32 30 31 36 20 31 36 3a 34 33 3a 34 37 00
+00 ff
+7e aa 99 7e
+51 00
+01 05
+92 00 20
+62 01 4b
+72 00 90
+82 00 00
+11 00
+01 01
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 40 05 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 03 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 10 00 00
+00 00 00 00 00 04 00 00 00 00 00 00 10 00 00 00 00 00 00 40 00 00 00 00 10 00 00 00 00 00 00 40 00 00 00 00 00 81 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 18 00 00 00 00
+00 00 00 00 00 04 00 00 00 00 00 00 10 00 00 00 00 00 00 40 00 00 00 00 10 00 00 00 00 00 00 40 00 00 00 00 00 03 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 08 00 00 00 20 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 04 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 08 00 00 00 00 00 00
+00 00 00 00 00 0d 7a 95 00 00 02 00 46 8b 7c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 40 01 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 d4 15 50 00 00 04 3f c8 12 4a 00 78 00 00 00 00 00 00 00 00 00 00 00 02 00 c0 00 00 00 00 00 00 00 00 00 00
+00 00 18 00 00 08 3b 45 00 60 03 c0 7c 99 5c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 20 00 78 a0 00
+00 00 00 00 00 00 f2 b8 90 00 00 06 2b 48 56 60 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 03 42 02 0a 00 00
+00 00 00 00 80 00 7b 15 00 40 00 46 26 8b 7e 00 00 00 00 00 00 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 01 00 b7 b2 90 04 00 00 00 cd 12 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 02 00 00 00 a3 3a 80 40 00 03 66 94 99 5c 00 00 00 00 00 00 00 10 02 00 00 00 00 00 00 0a 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 10 08 28 00 40 00 14 2d e8 56 48 00 00 00 00 00 00 00 00 40 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 18 2a 80 00 00 00 00 66 9b 7e 00 00 00 00 00 00 00 00 00 3c ef 50 10 00 00 00 fb bf c0 00 00 00 00 00 00 00
+00 00 20 00 00 08 30 14 00 00 00 00 23 48 12 40 00 00 00 00 00 00 00 00 03 50 50 00 40 00 00 0d 67 f8 40 00 00 00 00 00 00 00
+00 00 00 00 00 03 ba 80 00 00 00 06 74 99 5c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 00 00 04 00 00 00 00 00 00
+00 00 00 00 01 00 00 28 00 00 00 34 21 48 56 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 40 00 00 00 00 00 00
+00 00 00 00 18 08 02 04 00 00 02 67 26 9b 7c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 33 50 80 00 00 0c 01 4d 12 40 00 00 00 00 00 00 00 04 3c 00 00 00 00 00 00 c0 00 00 00 00 00 00 00 00 00 00
+00 00 30 00 70 05 f2 80 00 c0 00 40 26 9b 74 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 03 00 00 0c 08 28 00 0c 00 02 00 6d 21 41 00 00 00 00 00 00 00 00 00 00 00 00 01 00 30 00 00 00 00 10 00 00 00 00 00 00
+00 00 00 00 81 e1 6a 95 80 00 01 42 96 aa 00 00 00 00 00 00 00 00 00 06 a5 cf 50 00 00 10 0e d2 2b c0 00 00 20 05 58 a0 60
+00 00 00 00 01 00 1c 2a 90 00 08 14 00 10 a0 00 00 00 00 00 00 00 00 00 41 60 a0 01 00 00 11 03 43 fc c0 00 01 43 a4 0f 56 98
+00 00 18 00 00 8f 7a 95 00 00 01 e0 01 ea 00 00 00 00 00 00 00 00 a1 60 36 ef 50 00 00 05 80 77 a0 00 0a 00 bc 00 00 00 00
+00 00 00 00 00 10 90 15 54 00 00 02 01 50 50 00 00 30 00 00 00 00 00 02 01 d0 50 01 00 00 10 0d 74 00 00 a0 13 60 00 00 00 00
+00 00 00 00 00 08 3b 45 00 00 09 c3 24 98 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 bb 00 44 80 00 34 29 6a 05 00
+00 00 00 00 00 00 77 b8 90 00 01 76 29 5b 00 00 00 00 00 00 00 00 00 00 20 00 00 00 00 02 30 cb 81 48 40 00 00 66 c0 00 51 00
+00 02 00 00 81 90 00 00 00 00 01 42 a4 c8 00 20 00 00 00 00 00 00 00 40 00 00 00 03 00 00 00 7b e0 48 00 0e 04 60 0a 50 00
+00 00 00 00 0d 0f 00 00 00 00 00 14 2b 40 00 01 00 00 00 00 00 00 00 80 00 00 00 00 20 00 00 0b 62 80 60 00 03 60 15 0a 00 80
+00 00 00 00 00 07 6a 80 00 00 02 00 07 af 50 00 00 00 00 00 00 00 00 00 26 ef 50 00 00 0b 0c 03 94 00 00 00 00 01 4a 05 00
+00 00 20 00 00 00 08 28 00 00 06 04 03 50 50 00 40 00 00 00 00 00 00 00 3d 40 a0 01 00 00 50 03 42 80 00 00 00 00 02 00 51 00
+00 00 00 00 98 08 7b 15 00 00 00 07 bd af 50 00 00 00 00 00 00 00 15 c2 0e c5 00 00 00 20 18 10 49 00 00 00 40 20 0a 50 20
+00 00 00 00 03 00 33 f2 90 00 04 00 70 40 a0 00 40 00 00 00 00 00 00 be 43 50 00 00 00 01 10 e3 34 00 01 00 08 04 14 0a 00 00
+00 00 00 00 18 13 ea 80 00 00 09 c0 01 ca 00 00 00 00 00 00 00 00 00 47 80 b1 20 00 00 07 9c 83 81 48 10 00 1c 00 fe a0 40
+80 00 00 00 00 08 00 28 00 20 01 42 01 50 50 00 00 00 00 00 00 00 00 1e 02 dc 21 00 00 00 f8 81 00 28 82 00 00 20 07 0f 54 00
+00 00 30 00 30 0d fa 95 00 0a 00 03 8e aa 00 00 00 50 00 00 00 00 14 60 3e e0 20 20 00 03 1e 77 bd 40 04 00 00 06 7a f5 49
+00 00 01 00 00 00 38 15 50 00 40 00 00 20 a0 08 00 02 00 00 00 00 01 84 02 c0 a1 11 00 00 00 0d 43 fc 20 c0 00 02 2d 05 04 04
+00 00 00 00 78 07 37 dc 02 00 00 00 1c ea f4 00 00 00 00 30 10 00 00 00 00 e0 50 00 00 08 00 b7 29 58 00 40 00 02 08 84 d0
+00 00 00 00 00 8b da 7f c0 10 00 00 01 d0 a0 c0 00 00 00 c5 82 00 00 00 3e 50 0a 00 00 00 90 01 41 55 00 02 20 00 1c c1 24 20
+00 00 28 00 78 08 7b 15 00 a0 00 00 00 ea a4 01 80 08 1b 78 08 00 06 00 00 c5 00 81 80 4f 80 00 00 00 06 c1 20 02 09 84 c0
+00 00 02 00 00 0b 57 32 b0 08 0c 0c 03 c0 55 c1 00 00 90 f7 01 00 a0 34 3f c0 a0 00 00 02 b0 00 00 00 00 0e 01 40 0c e1 24 00
+00 00 00 00 19 8b ba 81 00 c0 00 00 40 00 00 00 00 09 80 78 00 00 11 e0 7d ef 50 03 00 00 00 07 03 c0 04 00 00 3f 48 84 c0
+00 00 00 00 00 8b dc 3e b0 04 00 1c 38 00 00 00 00 00 98 09 81 00 00 82 2b 70 50 00 30 00 00 00 40 3c 40 c0 04 03 5e 01 24 00
+00 02 00 00 81 88 2f 91 00 00 00 00 0e 00 00 00 00 01 00 18 00 00 84 06 c1 85 00 00 00 07 00 93 bd 44 00 00 56 6f 68 84 c0
+00 00 00 00 01 00 f7 76 30 00 00 01 03 40 a5 00 00 00 00 05 82 00 00 80 6b c0 a0 00 00 00 00 01 01 40 20 00 00 02 8e 01 24 00
+00 00 00 00 98 05 e2 91 00 04 00 00 14 a5 00 04 00 08 1a f8 02 00 00 00 1d a5 00 00 40 05 81 07 94 00 00 00 00 03 68 84 c0
+00 00 20 00 05 0a b3 39 50 00 20 00 38 20 50 00 08 00 50 01 02 00 00 3c 00 30 50 20 00 08 08 e1 42 80 00 00 c0 40 1e 01 24 00
+00 00 00 00 00 e3 3b e8 00 00 00 00 1c 00 00 00 00 09 80 b0 08 00 00 00 00 a5 00 00 00 00 08 13 14 00 00 00 06 03 68 84 e0
+00 00 00 00 00 00 00 3e 80 00 00 04 03 60 a5 00 00 00 98 03 02 00 00 00 03 c0 a0 00 00 00 00 f0 41 40 00 00 00 60 0c 01 24 00
+00 00 00 00 58 17 e2 85 08 00 02 66 80 00 00 00 00 00 01 98 00 00 00 00 5c a5 02 00 08 0b 8c 03 94 00 00 00 20 03 c8 84 c8
+00 00 00 00 00 08 98 2d 50 00 00 04 6c 00 00 00 00 00 10 a3 80 00 00 00 38 30 50 00 00 00 78 01 02 80 00 00 e1 c0 1c 01 24 00
+00 00 30 00 00 f5 aa 15 00 c0 00 00 06 00 00 01 00 09 1a 78 00 00 00 00 01 85 00 01 00 50 01 17 14 00 0c 02 a6 02 68 84 e0
+00 00 02 00 00 08 da 39 50 08 00 00 03 40 a5 00 30 00 b8 ef 82 40 00 00 3f d0 a0 00 30 00 00 e0 41 40 00 40 02 60 0c 01 24 00
+00 00 00 00 98 00 32 bd 00 10 09 60 14 da 14 00 00 00 0e 38 10 00 00 06 dd 85 02 00 00 80 00 76 94 00 00 80 56 3d 48 84 d0
+00 00 00 00 01 80 10 17 d0 01 00 14 00 eb 7a 40 00 20 00 0b 00 00 00 00 6c 00 50 00 00 28 00 00 01 40 00 00 08 02 b4 01 24 40
+00 00 28 00 80 01 33 dc 00 a0 00 00 0c ea 04 09 80 09 80 18 00 00 21 60 47 cf 50 00 00 00 00 07 14 00 06 40 20 39 68 84 c0
+00 00 02 00 0f 00 56 3f c0 58 00 00 00 40 f5 c1 00 00 b8 03 01 40 00 3c 2a 70 a0 00 00 00 00 07 42 80 00 0a 01 c0 26 01 26 00
+00 00 01 00 80 00 01 99 08 00 01 46 40 a0 50 00 00 07 01 30 02 00 00 00 2c e8 01 20 00 08 00 77 94 00 0c 00 a0 39 68 84 c0
+00 00 00 09 89 00 b0 26 70 00 00 80 29 50 0a 00 00 00 00 9f 81 00 00 00 3f e0 e5 00 01 00 70 00 41 40 00 c0 11 40 36 01 25 00
+00 02 00 00 18 00 00 00 00 00 02 06 04 ab 04 20 00 07 80 b8 00 00 00 00 41 85 02 00 00 00 0e 03 14 00 10 00 80 6c 48 84 c0
+00 00 00 80 00 00 00 00 00 02 00 04 00 d0 f2 40 00 00 00 07 81 40 00 40 39 d0 a0 00 09 00 31 07 02 80 00 00 04 02 a6 01 25 00
+00 00 00 01 18 11 02 94 00 00 03 e0 05 aa 04 10 00 1f 98 18 00 00 00 07 14 e0 50 00 00 1f 81 d3 3d 40 00 20 20 00 68 84 c0
+00 00 20 80 00 08 b0 3f c0 02 00 04 03 40 fa c0 00 00 f1 83 02 00 00 00 40 20 05 00 08 00 70 fb 01 40 00 20 03 c0 36 01 24 04
+00 00 00 00 00 05 e2 85 08 00 00 00 44 af 50 00 00 09 9b 38 00 00 00 00 40 85 00 00 00 00 01 5f 34 40 80 00 80 00 c8 84 e0
+00 00 00 00 00 00 50 2d 50 00 00 00 20 00 f5 00 00 00 58 a9 02 00 00 00 25 d0 a0 10 00 00 f0 e7 81 40 80 00 e0 00 24 01 24 00
+00 00 00 00 00 0b 7a 81 00 00 00 60 34 ca 14 20 10 00 1e 38 00 00 02 00 16 e0 50 00 00 00 00 77 94 00 00 00 80 79 e8 84 e0
+00 00 00 80 00 00 54 3e b0 02 00 00 02 e0 7a 40 02 80 00 05 80 00 00 1c 00 20 05 00 00 00 90 00 01 40 00 00 14 00 36 01 24 00
+00 00 30 00 00 10 00 00 00 c0 00 00 04 aa f0 01 00 08 0e 78 00 06 00 07 81 85 00 00 01 a8 01 03 14 00 04 00 00 05 48 84 50
+00 00 02 00 00 08 00 00 00 08 00 00 00 00 af 00 30 00 71 0d 82 00 e0 00 41 c0 a0 00 02 00 f0 f7 42 80 00 40 00 03 c6 02 14 00
+00 00 80 00 01 eb b7 dc 02 00 00 00 2c aa 04 00 00 20 00 00 00 00 c0 00 0e bf f0 00 00 80 00 ba a9 40 00 00 20 03 5c f5 00
+08 00 20 00 00 00 1b 7f c4 00 00 00 02 40 fa c1 00 44 00 00 00 00 00 00 21 7b f7 10 00 00 00 01 03 d4 00 00 02 40 2d 05 00 00
+00 00 18 00 80 05 6b d4 00 a0 00 00 1d 8f 54 00 00 00 00 00 00 60 00 00 34 a3 c4 21 80 08 1e ba 8d 52 ca 00 00 00 00 00 00
+08 00 00 00 01 00 08 3d 40 08 4c 0c 28 c0 a0 c1 00 00 00 00 00 00 00 00 3e e0 3e 40 00 00 f1 07 80 c1 81 a0 02 c0 00 00 00 00
+00 00 00 00 01 8b a2 80 00 04 02 00 00 00 00 00 03 a0 00 00 00 40 01 e6 4c ea f0 11 00 01 9e 3f d4 1a 40 00 20 69 da f5 00
+00 00 00 00 00 00 bc 00 00 00 20 04 00 00 00 00 00 05 00 00 00 04 00 00 20 10 af 00 30 00 f0 05 62 e1 41 00 02 44 05 0a 00 00
+00 01 00 05 18 00 28 cd 08 00 00 60 00 00 00 00 00 00 00 00 00 00 00 07 01 ae f0 00 00 50 00 52 81 40 40 00 1c 60 cc f5 00
+00 00 00 80 20 00 04 0c d0 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 40 df df 00 00 02 00 00 80 14 00 14 02 c2 55 0a 00 00
+00 00 00 00 18 03 bd 8d 00 00 00 60 00 00 00 00 03 00 00 00 00 00 09 60 00 16 60 00 00 00 00 f6 30 40 00 04 3e 05 cc f5 10
+08 00 00 80 00 00 d6 30 d0 02 00 02 00 00 00 00 00 00 00 00 00 02 01 00 01 4b 99 00 08 00 00 03 fa 04 00 20 01 e3 06 0a 00 00
+00 00 00 00 19 95 69 55 00 00 00 00 01 aa 04 08 00 00 00 00 00 00 00 02 3e e0 04 20 00 01 81 7b bd 40 00 00 04 7b 6f 50 48
+80 00 00 00 07 08 f8 3c 10 00 00 00 00 c0 50 c0 00 00 00 00 00 00 00 00 02 e0 01 40 00 00 10 8f 83 fc 00 00 02 42 4d ad 14 04
+00 00 00 00 00 1b a0 15 00 00 00 60 00 00 00 00 00 20 00 00 00 00 01 60 0d d0 24 00 00 05 00 80 60 40 00 00 a4 24 ff 50 41
+08 00 00 00 00 08 bc 3e 90 02 00 00 00 00 00 00 00 01 00 00 00 00 00 00 21 5b 00 40 00 02 00 a1 3d 08 00 00 13 c7 f5 8e 24 00
+00 00 30 00 00 08 01 99 00 c8 08 00 00 00 00 00 00 00 00 00 00 c0 00 42 15 81 04 03 00 1f 08 3e 00 00 0c 00 44 07 fb e2 41
+00 00 01 00 00 00 b2 66 50 08 00 c0 00 00 00 00 00 00 00 00 00 0c 00 02 03 dc 00 40 30 06 10 cf 01 40 00 40 00 02 0d aa 06 00
+00 00 00 00 18 a3 22 bc 00 00 21 40 45 9e f0 00 00 00 00 00 00 00 01 40 0f 8a 04 00 00 40 00 d3 bc 00 00 08 26 68 5b 74 00
+00 00 00 00 00 90 0c 2b c0 00 00 1c 3c 4d ff 00 00 00 00 00 00 00 00 9c 02 e0 f5 40 00 00 00 03 c1 54 00 00 c3 c0 14 b2 40 00
+00 00 00 00 80 80 2a 80 00 62 01 c0 04 cf 70 00 00 00 00 00 00 60 00 e2 84 ca 54 00 00 00 00 07 01 40 06 00 00 02 4e a3 6a
+00 00 00 00 01 10 34 14 00 00 40 00 03 4a ff 00 00 00 00 00 00 00 00 24 03 d0 55 40 00 00 00 0d 00 28 00 00 02 40 34 00 34 10
+00 00 00 00 18 a9 f3 fc 08 40 02 00 5e af 70 00 00 00 00 00 00 c0 02 00 45 af 54 00 00 00 00 bb 8c 00 8c 00 1c 05 68 30 60
+00 00 00 00 00 90 1c 3b c0 44 00 14 34 d8 ff 00 00 00 00 00 00 0c 00 04 3e c0 a0 41 00 00 d0 a5 40 d4 00 c0 00 22 07 eb 14 04
+00 02 00 00 00 01 b7 ec 00 00 00 40 1c ea 44 30 00 00 00 00 00 00 03 42 ad aa 04 00 00 03 80 7b a9 c0 80 00 26 62 fa 51 00
+00 00 00 00 00 00 13 ff c0 10 00 02 01 e0 00 40 00 00 00 00 00 00 00 04 69 e0 fa 40 00 00 08 07 82 88 00 00 01 43 7e da 10 00
+00 00 00 00 d8 c3 27 bc 00 00 00 00 05 8a 00 10 01 00 00 00 00 00 00 00 54 aa 04 00 00 00 00 d3 a8 00 00 00 06 7e ec c0 02
+00 00 20 00 01 00 5f 7f c0 00 00 1c 00 00 a0 00 00 00 00 00 00 00 00 00 36 d0 f5 40 00 20 70 07 c0 00 00 00 00 02 7c 0c f0 00
+00 00 00 00 01 93 ab d4 00 00 00 00 05 cf d0 30 00 00 00 00 00 00 00 66 16 c0 54 00 13 09 80 37 28 00 00 00 06 02 4e a3 63
+00 00 00 00 00 0a b8 3f c0 00 00 1c 33 40 ff 00 00 00 00 00 00 00 00 00 00 30 05 40 00 80 70 9d 43 d4 00 00 00 03 34 00 34 90
+00 00 00 00 00 09 32 94 48 00 00 62 95 8f 50 00 00 00 00 00 00 00 00 67 c7 cf 54 00 00 0d 81 d3 80 00 00 00 06 39 4e a5 00
+00 00 00 00 00 00 18 12 80 10 00 24 40 60 ff 00 00 01 00 00 00 00 00 00 6e e0 a0 41 00 30 10 a3 c0 14 00 00 00 22 2f ab 50 00
+00 00 00 00 00 15 73 fc 00 40 00 00 00 00 00 00 00 00 00 00 00 40 02 00 3c ca 54 00 01 85 98 7b a1 40 84 00 00 64 1a c0 02
+00 00 00 00 00 0a b6 7f 80 0c 00 1c 00 00 00 00 00 00 00 00 00 04 00 2c 03 50 55 40 00 00 00 05 03 54 00 40 00 06 00 0c 00 00
+00 00 00 00 99 89 23 fc 00 00 02 06 97 bf 70 00 00 00 00 00 00 00 00 00 3c 88 4c 00 08 05 80 3a 95 40 00 06 14 00 1c 0f 00
+00 00 00 00 01 8a 54 3e 80 00 00 5c 00 6d ff 08 00 40 00 00 00 00 01 00 03 c0 12 52 00 00 78 01 41 40 00 00 00 03 80 00 f0 00
+00 00 18 00 00 a1 78 3c 00 00 42 00 06 e0 41 00 00 00 00 00 00 60 00 63 ae 88 4c 00 00 31 81 da a9 40 06 06 34 00 00 00 00
+00 00 00 00 07 10 7c 2b c0 00 00 04 2a 6a 00 08 00 00 00 00 00 00 00 00 02 ec 12 40 00 02 38 d3 f6 2c 00 00 03 43 00 00 00 00
+00 00 00 00 10 01 fb fc 08 00 01 40 4e 8f e0 00 00 00 00 00 00 d0 00 02 f4 98 4c 00 00 21 89 16 b9 c0 84 00 14 70 40 a5 00
+00 00 00 00 00 80 1c 3d c0 00 00 14 34 1a fe 00 00 00 00 00 00 0d 00 00 23 ed 12 50 00 05 79 91 43 88 00 40 00 06 b4 0f f0 00
+00 02 00 00 d0 00 7b c1 00 00 02 00 06 e2 40 20 00 00 00 00 00 00 00 03 ee 98 4e 00 00 05 8e 17 68 80 00 00 0e 05 f8 50 4a
+00 00 00 00 01 00 00 3c 10 00 00 1c 31 40 20 01 00 00 00 00 00 00 00 00 3e eb 12 40 00 00 09 cd 77 c4 00 00 00 22 1f 0b 04 00
+00 00 00 00 00 0f 6e c1 00 00 e0 e0 34 cf f0 00 00 00 00 00 00 10 00 60 3e 9b 7c 00 00 20 1d d6 03 00 80 00 00 00 00 00 00
+00 00 20 00 05 00 33 bc 50 00 00 02 36 60 fa 00 00 00 00 00 00 01 00 00 3f 4d de 40 00 05 01 8f 81 70 00 00 00 00 00 00 00 00
+00 00 00 00 18 0f f7 1d 00 02 00 60 4c ee 52 20 00 00 00 00 00 00 00 03 ae 98 44 80 00 01 09 32 b1 40 a0 00 06 03 4b ef 01
+00 00 00 00 03 00 53 30 90 00 0e 02 3f f0 f5 20 40 00 00 00 00 00 00 00 66 e8 12 40 00 00 01 80 83 14 00 00 00 40 06 bf f0 00
+00 00 00 00 00 05 f3 d4 40 00 00 e6 74 e0 00 10 00 00 00 00 00 00 a2 02 00 00 00 00 02 80 00 ba e1 40 00 00 96 02 0a f5 00
+00 00 00 00 05 00 30 3f c0 10 00 02 60 5e 08 00 00 00 00 00 00 00 00 04 40 00 00 00 00 00 00 01 67 54 00 00 10 40 15 0f a0 00
+00 00 10 00 39 b8 2f 80 40 00 00 00 06 ef d0 10 00 00 00 00 00 c0 02 43 b4 ca 04 00 00 00 18 9e b9 c0 0c 00 00 73 d8 a5 42
+00 00 01 00 00 0a 32 b4 00 00 00 00 03 eb ff 00 00 04 00 00 00 0c 00 04 42 70 f5 40 00 00 00 03 2a 2c 00 40 00 00 04 0a d4 80
+40 00 00 08 51 80 32 80 00 00 02 00 0d af 56 00 00 00 00 00 00 00 02 06 24 af 00 00 00 03 18 da f0 c0 60 00 00 61 e8 84 c0
+80 00 20 00 0d 8b 94 14 00 00 00 1c 00 00 f5 40 00 00 00 00 00 00 00 04 2c f0 5a 00 00 00 08 9d ff 8c 01 00 01 40 06 c1 24 20
+00 04 18 00 50 e1 62 00 08 60 02 00 0c a5 05 80 00 00 00 00 00 60 08 00 05 cf 00 01 80 20 00 7e 94 00 06 00 14 00 68 84 c0
+08 03 00 00 0d 98 10 00 00 00 00 3c 00 30 50 70 00 00 00 00 00 00 00 54 02 60 0f 00 00 21 f0 c0 c1 40 20 00 00 03 d6 c1 24 10
+60 00 30 01 79 99 eb f4 08 00 08 06 00 0a 54 00 00 40 00 00 00 4a 01 47 8c e7 80 21 00 18 00 87 28 10 0d 00 80 05 49 84 c0
+83 c0 03 00 20 9f d4 3f c8 00 01 00 03 40 5a 40 00 00 00 00 00 0c 00 00 6c 50 87 00 10 0a f0 cf 41 41 00 50 15 42 06 91 24 00
+00 03 00 02 b8 a7 a9 40 00 00 00 00 04 0a 54 00 02 80 00 00 00 00 41 e0 00 0c 34 20 00 08 0f b7 a9 50 00 00 14 04 68 84 c0
+00 00 00 01 9b 1b fc 00 00 00 00 3c 38 00 a5 40 00 20 00 00 00 00 00 00 30 00 c3 41 00 30 71 a7 c1 55 00 00 00 02 16 91 24 10
+00 00 04 01 01 d5 ab 94 0c 00 02 60 40 00 00 00 10 00 00 00 00 00 01 40 20 85 50 00 01 d0 01 92 3d 50 00 c0 a6 03 e9 b7 c0
+00 00 20 40 00 18 54 30 00 00 00 0c 20 00 00 00 00 02 00 00 00 00 00 00 00 d0 aa 00 00 00 00 89 41 41 00 00 14 43 d4 9d ec 10
+44 00 30 05 00 0f b2 81 40 00 00 06 00 00 00 00 00 10 00 00 00 00 c1 c0 35 9f 70 00 00 09 9d 3f a9 50 00 0a 06 60 69 84 c0
+00 c2 82 03 20 00 94 02 98 00 00 00 00 00 00 00 00 02 00 00 00 00 00 26 00 cb ff 10 00 00 11 85 41 55 00 00 04 00 16 c1 24 04
+00 00 00 00 00 8d a7 94 00 00 01 e0 1f a0 54 10 00 00 00 00 00 00 03 e0 2e ee 02 00 00 00 01 f7 3d 50 00 4c 00 01 69 84 c1
+08 02 c0 30 00 18 76 70 00 00 00 00 00 f0 af 40 00 00 00 00 00 00 0c 3e 28 4a f0 00 00 20 00 ff 82 81 00 02 00 00 06 91 24 00
+40 00 10 00 18 a7 aa 80 00 40 00 00 7c ca 54 04 00 00 00 00 00 44 00 07 be e0 21 25 00 08 1e bf a9 50 2c 00 3e 02 69 b7 c1
+00 00 03 00 00 00 fc 3c 00 04 00 00 22 c0 aa 40 00 00 00 00 00 0c 00 00 43 60 00 00 10 00 f0 05 c1 55 00 ca 00 42 06 dd ec 00
+00 00
+11 01
+01 01
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 40 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 10 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 04 00 00 00 00 00 00 10 00 00 00 00 00 05 40 00 00 00 00 10 00 00 00 00 00 00 40 00 00 00 00 0d 01 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 00 00
+00 00 00 00 00 04 00 00 00 00 00 00 10 00 00 00 00 00 00 00 00 00 00 00 30 00 00 00 00 00 00 40 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 10 00 00 00 00 00 00 00 00 00 00 00 00 00 80 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 04 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 40 00 00 00 30 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 10 00 00 83 42 81 00 c0 00 22 17 05 04 00 08 00 00 00 00 c0 00 02 2f 0a a4 03 00 00 8a 34 28 10 0c 00 3c 29 d0 a0 40
+00 00 01 00 05 81 7e bd 50 0c 00 1e 04 da f5 40 01 00 00 00 00 04 00 16 07 4c a5 40 30 00 71 b1 eb d5 00 c0 03 e7 f7 af 54 00
+00 00 00 00 00 05 41 41 00 00 00 02 35 05 04 00 00 00 00 00 00 00 01 c2 2d 0a 04 00 00 00 08 b8 2a 90 00 00 00 23 d0 a0 40
+00 00 00 00 01 80 b7 bd 50 00 00 06 04 5e f5 40 01 00 00 00 00 00 00 26 05 de f5 40 00 00 18 1f 32 95 00 00 00 00 75 af 54 00
+00 00 00 00 00 03 02 81 00 00 00 00 3e 05 04 00 00 00 00 00 00 00 00 00 0d 0a a6 00 00 00 08 30 28 10 00 00 00 01 e0 a0 40
+00 00 00 00 00 00 76 bd 50 00 00 00 02 da f5 40 00 02 00 00 00 00 00 06 63 cc a5 40 00 00 00 17 6b d5 00 00 00 00 2d af 54 00
+00 02 00 00 00 8d 01 41 00 02 00 02 ae 0a 06 00 00 00 00 00 00 00 00 02 ee 0a 04 00 00 01 08 10 14 10 00 00 00 3b e0 a0 40
+00 00 00 00 07 81 b6 bd 50 00 40 00 01 7a f5 40 00 00 00 00 00 00 00 00 00 fa f5 40 00 00 f8 13 6b d5 00 00 00 00 75 af 54 00
+00 00 00 00 10 0f 71 c9 00 00 00 43 7f 05 04 00 00 00 00 00 00 00 00 40 25 0a a4 00 00 01 00 3c 28 14 00 00 04 21 70 50 40
+00 00 20 00 09 98 82 ac 50 00 00 26 64 ca f5 40 00 00 00 00 00 00 00 3e 01 ec a5 40 00 00 99 87 ab d5 00 00 02 66 7e af 54 00
+00 00 00 00 10 0b 02 a9 00 00 00 40 1d 05 04 00 10 00 00 00 00 00 20 40 2f 0a 04 00 00 00 00 b0 2a 90 00 00 04 33 f0 f5 40
+00 00 00 00 08 18 5b 29 50 00 00 20 60 4e f5 40 02 85 00 00 00 00 00 20 61 ee f5 40 00 30 01 85 b2 95 00 00 03 e6 7d ea 05 00
+00 00 00 00 d0 03 82 81 00 00 00 00 06 0a 04 00 00 00 00 00 00 00 00 00 3e 05 04 00 00 05 00 30 28 10 00 00 00 01 e0 f5 48
+00 00 01 80 08 00 33 bd 50 06 00 00 01 6e f5 40 00 00 00 00 00 06 00 00 28 ce f5 40 18 00 80 03 3b d5 00 60 00 00 24 aa 06 00
+00 00 00 00 00 0d 01 41 00 00 00 04 2e 0a 04 00 00 10 00 00 00 00 00 00 2d 0f 54 00 00 05 00 38 2a 90 00 01 40 3f 40 50 40
+00 00 00 00 00 00 32 bd 52 00 00 04 38 4a f5 40 00 00 00 00 00 00 00 00 61 58 a0 40 00 00 80 07 b2 95 00 00 00 00 5e af 54 00
+00 00 30 00 f0 87 42 81 00 c0 00 02 17 0a 04 00 00 00 00 00 00 40 00 02 05 0a 04 01 00 0f 08 97 9c 90 0c 00 00 20 f0 f5 40
+00 00 01 00 01 81 9e bd 50 0c 00 04 07 5a f5 40 00 00 00 00 00 0c 00 00 05 da f5 40 10 00 00 18 6e c5 00 c0 00 40 56 aa 04 00
+00 00 00 00 00 87 41 41 00 00 00 02 35 05 04 00 23 80 00 00 00 00 01 c2 35 a7 24 00 00 00 08 74 14 10 00 00 00 20 d0 a0 40
+00 00 00 00 01 81 7f bd 50 00 0c 06 07 7e f5 40 00 00 00 00 00 00 00 26 04 1e b1 40 00 00 18 17 fb d5 00 00 00 60 77 ef 54 00
+00 00 00 00 00 07 43 d5 00 00 00 00 14 0a 04 00 00 00 00 00 00 00 00 40 14 05 04 00 00 01 00 70 28 10 00 00 3c 00 c0 a0 40
+00 00 00 00 00 00 fa a8 10 00 00 00 02 5a f5 40 00 00 00 00 00 00 00 00 01 5a f5 40 00 00 80 0b eb d5 00 00 02 00 05 af 54 00
+00 02 00 00 00 0d 01 41 00 00 00 00 06 0a a6 00 00 00 00 00 00 00 00 03 96 0a 04 00 00 00 00 38 2a 90 00 00 02 00 d0 f5 40
+00 00 00 00 00 00 fe bd 50 00 00 00 03 fa a5 40 00 00 00 00 00 00 00 00 05 fa f5 40 00 00 00 0f fa 95 00 00 01 e0 37 aa 06 00
+00 00 00 00 10 0f 79 c9 00 00 02 40 17 0a 04 00 00 00 00 00 00 00 00 40 07 0a 04 00 00 00 00 74 28 10 00 00 04 38 e0 f5 40
+00 00 20 00 0f 18 82 ec 50 00 00 06 62 6a f5 40 00 30 00 00 00 00 00 26 60 ca f5 40 00 00 19 8d ab d5 00 00 02 66 54 ea 04 00
+00 00 00 00 00 07 41 41 00 00 00 00 1d 05 04 00 01 00 00 00 00 00 00 60 15 a7 24 00 00 01 00 d4 14 10 00 00 04 01 50 50 40
+00 00 00 00 00 18 fb bd 50 00 00 00 61 6e f5 40 00 10 00 00 00 00 00 3e 62 0e b1 40 00 00 81 87 bb d5 00 00 02 06 2c ef 54 00
+00 00 00 00 50 05 39 c9 00 00 00 43 96 0a 04 00 00 00 00 00 00 00 00 00 14 05 04 00 00 0b 1b 78 28 10 00 00 00 03 c0 50 40
+00 00 01 80 00 00 83 ec 50 06 00 20 02 4e f5 40 00 00 00 00 00 06 00 00 03 4e f5 40 18 00 80 a9 bb d5 00 60 00 00 2e ef 54 00
+00 00 00 00 10 01 82 a9 00 00 00 42 86 0a a4 00 04 00 00 00 00 00 00 20 14 0a 04 00 00 00 00 d0 14 10 00 00 14 00 d0 f5 40
+40 00 00 00 08 00 77 a9 50 00 00 20 01 da a5 40 00 00 00 00 00 00 00 1e 01 ca f5 40 00 00 00 0f ab d5 00 00 00 00 34 ea 06 00
+00 00 10 00 00 03 42 81 00 c0 00 20 25 87 24 00 00 00 00 00 00 c0 00 00 00 00 00 01 00 00 18 bc 2a 90 04 00 00 62 f0 f5 40
+00 00 03 00 00 00 5e bd 50 0c 00 1c 02 1b b1 40 00 00 00 00 00 04 00 06 00 00 00 00 30 00 01 9f f2 95 00 40 00 07 56 ca 04 00
+00 00 00 00 10 0b 02 a9 00 02 00 02 2c 0a a4 00 00 00 00 00 00 00 00 00 25 d5 34 00 00 00 08 bc 28 10 00 20 00 60 f0 55 48
+00 00 00 00 09 80 bb 29 50 00 40 06 07 58 a5 40 02 80 00 00 00 00 00 00 00 09 a3 40 00 00 00 1b fb d5 00 00 00 07 7e ca 54 00
+00 00 00 00 30 83 02 81 00 00 00 02 06 0a 04 00 00 00 00 00 00 00 00 42 25 0f 54 00 00 03 0f 3c 2a 90 00 00 04 02 e0 a0 41
+00 00 00 00 0d 01 16 bd 50 00 00 00 06 fa f5 40 00 00 00 00 00 00 00 20 05 ea a0 40 00 00 99 89 72 95 00 00 02 00 15 af 54 00
+00 02 00 00 18 87 01 41 00 00 00 00 14 05 04 00 20 00 00 00 00 00 00 02 0d dc a4 00 00 00 00 b0 28 10 40 00 01 7b d0 55 40
+00 00 00 00 0f 01 36 bd 50 00 00 00 02 7a f5 40 00 00 00 00 00 00 00 00 06 09 c5 40 00 00 18 0b 6b d5 00 00 00 07 96 ca 54 00
+00 00 00 00 10 03 c2 81 00 00 00 40 05 0a 04 10 00 00 00 00 00 00 10 20 27 0f 54 00 00 01 00 fc 14 10 10 00 04 00 5d 72 40
+00 00 20 00 09 98 3a bd 50 00 00 26 62 6a f5 40 00 00 00 00 00 00 00 1c 01 4c a0 40 00 00 80 0b ab d5 00 00 02 66 20 ab 14 00
+00 00 00 00 d0 0b 02 a9 00 00 00 40 1d 05 04 00 00 40 00 00 00 00 02 c3 4d d5 34 00 00 01 00 b4 28 12 00 00 04 03 70 50 40
+00 00 00 00 00 18 73 29 50 00 00 20 60 6e f5 40 00 02 00 00 00 00 00 20 62 08 a3 40 00 00 81 89 3b d5 00 02 02 06 2c ef 54 00
+00 00 00 00 00 03 82 81 00 00 01 60 04 0a 04 00 00 00 00 00 00 00 00 00 36 0e 60 00 00 00 00 34 2a 90 00 00 24 00 00 00 00
+00 00 01 80 00 00 53 bd 50 06 00 04 6a 4e f5 40 00 30 00 00 00 06 00 00 00 fc c1 02 18 00 58 01 72 95 00 60 01 60 00 00 00 00
+00 00 00 00 50 03 02 a9 00 00 01 c0 34 05 04 00 01 00 00 00 00 00 00 06 ee bd 00 00 00 0d 8b b0 28 10 00 00 00 03 d0 55 40
+00 00 00 00 00 00 53 29 50 00 00 00 02 6a f5 40 00 00 00 00 00 00 00 00 79 4a d5 00 00 00 38 09 ab d5 00 00 00 00 34 ca 54 00
+00 00 10 00 f0 07 42 81 00 c0 00 62 1f 0a 04 00 00 00 00 00 00 40 00 02 3d 87 24 00 00 00 80 00 00 00 0c 00 02 02 d0 fa 40
+00 00 03 00 05 80 fe bd 50 0c 00 24 04 7a f5 41 00 00 00 00 00 0c 00 06 06 1a b1 40 00 00 51 e0 00 00 00 c0 00 40 2f ca 04 10
+00 00 00 00 00 8b 02 a9 00 00 02 42 2d 05 04 00 20 00 00 00 00 00 01 40 1d 05 04 00 00 00 00 54 39 80 00 00 00 62 d0 fa 40
+00 00 00 00 01 81 df a9 50 00 00 06 05 de f5 40 00 00 00 00 00 00 00 06 02 5e f5 40 00 00 19 eb 2b 04 0c 00 00 02 6c 8a 04 00
+00 00 00 00 78 80 ba c5 00 00 00 40 24 05 04 00 00 00 00 00 00 00 02 40 14 87 24 00 00 00 00 b0 3e 80 00 00 3c 22 70 c9 00
+00 00 00 00 03 81 3e ec 50 00 00 00 02 fa f5 40 00 00 00 00 00 00 00 00 02 1e b1 60 00 00 78 8d ba 04 08 00 02 06 4f ac 50 20
+00 02 08 00 00 01 02 a9 00 20 00 02 f4 05 04 00 02 80 00 00 00 20 00 02 24 05 04 00 80 00 80 d8 32 40 02 00 02 03 db 98 00
+00 00 00 00 00 00 bf a9 50 00 00 00 01 de f5 40 00 00 00 00 00 00 00 00 06 5a f5 40 00 00 50 89 f3 14 08 00 01 e0 17 de 50 00
+00 00 00 00 10 07 42 81 00 00 03 40 3d 05 04 00 00 00 00 00 00 00 00 43 86 0f 54 00 00 00 8a bf 26 00 00 00 34 02 48 ca 40
+00 00 00 00 09 98 da bd 50 00 00 06 60 ea f5 40 00 30 00 00 00 00 00 20 64 6e a0 60 00 00 71 b5 67 94 00 00 00 07 01 cc 54 00
+80 00 00 00 00 0d 41 41 00 00 00 40 0d 0a 04 00 00 40 00 00 00 00 00 00 2c 0f a4 00 00 05 18 13 a8 80 00 00 00 2c f0 a0 40
+00 00 00 00 00 18 fb bd 50 00 00 20 62 4e f5 40 00 10 00 00 00 00 20 00 00 4e a0 40 00 38 80 b5 76 9c 00 00 00 00 34 ef 54 00
+80 00 00 00 10 0f 39 c9 00 00 00 02 bc 05 04 10 00 00 00 00 00 00 00 07 c5 0f 54 00 00 05 1b 38 39 80 00 80 00 03 c8 53 40
+00 00 01 80 08 00 03 ec 50 06 00 00 2a ee f5 40 00 00 00 00 00 06 00 00 75 cc a0 40 00 00 80 af 63 04 08 60 00 00 01 ca 34 00
+10 02 00 00 10 01 02 a9 00 00 00 00 0c 0f 54 00 04 00 00 00 00 10 00 20 2f ed 00 00 40 0d 09 9b e2 80 00 00 00 03 db 98 00
+00 00 04 00 0d 00 17 a9 50 00 00 16 03 5a a0 40 00 00 00 00 00 00 00 1e 01 78 d5 00 04 00 00 05 f7 94 00 00 e0 66 04 fe 50 00
+00 00 11 00 00 00 00 00 00 c0 00 02 2c 0a a4 00 00 00 00 00 00 40 02 42 07 05 04 01 20 07 08 b4 3e 90 04 00 2e 3b d0 a0 40
+00 00 01 20 01 80 00 00 00 04 00 00 07 4c a5 40 00 00 00 00 00 04 00 00 06 7a f5 40 10 00 51 bb 22 81 00 c0 02 c0 77 af 56 00
+00 00 00 00 00 00 00 00 00 20 00 02 0d 0a 04 00 00 00 00 00 00 00 00 02 25 0a 04 00 00 00 08 dc 15 50 00 00 00 20 00 00 00
+00 00 00 00 01 80 00 00 00 00 00 06 04 7e f5 40 00 00 00 00 00 00 00 06 06 fe f5 60 00 00 59 ef b2 95 00 00 00 00 40 00 00 00
+00 00 00 00 08 03 82 81 00 04 00 00 0c 0a a4 00 00 00 00 00 00 00 00 00 0d 0a a4 00 00 00 00 10 39 88 00 00 3d 3b e0 a0 48
+00 00 00 00 17 00 d7 bd 50 00 20 06 62 4c a5 40 00 01 00 00 00 00 00 06 03 d8 a5 40 00 00 01 87 bb 04 08 00 02 00 75 af 54 00
+00 02 08 04 00 00 00 00 00 20 03 c0 0e 0a 04 00 10 10 00 00 00 20 a0 00 26 0a 05 14 80 07 18 50 39 c0 02 00 00 00 60 fa 40
+00 00 00 00 20 00 00 00 00 00 00 20 01 da f5 41 00 80 00 00 00 00 00 00 02 7a f5 40 00 00 98 e5 b2 80 08 00 00 00 3f ea 04 00
+00 00 00 18 08 00 00 00 00 20 00 60 00 00 00 00 00 40 00 00 00 00 00 43 df 05 04 00 01 07 00 fc 39 80 00 00 00 03 f0 50 40
+00 00 20 00 07 00 00 00 00 00 00 3e 00 00 00 00 00 02 00 00 00 00 00 20 62 6a f5 40 00 00 81 83 7b 04 08 00 00 66 0e af 54 00
+00 00 00 00 01 00 00 00 00 00 00 40 05 c7 24 00 00 00 00 00 00 00 00 40 35 97 24 00 00 00 80 f6 22 80 00 00 00 00 70 50 40
+00 00 00 00 00 0a 00 00 00 00 00 34 02 0e b1 40 01 00 00 00 00 00 00 20 60 0f b1 40 00 00 79 a7 bb 94 00 02 00 06 3e ef 54 00
+00 00 00 00 30 03 03 d5 00 00 03 c0 14 05 04 00 00 00 00 00 00 00 03 c3 87 0a a4 00 01 03 00 fc 39 80 00 00 04 01 d0 c9 00
+00 00 01 80 08 00 f6 a8 10 06 00 16 00 ce f5 40 00 00 00 00 00 06 00 34 2d 78 a5 40 18 00 80 05 23 04 08 60 02 00 26 8c 50 20
+00 00 00 00 00 00 00 00 00 00 03 40 0c 0a 04 00 00 00 00 00 00 00 00 00 26 0a 04 04 00 15 8a fe e2 80 00 00 00 39 f9 98 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 ea f5 40 00 00 00 00 00 00 00 06 03 6a f5 40 03 80 f8 17 bf 94 00 00 00 06 24 ee 50 00
+00 00 30 00 00 00 00 00 00 c0 02 42 00 00 00 00 00 00 00 00 00 40 00 00 04 0f 54 03 00 00 00 94 07 50 0c 00 00 21 40 1d 40
+04 00 01 00 00 00 00 00 00 0c 00 04 04 00 00 00 00 00 00 00 00 0c 00 1e 02 5e a0 40 10 00 01 c9 a8 69 08 c0 00 40 65 a1 a4 20
+80 00 00 00 00 00 00 00 00 00 00 00 15 05 04 00 00 00 00 00 00 00 00 02 00 00 00 00 00 29 00 38 03 c0 00 00 04 40 e0 0f 00
+00 00 00 00 00 00 00 00 00 00 00 06 03 fe f5 40 00 10 00 00 00 00 00 00 04 00 00 00 00 00 80 0d e3 c0 00 00 01 63 a4 ef 00 00
+08 00 00 00 00 00 00 00 00 00 00 00 1e 0a 04 00 00 00 00 00 00 00 00 44 14 05 04 00 00 09 88 7c 3e 90 00 00 14 23 c0 f3 40
+04 40 00 00 00 00 00 00 00 00 00 00 03 5a f5 40 00 00 00 00 00 00 00 00 3b 5a f5 40 00 00 98 13 ab f5 08 00 03 60 64 cf b4 20
+00 3e 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 34 a7 24 00 00 00 8e 37 e2 00 00 00 14 20 d0 a1 00
+00 00 40 00 00 00 00 00 00 00 0e 00 00 00 00 00 00 00 00 00 00 00 00 00 00 1a b1 40 00 00 18 1b a6 ec 00 00 e2 00 15 ea 00 20
+00 00 00 00 50 00 00 00 00 00 00 00 1d 0a 04 00 00 00 00 00 00 00 00 40 3d 05 04 00 00 01 8a 74 28 40 00 00 04 00 50 00 00
+00 00 10 00 2f 00 00 00 00 00 00 06 03 4a f5 40 00 00 00 00 00 00 00 26 01 4a f5 40 00 00 b8 a1 f2 80 08 00 03 40 3c ea 00 00
+00 00 00 00 00 00 00 00 00 00 00 20 00 00 00 00 00 00 00 00 00 00 00 e0 17 0a 04 01 00 00 0a d4 00 00 04 00 04 00 6e 0c 40
+00 00 00 00 00 00 00 00 00 00 00 14 60 00 00 00 00 10 00 00 00 00 00 1e 60 ee f5 40 70 10 01 8b 2a 80 00 c0 02 00 1f a5 e4 00
+80 00 00 00 00 00 00 00 00 00 00 00 3c e7 24 00 00 00 00 00 00 00 00 20 00 00 00 00 00 01 00 de 87 50 00 00 00 35 70 1d 40
+00 00 01 80 00 00 00 00 00 06 00 00 02 0f b1 40 00 00 00 00 00 06 00 04 00 00 00 00 18 00 d0 a3 ac 69 00 60 01 40 6e e1 a4 20
+80 02 00 00 00 00 03 c1 80 00 00 00 00 00 00 00 04 00 00 00 00 00 00 40 00 0f 04 00 00 00 00 d3 43 10 00 00 04 00 c9 88 00
+00 00 02 00 00 00 06 bc 10 00 00 00 00 00 00 00 00 00 00 00 00 02 00 20 00 0a f0 40 00 00 00 a3 6d 79 00 00 02 02 ae fb b0 00
+00 00 10 00 08 00 00 00 00 40 00 00 00 00 00 00 00 00 00 00 00 40 00 02 80 00 00 01 00 00 00 d8 03 c0 04 00 14 00 00 ff 21
+00 00 03 00 01 00 00 00 00 04 80 1c 00 00 00 00 00 00 00 00 00 04 00 00 04 00 00 00 30 00 00 03 ab c0 00 50 01 40 00 0f f0 00
+00 00 00 00 00 00 00 00 00 00 00 00 15 0f 54 80 00 00 00 00 00 00 00 00 01 00 f4 00 00 00 00 54 11 1a 01 00 2c 38 d0 f0 08
+00 00 00 00 00 00 00 00 00 00 00 00 02 ca a0 40 00 00 00 00 00 00 00 14 00 1e 0f 50 00 00 00 0b 22 ed 08 10 15 42 4e e0 f0 00
+00 00 00 00 30 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 08 02 be bc c0 00 00 03 98 94 34 80 00 00 0c 02 50 0f 00
+00 00 00 00 08 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 54 2e e9 33 00 00 00 99 90 2b 84 0c 00 00 40 1c cf 00 00
+00 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 40 02 d9 60 04 00 0b 0f 04 38 40 00 00 3c 28 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 06 00 00 00 00 00 00 00 00 00 00 00 00 01 69 96 80 00 00 f0 01 2b 84 08 00 00 07 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 20 00 00 00 00 00 03 40 b9 60 00 00 01 00 04 03 c0 00 00 1e 35 cd 88 40
+00 00 20 00 00 00 00 00 00 00 00 0c 00 00 00 00 00 04 00 00 00 00 00 14 05 c9 96 80 00 00 d8 00 70 3c 00 00 00 40 7f ab b6 00
+00 00 00 00 00 07 01 69 00 00 00 02 80 00 00 00 00 00 00 00 00 00 00 00 02 a9 60 01 10 00 0a d3 5a 40 0c 00 14 74 6c ff 00
+00 00 00 00 00 00 80 29 50 00 00 00 04 00 00 00 00 00 00 00 00 00 00 14 00 e8 96 80 30 00 59 b0 6e 58 00 42 00 02 54 bf 70 00
+00 00 00 00 00 00 00 00 00 00 02 40 00 0f 04 00 00 00 00 00 00 00 0a 40 00 99 60 00 00 05 00 30 25 82 00 00 a4 39 f0 ff 00
+00 00 01 80 00 00 00 00 00 06 00 00 00 1e f0 40 00 00 00 00 00 06 00 40 28 c9 96 80 18 00 00 0b 60 f0 08 60 14 00 06 8f 70 a0
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 10 00 00 00 00 00 00 00 a9 60 00 00 00 00 b8 03 c0 00 00 0c 23 d0 ff 00
+00 00 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 08 40 00 00 e1 96 80 00 00 59 8b f3 c0 00 00 02 06 57 af 50 00
+00 28 30 00 10 09 80 49 00 80 00 00 01 0f 0c 08 00 00 00 00 00 4a 00 02 a6 b1 d4 00 00 81 08 12 a7 c0 04 00 00 00 00 00 00
+04 00 03 00 0f 00 da 21 10 0c 00 00 70 0c f0 40 80 00 00 00 00 0c 40 00 6d 78 25 40 00 00 f0 0f e3 f0 00 c0 00 00 00 00 00 00
+80 00 00 00 10 01 80 49 00 00 00 00 02 0f 50 00 00 00 00 00 00 00 01 40 2e a3 c0 00 00 03 8e 90 1b 00 00 00 00 00 00 00 00
+00 00 00 00 09 80 5a 21 30 00 00 00 00 ea f5 08 00 00 00 00 00 00 00 36 02 fc 96 00 00 00 70 0b fa 4c 08 00 00 00 00 00 00 00
+0c 00 00 00 00 09 00 49 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 42 9c 0f 34 00 00 00 08 10 03 00 00 86 24 00 00 00 00
+04 c0 00 00 00 00 da 21 30 00 01 40 60 00 00 00 00 00 00 00 00 00 00 06 61 6c ff 42 00 10 70 09 79 20 0c 04 00 00 00 00 00 00
+00 02 00 00 00 e1 00 49 00 00 00 02 c0 00 00 00 00 00 00 00 00 00 00 42 bf 03 00 00 00 20 10 b8 39 80 00 40 00 00 00 00 00
+00 00 00 00 00 00 7a 21 30 00 00 00 04 00 00 00 00 10 00 00 00 00 00 20 07 ea 70 02 00 00 01 cb 3b 04 08 08 00 00 00 00 00 00
+00 00 00 00 00 89 80 49 20 00 00 03 83 05 00 10 00 00 00 00 00 10 01 44 15 0c c0 00 00 20 0e d7 e2 80 00 00 00 40 00 00 00
+00 00 10 00 01 99 d2 21 30 00 00 00 71 78 50 00 00 00 00 00 00 00 00 06 23 cc 33 02 00 01 04 1f 77 94 00 00 00 02 80 00 00 00
+00 00 10 00 00 81 80 49 00 00 02 c3 00 00 00 00 00 20 00 00 00 40 00 02 ae aa 50 00 00 0d 00 76 4c 00 0c 01 40 78 00 00 00
+02 00 03 00 00 19 52 21 30 00 00 20 04 00 00 00 00 01 00 00 00 04 00 06 02 fc d2 00 00 00 00 0f bd e0 00 40 08 03 80 00 00 00
+80 00 00 00 01 09 00 49 00 80 00 03 40 00 00 00 00 00 00 00 00 00 00 40 3c 0c b4 00 20 01 0a 00 3d 40 00 00 00 00 00 00 00
+08 00 01 80 00 0e f2 21 30 0a 00 00 04 00 00 00 00 00 00 00 00 06 00 20 02 18 c7 42 00 00 d8 17 e3 d4 00 60 00 00 00 00 00 00
+10 42 00 00 f0 01 00 49 08 00 00 00 3f 05 a0 00 04 00 00 00 00 00 00 03 c3 05 00 00 00 0d 00 70 15 40 00 00 04 03 68 ed c4
+00 07 04 00 00 00 72 21 30 08 00 00 03 5a 05 20 00 00 00 00 00 00 00 00 65 48 50 00 00 00 00 08 7a a8 00 00 02 00 34 8b 74 00
+00 00
+11 02
+01 01
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 20 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 08 00 00 00 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 c0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 08 00 00 00 00 00 00 20 00 00 00 00 08 00 00 00 00 00 00 20 00 00 00 00 00 00 80 00 00 00 00 00 02 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 08 00 00 00 00 00 00 20 00 00 00 00 08 0e 00 00 00 00 00 20 00 00 00 00 00 00 80 00 00 00 00 00 03 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 08 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 10 00 00 00 00
+00 00 00 e8 b1 fc 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 29 fe d8 00 00 02 01 69 17 00 24 00 00 00 29 ee 00 00 00
+00 00 00 02 c3 3a 40 38 00 00 00 00 00 00 90 00 00 00 00 00 08 00 03 ff 7d 50 90 00 04 06 90 40 06 00 00 20 02 82 00 09 00 00
+00 00 00 00 00 01 40 00 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 40 02 01 69 17 00 00 00 00 00 00 00 00 0a 00
+00 00 00 00 00 00 36 00 00 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 00 00 06 90 00 00 00 00 00 00 00 00 00 40 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0e 1f a8 00 00 00 01 69 12 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 41 f8 70 00 00 00 06 90 00 00 00 00 00 00 00 00 00 00 00
+00 02 00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 00 00 00 00 00 00 00 07 00 1c 00 01 69 13 80 68 00 80 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 90 04 00 00 00 00 00 00 00 00 00 00 70 00 00 00 06 90 40 00 00 08 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 07 00 00 01 01 69 13 8e 00 00 00 02 94 fe 10 00 00
+00 00 20 00 00 00 00 20 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 d0 00 00 00 06 90 40 00 00 00 00 01 40 8f 80 00 00
+00 00 00 00 00 00 00 00 00 00 21 5e 90 00 40 00 00 00 00 00 00 00 00 00 09 00 00 02 01 21 13 9c 00 00 01 03 ac dc 81 c0 00
+00 00 00 00 00 00 00 00 00 00 02 2f cb 00 08 00 00 00 00 00 00 00 00 00 00 18 00 00 00 04 80 38 03 40 00 00 3e c3 f1 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 08 00 00 00 00 00 00 00 00 00 2b ce a0 0e 08 00 00 69 13 0e 7c 00 00 00 14 ec 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 70 00 00 00 00 00 00 00 00 03 bd f8 00 00 00 20 06 90 41 e6 80 00 00 01 41 09 0b 00 00
+00 00 00 00 00 00 07 00 03 00 00 00 00 1c 00 00 00 00 00 00 00 10 12 8c 80 00 00 01 00 a5 da 00 00 00 00 00 00 00 80 00 00
+00 00 00 00 00 00 00 30 00 30 00 00 00 00 00 00 00 00 00 00 00 02 01 28 30 70 00 00 00 02 5b 34 00 00 00 00 00 00 03 0f 00 00
+00 00 00 aa db aa 00 00 20 00 02 2f f7 98 00 00 00 00 00 00 00 00 00 96 bd 0b 00 01 08 00 3b 14 28 00 04 2a bc cb 00 c0 80
+00 00 00 0a 85 bb bc 3c 01 00 20 00 4e 08 00 00 00 00 00 00 00 00 00 95 fa 59 e1 00 00 84 01 78 26 c3 00 00 82 80 d0 0b 00 00
+00 00 00 0b d0 04 00 40 04 00 3b d7 f0 00 00 00 00 00 00 00 00 00 29 40 85 0a 00 00 00 00 00 00 00 01 00 2a bc c8 00 08 09
+00 00 00 00 7e f2 c0 3c 05 40 03 fe 4e 70 90 40 00 00 00 00 00 00 00 00 08 09 00 c8 00 00 00 00 00 01 22 01 82 82 f0 00 49 14
+00 00 04 2a d3 b8 03 c8 00 00 2b c4 10 00 01 40 00 00 00 00 00 00 12 96 d3 80 00 00 00 af 32 06 22 e0 00 0a bd cf 18 80 00
+00 00 00 0e 4a 0b 40 20 00 00 21 7c 2e 00 00 00 00 00 00 00 00 00 41 68 da 58 00 00 20 0a f0 80 00 00 00 00 81 42 c0 0b 00 00
+00 02 00 00 00 00 06 00 00 00 00 00 00 0a 00 00 00 00 00 10 00 00 19 04 c8 0d a0 80 00 af 72 00 00 00 80 0a 94 ea 98 80 00
+00 00 00 00 00 00 34 00 10 00 00 00 00 00 90 48 00 00 00 02 80 00 01 60 7f f1 e4 90 00 0a f0 80 00 00 08 00 aa 81 8f 00 04 00
+00 00 10 05 f7 6a 00 00 00 00 2b de 10 00 08 00 00 00 00 00 20 55 1f c7 c9 80 00 80 00 00 93 34 28 00 02 0a bd ea 80 80 00
+00 00 20 00 5f 0c 04 00 00 00 01 7c 0e b0 00 00 00 00 00 00 00 00 01 fc 30 78 b0 10 00 44 07 ea c0 00 00 02 82 80 bb 1f 00 00
+00 00 05 20 75 f6 60 00 00 10 3b cd d0 0a 00 20 00 00 00 20 00 20 2b de f1 00 00 00 00 05 32 16 2a 00 00 0a 94 ff 00 10 14
+00 00 00 0a 1f 07 44 00 00 00 02 14 3f f0 00 00 00 00 00 01 00 00 00 14 18 00 00 c0 00 00 00 b4 00 10 00 00 aa 80 bb 0a 40 80
+00 00 00 0f 07 00 06 40 00 10 0c 16 90 00 00 80 00 00 00 00 00 00 1e 04 85 8a a0 00 40 d0 32 14 68 00 00 4a bd eb 80 00 00
+00 00 00 00 f0 00 1c 34 00 00 42 d4 0d 00 00 14 00 00 00 00 50 00 03 e0 eb 19 01 80 00 08 00 2c 00 00 50 20 82 82 e1 08 00 00
+00 00 08 00 a5 20 00 00 02 00 00 67 80 08 0c 00 00 00 00 17 00 10 30 1c 00 1e 00 02 c0 02 7f d4 28 00 00 08 15 6d 81 90 10
+80 00 00 88 0a 04 00 00 02 20 20 03 e9 10 80 00 00 00 00 00 80 00 03 00 00 00 00 00 00 45 20 74 00 10 00 a0 97 c2 bb 0d 1c 2c
+00 00 00 8e f5 f8 02 80 00 00 01 54 e0 00 00 00 00 00 00 00 00 00 10 15 dd 80 00 23 06 64 5a c0 04 40 04 00 00 fa 00 b0 00
+00 00 00 08 ff 57 40 40 00 00 00 14 10 00 00 00 00 00 00 01 0c 00 01 61 db 58 c0 00 20 a5 81 30 02 c0 10 00 14 01 ad 18 14 00
+00 00 00 a0 0b b4 00 00 05 11 00 5f f0 00 08 00 00 00 00 00 00 52 a1 54 c8 01 80 16 02 80 ba 40 3c 02 51 00 f0 00 00 10 01
+40 00 00 02 80 d6 b4 00 00 40 00 00 1f 30 00 00 00 00 00 00 02 02 1b bc 39 30 e4 01 01 6d a7 a0 07 00 44 00 0f 00 03 0d 00 14
+00 00 00 2a 50 00 62 80 00 02 15 4f b0 01 80 00 00 00 00 00 00 00 14 15 c3 9c 00 08 00 ff 5a a0 04 00 34 2a 35 c0 19 a0 00
+00 00 00 02 5a 02 c0 43 70 00 01 68 3b 00 e4 00 00 00 00 00 00 00 01 61 d8 01 b0 00 80 0a f0 e3 42 56 22 00 93 84 b0 10 40 00
+00 02 00 21 fd 2c 03 90 00 40 2b cf 8d 00 00 00 00 00 00 00 00 11 88 15 e1 0e 00 00 00 af 70 00 04 70 80 0a bd 59 18 10 c0
+00 00 00 02 0f 5b f4 6e c0 00 02 bc 30 10 04 06 00 00 00 00 00 08 4a d4 09 f0 00 00 08 05 f0 38 c3 80 08 00 81 43 af 09 00 00
+00 00 10 0a f7 a2 00 28 50 00 3b ef f8 00 40 00 00 00 00 00 00 00 14 15 c0 01 00 00 00 00 00 20 00 00 00 0a 95 7e 81 e0 14
+00 00 20 00 af 08 04 3d 02 02 03 fe 7d 70 08 00 00 00 00 00 10 00 01 61 df 70 f0 00 00 00 00 00 43 c0 00 00 aa 80 d3 10 00 80
+00 00 04 40 01 b6 00 40 08 00 06 f6 cf 80 00 80 00 00 00 28 00 10 88 07 c9 81 00 00 00 00 00 20 00 00 04 1a bc 49 00 a0 00
+00 00 00 00 04 0e 84 20 00 00 40 0e fa 70 00 10 00 00 00 01 00 0e 5a d4 29 f0 d0 00 00 00 00 01 43 40 00 00 82 82 e0 00 00 80
+00 00 00 2f 55 a4 00 20 50 00 29 55 e8 0c a0 00 00 00 00 00 00 00 0c 35 a7 18 00 00 00 00 00 00 6c 20 08 1a 94 09 00 e0 00
+00 00 00 03 0a 03 40 01 02 00 02 bc 1d 71 04 00 00 00 00 00 00 00 00 d3 de 08 00 00 00 00 00 00 02 10 00 00 99 84 b0 0e 00 00
+00 00 01 28 09 ae 00 00 02 11 17 d6 ff 9e 00 00 00 00 00 10 00 10 81 17 d1 88 00 08 00 00 00 00 04 00 20 08 29 7f 01 d0 00
+80 00 00 82 00 5b c4 00 00 30 00 b8 2d f0 01 00 00 00 00 02 00 04 19 78 1f 91 00 00 80 00 00 00 02 c0 02 00 91 ce a0 18 00 08
+00 00 00 88 07 ec 00 00 00 00 2b ce a5 1e 00 00 00 00 00 02 00 00 3b e6 e0 00 1c 04 00 87 37 46 20 70 04 2c 84 1c 00 10 00
+00 00 00 00 00 5e 00 00 00 00 00 14 28 00 d0 00 00 00 00 00 00 00 03 3e 4f 00 00 00 00 0e ff a9 46 80 00 02 92 05 a0 08 08 00
+00 00 00 25 51 aa 00 40 05 10 28 5e 80 18 00 00 00 00 00 07 00 40 00 dc 03 1d 20 14 40 e7 00 46 64 00 50 05 a4 58 00 b0 01
+40 00 00 13 55 00 0c 20 40 50 02 88 2c 01 00 00 00 00 00 00 00 02 00 0d e0 99 a4 01 00 0d b0 24 26 00 05 00 1a 41 05 0c 00 14
+00 00 10 00 55 80 66 00 00 00 01 4d 80 01 00 00 00 00 00 00 00 00 02 ac e5 8e 00 00 40 18 5e 1e 28 00 20 05 a4 58 00 aa 00
+00 00 00 00 0a 0a 80 28 70 00 00 14 20 00 b0 02 00 00 00 00 00 00 01 0a cf 79 00 00 00 02 50 28 00 00 02 00 1a 40 00 0e 00 00
+00 02 14 22 51 ac 60 40 00 00 22 cd e0 01 00 40 00 00 00 00 00 10 23 d7 9d 8a 01 80 00 af 5b 80 60 00 00 05 a4 5c 01 c0 90
+00 00 00 0a a7 0e 94 20 00 00 02 bc 5d f0 e0 08 00 00 00 00 00 00 02 28 2c 11 00 14 00 08 f1 74 06 40 00 20 1a 40 00 00 00 00
+00 00 00 25 a0 04 00 00 00 10 20 4f bf 9d 00 80 00 00 00 00 00 10 22 46 b7 89 00 00 c0 10 18 24 30 00 00 05 a4 5e 80 00 08
+00 00 20 93 a5 02 00 00 00 00 02 bc 1e b0 c0 04 00 00 00 00 00 00 03 1c 38 01 f0 00 00 42 00 a8 40 00 00 40 1a 40 03 00 01 00
+00 00 00 00 00 00 00 00 10 10 22 5d f3 1d 00 40 00 00 00 00 00 10 00 d4 00 1c 00 82 82 af 53 4c 60 00 00 05 a4 4c 50 10 00
+00 00 00 00 00 00 00 00 00 00 03 2c 0a 08 e0 08 00 00 00 00 00 00 00 0c 00 f1 90 0c 09 e4 73 f4 20 00 00 04 1a 41 00 0d 40 00
+00 00 00 20 57 a8 07 00 00 a0 3f e4 e8 18 00 00 00 00 00 00 00 10 a0 0c e3 81 40 00 00 ef 16 0e 70 00 00 05 a4 4a 01 c0 00
+00 00 00 03 5f 0a c0 40 00 00 03 7c fd 10 00 04 00 00 00 00 00 00 0b 80 3b 10 92 00 00 0f ff e8 00 00 00 04 1a 40 00 10 00 00
+00 00 08 aa d9 ee 07 40 03 20 28 1e 17 9e 40 00 00 00 00 00 00 00 90 b6 a0 00 00 2c c0 bc 1a 00 39 00 30 05 a4 58 00 00 00
+80 00 00 06 85 5f 84 6e 10 30 01 40 28 09 02 00 00 00 00 01 00 08 08 17 5d 00 01 42 a1 4b c0 00 00 08 03 04 1a 40 00 0c 00 0c
+00 00 00 20 0b b8 60 00 01 00 01 4f b3 00 14 00 00 00 00 00 00 82 00 84 a1 00 00 00 00 a7 bb 00 00 00 00 01 a4 4e 00 10 00
+00 00 00 02 02 52 00 28 00 00 02 bc 1e 00 00 00 00 00 00 00 08 02 20 01 7c d8 80 00 00 02 61 6c 40 00 00 0c 1a 40 00 0a 00 00
+00 00 00 00 57 68 00 00 04 10 29 ce b8 00 40 80 00 00 00 00 20 50 a3 5c e0 00 00 90 40 89 5e 5e 00 80 88 01 1f 59 39 9a 00
+00 00 00 00 05 00 00 34 00 50 01 44 1e f0 0b 80 00 00 00 00 05 00 0a 34 10 d0 00 15 00 0c b0 b8 02 85 00 00 20 7e 8d 9d 40 00
+00 00 04 20 a3 ba 03 80 00 10 22 5f d1 0f 00 00 00 00 00 00 00 00 01 56 a8 0a 00 00 48 81 00 5e 6d 00 00 00 07 59 d8 00 00
+00 00 00 02 42 0a 14 00 80 00 03 1c 3c 09 c0 00 00 00 00 00 00 00 01 7c 3e 30 b0 04 00 04 20 3c 27 a8 00 00 16 c6 95 00 80 00
+00 02 00 20 47 a0 03 80 00 00 00 00 01 01 01 00 00 00 00 00 00 00 23 7f 88 00 a0 00 00 af 36 d6 28 00 08 01 1e 69 01 90 00
+00 00 00 02 1c 7b c0 40 00 00 00 00 00 d8 d0 08 00 00 00 00 00 00 01 35 fa 10 00 00 00 00 a0 3f c0 00 00 00 20 64 80 1d 00 00
+00 00 00 28 0f 20 00 40 00 00 00 00 00 00 00 00 00 00 00 00 00 10 22 5e fd 80 00 00 00 af 1b 4e 70 00 42 03 fc cf 78 a0 00
+00 00 20 02 e0 16 00 20 00 40 00 00 00 00 00 00 00 00 00 00 40 00 03 1c 3c f8 f0 01 00 00 50 a8 23 e0 04 00 17 c1 ed 10 00 10
+00 00 00 60 43 a4 66 00 20 00 01 46 ab 98 00 80 00 00 00 00 00 10 20 40 17 01 00 00 40 47 3f 3e 60 02 01 00 80 dc 00 f0 14
+00 00 00 02 1c 73 80 6c 60 00 02 bc 2f f8 90 14 00 00 00 00 00 00 01 08 0d 00 90 00 00 04 70 80 43 00 40 80 00 02 d0 0f 00 00
+00 00 00 00 55 06 02 80 00 00 11 e5 bf 00 00 00 00 00 00 00 00 00 83 56 cf 18 0c 00 00 af 3a 80 01 02 00 02 bd fd 30 00 00
+00 00 00 00 0a 0a 84 78 00 00 02 06 eb 78 00 00 00 00 00 00 80 00 09 3d 7f 10 00 00 00 00 50 a4 00 28 50 00 01 40 ff 0d 00 00
+00 00 04 20 a3 21 47 40 03 02 3f de e8 1d 00 00 00 00 00 00 00 00 29 4c 99 8f 40 0c 00 00 5a e4 04 30 01 02 2d db b0 b0 04
+00 00 00 02 81 03 82 20 00 32 01 7c 1a 10 f0 00 00 00 00 00 00 02 02 a8 3b b8 93 82 c0 00 a0 2d e3 80 00 00 02 82 ad 1e 58 80
+00 00 00 00 00 00 00 00 00 04 01 5f 91 00 00 00 00 00 00 10 20 00 09 06 e0 00 00 00 00 c7 bb 94 00 40 08 0a 0d cb 00 10 10
+00 00 00 00 00 00 00 00 00 00 01 7c 3c 00 e0 00 00 00 00 00 85 00 00 50 de b0 94 00 00 08 99 63 43 80 00 00 b8 c6 90 08 00 00
+00 00 00 00 00 00 00 00 04 00 11 56 a7 8c 40 00 00 00 00 00 50 00 ab 4e f7 9f 20 10 40 89 32 5e 78 81 00 0b 96 6e 81 e0 01
+00 00 00 00 00 00 00 00 00 50 01 3e e9 00 02 08 00 00 00 00 42 00 0a 15 e8 09 f0 81 00 4c b0 b5 c4 10 00 00 a1 46 f3 10 14 14
+00 00 00 00 00 00 07 40 00 00 31 e6 ab 88 a0 00 00 00 00 00 00 00 81 5c b7 01 00 00 00 8f 56 54 69 70 04 18 1f 6f 01 c0 08
+00 00 00 00 00 00 00 70 00 00 02 26 ca f1 b4 00 00 00 00 00 00 00 09 7c 2d 08 c0 14 00 04 57 fd e0 20 00 00 87 e5 a0 18 01 40
+00 02 00 00 00 00 07 00 00 10 22 5c b5 1e 00 00 00 00 00 00 00 00 28 14 e1 9c c0 20 04 05 53 8e 01 00 00 00 00 09 98 d0 00
+00 00 00 00 00 00 00 41 00 00 03 2c 0e 08 00 02 00 00 00 00 00 00 42 80 20 00 0a 00 00 05 f0 e4 20 2d 00 20 29 40 db 0f 08 00
+00 00 00 00 00 00 00 00 00 10 20 40 07 9c 00 00 00 00 00 04 00 01 b8 e7 98 00 00 00 00 05 32 a0 39 02 02 00 28 dc 31 81 48
+00 00 20 00 00 00 00 00 00 00 01 08 0b 09 00 c0 00 00 00 00 20 00 09 0c ed f0 e0 00 00 05 f0 6a 43 a8 40 00 02 81 00 08 81 00
+00 00 00 00 00 02 00 00 00 41 2b d6 88 00 20 00 00 00 00 14 10 04 ab 6e 98 19 a1 00 40 47 33 96 e0 00 00 0a 94 de 70 18 02
+00 00 00 00 00 00 0c 00 00 00 42 bc 00 30 d1 40 00 00 00 00 02 00 0e 16 78 30 80 08 00 04 70 40 20 00 00 00 aa 80 a0 8c 00 00
+00 00 00 00 00 00 00 00 00 00 2b d4 d0 1e 00 00 00 00 00 08 10 00 3c 67 c8 19 00 00 00 a5 56 6c 70 00 00 0a bd 6d 01 80 00
+00 00 00 00 00 00 00 34 00 00 00 14 2e 01 00 00 00 00 00 00 02 00 02 88 cd 10 b0 00 00 05 50 ac 44 00 20 44 82 83 e1 00 00 00
+00 00 01 68 53 f8 60 04 22 00 01 5e af 9f 20 00 00 00 00 00 00 00 ab 77 b0 00 00 08 48 47 13 9c 03 85 04 0a 94 db 01 80 00
+c0 00 00 02 ad 5f 80 00 04 b0 00 14 30 71 e0 00 00 00 00 00 00 04 1a 14 59 00 01 40 80 04 70 c0 20 3c 00 00 aa 81 80 00 00 08
+00 00 00 00 00 03 40 00 50 00 17 ff b1 08 00 00 00 00 00 10 00 04 14 46 9f 98 00 00 00 a1 7a 5c 01 f0 00 00 00 00 01 e0 00
+00 00 00 00 00 00 06 2c 02 00 02 07 cc 11 00 00 00 00 00 00 b8 00 02 9e 68 10 00 00 20 0e 2f f2 40 06 00 00 00 00 01 10 00 00
+00 00 00 0e e3 20 00 00 00 00 37 cf 90 00 21 00 00 00 00 00 00 00 a0 c6 e3 81 0c 14 0e fa 3b 80 00 00 60 00 a3 e8 00 10 01
+80 00 00 08 bb 7a 40 00 10 04 03 94 4a 00 b4 08 00 00 00 00 00 00 4f 8c 5c 08 e0 01 08 2f a0 40 00 00 00 00 00 37 c0 0d 00 00
+00 00 00 0e ef bc 62 a0 00 00 01 4c f8 00 00 00 00 00 00 00 40 00 b0 4c c1 00 40 00 00 af 32 c0 01 30 20 00 00 00 80 01 00
+c0 00 00 00 bb d7 74 41 00 00 02 bc 2e b0 00 00 00 00 00 00 00 00 1b 2e 6f 00 00 00 00 00 a0 74 40 20 02 00 00 00 07 00 00 08
+00 02 00 0e ed 69 42 80 00 00 3e ee d8 00 00 00 00 00 00 03 00 00 00 00 07 0f 20 00 00 8b b0 00 00 00 04 00 28 5e 80 00 00
+00 00 00 00 77 b3 42 40 00 00 02 9f 4a d0 80 00 00 00 00 02 00 00 00 00 00 08 84 00 00 04 77 ac 00 00 00 00 02 82 0f 00 00 00
+00 00 00 0c c3 ad 43 80 00 00 28 56 9f 01 00 00 00 00 00 00 00 00 81 f6 d7 1f 00 00 80 05 77 20 62 80 00 02 80 ca 81 90 00
+00 00 20 00 ff f7 be 00 70 02 01 5e 5c 70 e0 00 00 00 00 00 00 00 18 7c 4c 00 f0 00 00 00 50 c0 c0 10 50 00 28 01 07 1c 04 00
+00 00 04 0e f1 29 c2 e8 00 00 2b dd d7 81 40 00 00 00 00 28 00 02 a9 cf e0 01 1c 80 10 00 03 44 04 00 01 19 00 dc 80 00 00
+00 00 00 08 ff 0f 2c 74 00 00 00 28 0d 00 e2 00 00 00 00 00 00 00 08 96 cc 00 d0 00 00 0a 50 76 63 80 00 00 92 81 81 00 00 00
+00 00 00 00 00 00 e7 c0 00 10 11 dc a9 9e 00 00 00 00 00 00 00 00 3b fc 81 1d 0c 00 00 00 00 34 01 00 00 00 15 c0 78 10 00
+00 00 00 00 00 00 1e 70 00 00 01 1c 30 11 90 00 00 00 00 00 00 00 02 fd de 08 e0 00 00 00 00 00 c0 28 00 00 02 80 90 0e 14 00
+00 00 00 0a a3 b8 07 80 20 10 23 cc f9 0e 1c 80 00 00 00 02 00 30 3b d6 b0 18 60 08 08 af 78 5c 20 00 31 28 90 cf 58 e0 00
+80 00 00 08 aa 00 00 6c 05 00 01 14 3f f9 e0 00 00 00 00 00 00 06 03 fc 3e 00 f4 02 c8 05 f0 b6 42 40 03 00 8a 01 ff 10 00 08
+00 00 00 32 11 38 00 00 00 c0 80 37 db 81 80 00 00 00 00 10 00 00 2b de b8 0a 00 00 00 05 7b c0 01 00 00 02 80 60 50 00 00
+00 00 00 42 48 03 7c 02 80 08 38 12 7d 10 f4 00 00 00 00 00 80 04 00 14 0b 11 b0 00 01 0a f0 74 00 00 00 00 14 02 c1 8e 08 00
+00 00 00 32 11 38 00 00 06 00 00 00 08 19 1c 50 00 00 00 00 00 00 a9 40 15 81 00 18 00 42 80 00 7d 00 51 09 08 fb f9 da 05
+80 00 00 02 48 03 c0 00 00 00 00 00 00 b0 d0 19 00 00 00 00 00 00 09 68 0e 08 c0 04 00 08 1b 3c 07 a0 05 02 81 42 bb 9d 51 80
+00 00 00 32 11 2a 60 28 12 06 b0 d7 c0 00 20 00 00 00 00 10 00 00 83 cc 00 0a 00 00 00 a0 76 80 02 80 00 0b 81 69 30 b0 00
+80 00 00 02 48 07 44 00 02 20 0e 2e 6d 00 00 00 00 00 00 02 80 00 08 3c 00 d1 b1 80 00 0a 00 c2 40 00 00 02 a0 3f a0 1b 08 08
+00 02 00 32 11 2a 06 00 00 80 a2 c6 d1 9d 00 00 00 00 00 00 00 81 83 c4 07 00 14 00 00 0a 18 26 7c 02 00 18 22 cb 01 d0 00
+00 00 00 02 48 07 c4 00 00 00 0b 0e dc 10 80 00 00 00 00 00 00 04 48 3c 20 00 00 00 00 00 50 3f c3 40 40 00 a1 46 b5 1b 14 00
+00 00 00 32 11 78 00 00 00 00 83 57 d1 80 00 00 00 00 00 00 00 00 29 4e e0 18 00 00 00 a0 72 80 00 02 00 08 0b fa 80 00 00
+00 00 20 02 48 03 7c 00 00 00 0d 3e c8 10 00 00 00 00 00 00 00 08 02 a8 08 00 04 00 10 0f a0 fc 00 00 40 02 86 97 85 0d 00 00
+00 00 00 32 11 68 00 00 00 00 b0 fe db 9c 01 00 00 00 00 00 00 01 29 57 e0 1e 80 00 00 00 00 14 04 00 00 48 22 7f 80 00 04
+00 00 00 02 48 03 c0 00 02 02 09 1c 7c d9 08 08 00 00 00 00 00 00 02 a8 38 01 b4 00 00 00 00 02 42 c0 00 00 a1 47 b5 0f e0 00
+00 00 01 32 11 68 06 40 00 00 81 df d0 00 21 40 00 00 00 00 00 02 29 4f 80 01 00 00 00 af 5f ae 70 00 00 08 0b 5a 59 a0 14
+00 00 00 02 48 07 7c 20 00 04 2c 7e ef 00 04 08 00 00 00 00 00 00 02 a8 1a 00 f0 00 00 00 50 7d e4 10 20 01 86 95 e0 0f 00 00
+00 00 00 32 11 78 67 c0 03 00 8b f6 cf 80 40 08 00 00 00 00 00 00 29 57 c5 01 40 09 02 af 5f 40 01 40 22 03 bb 58 f8 00 00
+c0 00 00 02 48 07 c0 60 20 3c 08 2c f9 10 0a 00 c0 00 00 00 00 00 12 a8 2b 08 f8 00 81 20 a0 a1 4b 88 03 00 1d d6 e7 80 00 08
+00 00
+11 03
+01 01
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 40 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 00 00 00 02 00 00 00 00 00 00 00
+00 00 00 00 01 80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 40 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 08 00 00 00 00 00 00 20 00 00 00 00 08 00 00 00 00 00 00 00 00 00 00 00 00 00 08 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 08 00 00 00 00 00 00 20 00 00 00 00 0c 00 00 00 00 00 40 30 00 00 00 00 00 00 40 00 00 00 00 00 03 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 20 00 38 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 00 00 40 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 00 00 00 00 00 00 00 60 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 00 00 00 00 00 00 08 00 00 00 00 80 00 20 00 00 00 00 00 00 80
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 08 00 00 00 00 00 00 00 00 00 00 00 00 00 80 00 02 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 04 00 00 02 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 03 04 93 8e 91 00 00 0c 00 00 00 00 00 00 b2 ac c1 10 00 08 10 67 02 d4 02 80 00 09 54 3d 19 00 00
+80 00 00 00 00 00 00 70 00 30 0a 35 61 80 00 00 80 00 00 00 00 00 0b 17 e1 80 e0 00 84 08 33 a3 66 90 00 00 a9 45 f9 8c 00 0c
+00 00 00 00 00 00 00 00 00 04 82 82 81 00 00 00 00 00 00 00 00 02 81 43 e1 00 00 00 00 46 17 fc 00 00 00 09 38 6a 10 00 10
+00 00 00 00 00 00 0c 00 00 00 0a bd ec d9 80 00 00 00 00 00 00 00 0a bd fd 80 00 00 00 0c 7b 29 62 00 00 00 a3 5e 18 00 14 80
+00 00 00 09 30 a4 c0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 95 41 c0 00 00 00 00 00 00 00 28 00 00 08 28 0a 00 f0 00
+00 00 00 c0 a3 3a a0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0a 95 eb 19 80 00 00 00 00 00 00 40 00 00 ab d6 91 80 00 00
+00 02 00 01 9b a0 00 00 00 00 00 00 00 10 00 00 00 00 00 00 00 00 81 41 e0 00 00 00 00 00 00 3c 6c 00 02 09 38 4b 00 00 00
+00 00 00 00 a7 d2 80 00 00 00 00 00 00 01 c0 00 00 00 00 00 00 00 0a bd 69 00 00 00 00 00 00 02 c3 80 00 00 a3 56 00 00 00 00
+00 00 00 25 f0 a4 00 00 00 40 ab c3 c0 10 00 00 00 00 00 00 00 00 82 82 f0 08 00 00 00 df 06 80 00 00 00 48 28 28 00 88 00
+00 00 20 02 05 76 00 00 00 02 08 15 6a 18 80 00 00 00 00 00 00 00 0a bd 5e 00 10 00 04 0c f7 69 e0 00 00 00 ab d4 80 19 00 00
+00 00 00 00 00 01 42 80 00 00 82 82 e0 00 e0 00 00 00 00 00 00 02 81 42 e0 08 00 00 00 47 9f 24 24 00 00 08 14 38 01 08 00
+00 00 00 00 00 00 20 6c 00 00 0a bd cc 18 0c 00 00 00 00 00 00 00 0a bd db 18 10 00 00 08 5f 30 00 00 00 00 ab dd c1 9c 40 00
+00 00 00 00 00 00 03 80 00 00 81 41 c0 00 00 20 00 00 00 00 00 00 00 00 00 0c 08 00 10 67 0a dc 3c 00 00 0b 28 6f 00 00 00
+00 00 00 00 00 00 00 04 00 60 0a bd ce 50 04 01 80 00 00 00 00 00 00 00 00 50 10 01 84 08 37 f8 00 40 00 00 b1 44 00 00 00 98
+00 00 00 00 00 00 03 c0 00 00 97 c2 80 08 00 00 00 00 00 00 00 04 ab c2 e0 80 00 00 00 46 1f 40 34 00 00 00 65 ea 70 f0 04
+00 00 00 00 00 00 06 04 00 00 08 15 cc 00 11 40 00 00 00 00 00 00 08 14 6b 30 00 00 00 0c 7f a8 00 00 00 00 29 fc 88 18 00 80
+00 00 00 00 00 00 44 00 03 20 81 42 e0 0e 00 0c 00 00 00 00 00 00 97 c2 d0 90 00 0c 00 00 00 04 00 00 30 00 00 00 01 00 00
+00 00 00 00 00 00 20 70 00 30 0a bd 7f 01 80 00 80 00 00 00 00 00 08 14 ed 71 a0 00 80 00 00 02 02 00 03 00 00 00 00 1c 00 00
+00 00 01 20 a0 ac 40 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 97 c2 d1 0f 00 00 02 af 06 84 3c 00 00 03 2c 09 08 90 00
+00 00 00 02 af 7e 20 60 00 00 00 00 00 80 00 00 00 00 00 00 00 00 08 14 4f 80 00 00 00 20 57 7e 00 40 00 10 22 4e 93 81 00 00
+00 00 00 00 00 00 00 00 00 00 82 80 90 00 00 00 00 00 00 00 00 80 24 c3 91 00 00 00 00 00 00 06 00 00 00 00 64 59 b0 00 00
+00 00 00 00 00 00 00 00 00 00 0a bd e8 00 00 00 00 00 00 00 00 01 02 8d fc 98 00 00 00 00 00 00 40 00 00 00 29 d4 a0 1e 00 00
+00 02 00 00 00 00 00 00 00 00 81 41 83 00 00 00 00 00 00 00 00 00 06 7e e0 0f 00 00 02 05 06 80 00 00 00 03 2c 0a 01 00 00
+00 00 00 00 00 00 00 00 00 00 0a bd 7a 80 00 00 00 00 00 00 00 00 02 9e eb 00 00 00 00 2a f5 fc 00 00 00 10 22 5c 90 1c 1c 00
+00 00 00 24 e1 bc 00 00 00 00 90 a4 fd 18 00 00 00 00 00 00 00 00 b2 a4 80 00 00 00 0a 0a 0b c0 20 00 00 00 1c d8 d8 00 00
+00 00 20 02 8d d0 00 00 00 00 0b 9c 08 19 d0 00 00 00 00 00 00 00 0b 14 c0 00 e0 00 00 2a f5 68 07 c0 00 00 2a c6 85 1a 00 00
+00 00 00 20 a0 b8 00 00 00 00 81 42 80 00 00 00 00 00 00 00 00 00 82 82 a0 0b 00 00 02 05 0a 80 00 00 04 00 ae db 00 b0 00
+00 00 00 02 af 76 06 00 05 00 0a bd da 00 00 00 00 00 00 00 00 00 0a bd ce 00 a0 00 00 2a f7 6c 68 00 00 00 09 f5 95 9a 00 00
+00 00 00 20 50 60 00 00 00 00 00 00 07 00 00 00 00 00 00 00 00 00 b2 84 f0 20 00 00 00 00 00 00 00 00 00 01 9c 18 51 e0 00
+00 00 00 02 af 72 40 78 00 60 00 00 00 02 00 01 80 00 00 00 00 00 0b 14 c0 00 00 01 80 00 00 00 00 00 06 10 20 de ed 8a 00 00
+00 00 00 00 00 00 c0 00 00 00 06 6f 90 0e 01 00 00 00 00 00 80 00 06 7e e0 00 00 00 00 57 df 40 00 00 00 00 66 d8 50 00 14
+00 00 00 00 00 00 20 00 00 00 02 9d c9 1a 00 00 00 00 00 00 00 00 02 9f c9 19 80 00 00 0a 13 bc 00 00 00 00 29 e7 bf 1c 00 00
+00 00 00 00 00 00 00 00 00 00 19 c2 8b 00 00 80 00 00 00 00 00 00 00 00 00 00 00 08 00 af 04 2c 2c 00 00 0a a8 1c 30 00 00
+80 00 00 00 00 00 00 00 00 01 02 0d da 80 00 00 00 00 00 80 60 00 00 00 00 00 00 00 c8 0a f7 6a 00 00 00 00 a9 55 b8 00 00 2c
+00 00 08 09 30 bc 20 00 00 00 06 57 d5 00 00 00 00 00 00 00 00 00 97 c0 d0 00 00 00 10 67 0b 24 28 00 00 0a bc 1a 11 00 06
+00 00 00 40 a3 52 1e 00 00 00 02 9d f9 f0 00 00 00 00 00 00 00 00 28 14 ed 01 80 00 04 08 37 b6 07 80 00 00 81 57 a8 1a 00 a0
+00 00 00 01 9d 64 20 00 00 00 00 00 03 0d 00 00 00 00 00 00 00 81 81 41 c1 9c 00 00 00 46 bb f4 30 00 00 09 7c 2c 00 c0 02
+00 00 00 00 a7 1a de 00 00 00 00 00 00 80 10 00 00 00 00 00 00 00 0a bd 7c 98 90 00 00 0c 73 70 00 00 00 00 81 54 b0 19 00 00
+00 02 01 06 30 e8 00 00 00 00 13 cc 80 08 00 00 00 00 00 00 00 00 00 00 00 0e 00 00 00 d0 d3 9e 40 00 00 08 6d 68 11 00 00
+00 00 00 40 a3 57 40 00 00 00 01 17 49 10 00 00 00 00 00 00 02 00 00 00 00 01 e0 00 20 0e 0d 80 e2 80 00 00 89 d6 18 1a 00 00
+00 00 00 01 9d 64 00 00 00 00 17 c3 80 19 00 00 00 00 00 00 00 81 ab c1 c0 00 00 00 00 05 d2 f4 7a 00 00 08 28 2f 10 e0 00
+00 00 20 00 a7 52 54 2a 80 01 02 05 69 18 a0 00 00 00 00 00 00 00 08 14 ca 01 80 00 00 0e 79 a0 43 d0 00 00 ab d4 a9 80 00 00
+00 00 00 06 30 e4 c4 00 00 00 05 d7 85 8b 00 80 00 00 00 00 00 00 00 00 00 00 40 00 10 67 0b 34 38 00 00 09 39 68 00 00 00
+00 00 00 40 a3 52 4c 28 00 00 00 9d 4c 78 c0 14 00 00 00 00 00 00 00 00 00 18 02 00 04 08 31 7e 03 00 00 00 a3 5c 11 9e 00 00
+00 00 00 01 9d a7 42 a0 20 00 18 c3 a0 8b 00 00 00 00 00 00 00 00 81 40 c0 00 40 00 00 57 57 40 2c 00 00 02 4c 0b 00 80 00
+00 00 00 00 a7 5a 4e 00 04 01 12 8c 4b 11 c0 00 00 00 00 00 00 00 2a bd c8 00 08 01 80 0a 13 f0 00 00 00 10 28 dd 90 01 00 18
+00 00 00 00 00 03 62 80 00 00 11 4d 93 0d 00 00 00 00 00 00 00 00 97 c2 80 0f 00 00 00 4f 56 80 2c 00 00 00 2f 6d 02 00 08
+00 00 00 00 00 00 14 28 00 00 02 3c 6e 80 d0 00 00 00 00 00 00 00 18 14 ec 00 10 00 00 04 5f 28 60 00 00 00 2a de c0 00 15 40
+00 00 00 20 50 a0 00 00 02 00 97 c0 d1 10 00 0c 00 00 00 00 00 00 aa 81 c0 00 00 0c 02 0a 0b c4 40 00 30 00 00 00 08 e0 00
+00 00 00 02 af 5f 40 00 00 20 08 15 5b 81 c0 00 c0 00 00 00 00 00 0a 95 db 00 e0 00 c0 2a f5 e7 62 07 03 00 00 00 05 00 00 00
+00 00 00 00 00 00 00 00 00 00 ab c3 a0 00 00 00 00 00 00 00 00 00 ab c3 e1 00 00 00 02 05 0e 04 24 00 00 03 1c 0e d1 00 10
+00 60 00 00 00 00 00 60 00 00 08 14 ff 00 00 00 00 00 00 00 00 00 08 15 5a 81 e0 00 00 2a f7 f6 06 00 00 12 22 4c 80 08 00 00
+00 00 08 20 50 63 c3 40 00 04 05 e6 97 00 00 00 00 00 00 00 00 00 97 c2 c0 0e 00 00 02 0a 02 82 00 00 00 03 9c 0c 51 e0 00
+00 00 00 02 af 5f 40 04 00 00 00 9f 58 18 00 00 00 00 00 00 00 00 08 15 4f 01 90 00 00 2a f5 e5 40 00 00 10 01 4c 9d 8e 00 00
+00 02 00 20 a0 3b c0 00 04 00 00 00 00 00 01 10 00 00 00 00 00 00 86 de 80 00 00 10 02 05 06 00 00 00 40 02 4c 3a d0 a0 01
+00 00 00 06 af 5e 00 00 00 00 00 00 00 00 00 08 00 00 00 00 02 00 08 9d 61 00 c0 00 00 2a f5 a4 00 00 00 10 28 c5 9b 98 00 00
+00 00 00 00 00 00 02 00 00 00 00 00 00 10 00 00 00 00 00 00 00 00 82 82 f1 20 84 00 02 55 06 40 20 00 00 01 19 fd 01 00 00
+00 00 20 00 00 00 06 64 00 00 00 00 00 00 e0 00 00 00 00 00 00 00 0a bd 4e 98 00 00 00 2a 51 f8 66 40 00 00 31 ee d0 0a 00 80
+00 00 00 00 00 00 02 00 00 00 06 67 d0 80 a0 00 00 00 00 00 00 00 93 9e 85 00 00 00 02 4e 1b 80 20 00 00 00 5e df 00 a4 00
+00 00 00 00 00 00 00 04 00 00 02 9e ff 50 a0 00 00 00 00 00 00 00 0a 35 c1 98 00 00 00 28 df 00 00 40 00 00 09 d4 f0 01 80 00
+00 00 00 20 50 60 03 80 00 00 00 00 03 8b 00 00 00 00 00 00 20 00 24 c0 b0 08 00 00 02 0a 02 80 3c 00 00 02 4c 2d 58 a0 00
+00 00 00 02 af 73 40 78 00 60 00 00 00 b8 0a 01 80 00 00 00 01 01 02 8c f9 00 10 01 80 2a f7 60 00 40 06 10 28 cd 85 0a 00 00
+00 00 00 20 a0 2c 00 00 00 00 00 00 00 00 00 40 00 00 00 00 80 00 01 f5 c0 00 00 00 02 05 02 00 00 00 00 01 5e 6c 01 e0 00
+00 00 01 02 af 56 40 00 00 00 00 00 00 10 00 08 00 00 00 01 00 00 02 ac cf 00 00 00 00 2a f5 3c 60 00 00 00 28 65 93 8a 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0c 00 00 00 00 00 01 19 c0 e0 8c 00 00 00 45 12 76 39 00 00 08 28 2c 11 08 0c
+80 00 00 00 00 00 00 00 00 00 00 00 00 00 02 00 80 00 00 00 00 01 02 0c c8 18 10 00 00 0e 5d a7 e0 08 00 00 ab d6 d8 1a 01 08
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 ee e3 98 00 00 80 67 06 44 00 00 00 09 38 ea 10 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 39 80 00 00 00 00 00 00 00 02 ad ce 50 a0 00 04 08 37 f2 06 00 00 20 a3 5e 18 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 03 00 00 80 00 00 00 00 00 00 34 ae e0 0b 00 00 00 19 d7 c0 34 00 00 08 28 0a 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 03 85 e1 00 08 00 00 0a 73 fd e0 40 00 00 ab d6 d0 0a 80 40
+00 00 00 00 00 00 00 00 04 00 00 00 00 00 00 10 00 00 00 00 00 00 24 c0 9d 8b a0 10 00 99 d2 26 40 00 40 09 38 cb 00 c0 11
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 03 02 8c 69 18 00 00 00 06 68 06 66 00 00 00 a3 56 00 01 00 80
+00 00 00 00 00 00 00 00 00 00 00 00 00 10 00 00 00 00 00 00 00 00 39 c2 80 10 18 00 80 96 03 40 40 00 02 08 28 28 00 80 80
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 00 00 00 00 01 00 15 6b 58 a2 00 04 06 91 81 42 03 00 00 ab d4 c1 99 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 08 00 00 00 00 00 00 00 00 24 c1 a0 10 00 00 00 4b 03 6c 00 00 00 09 38 eb 00 04 08
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 10 00 00 00 00 00 00 01 02 8d d9 01 c0 00 04 08 73 02 00 00 00 00 a3 5c 11 80 00 40
+00 00 00 00 00 00 00 00 00 80 82 81 a0 00 00 00 00 00 00 00 00 00 06 5e f7 90 00 00 08 f0 00 00 64 00 00 0b 28 4f 32 c0 00
+00 00 00 00 00 00 00 00 00 00 0a bd ce 00 00 01 80 00 00 00 00 00 02 9d dc d1 c0 00 00 0f 01 81 62 84 00 00 b1 4c 08 01 01 58
+00 00 00 00 00 00 00 00 00 20 99 bc d0 00 00 00 00 00 00 00 00 00 3c 01 f0 1e 00 00 00 0f 0f ac 28 00 00 00 65 e9 00 00 00
+00 00 00 00 00 00 00 00 00 00 0a 94 0b 00 00 00 00 00 00 00 00 00 00 3d ed 00 b0 00 00 4a 57 32 00 40 00 00 29 fc 90 18 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 3c c3 87 10 a0 00 02 05 02 94 28 00 30 00 00 00 50 00 00
+c0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 03 3c fa 00 e4 00 00 2a f5 b7 62 40 03 00 00 00 08 00 00 08
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0c c3 d1 00 00 00 02 25 07 14 40 00 00 0b c0 20 08 01 c0
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 01 a4 59 80 00 00 04 22 e5 fa 02 00 00 00 bc 0c 01 9a 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 3c 01 fd 00 00 00 00 0c 07 86 00 00 00 00 ce dd 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 3d 59 01 80 00 04 00 e3 7f c0 00 00 00 33 24 e5 80 00 00
+00 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 21 c0 e0 00 00 00 00 33 0a 00 28 00 00 01 a7 d0 58 00 14
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 01 e0 dd 01 81 80 04 0c c7 34 06 c0 00 00 5a 45 c9 80 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 43 80 90 00 00 00 f0 16 c0 20 04 00 01 a6 c0 01 00 00
+00 00 20 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 40 fa 70 a0 00 00 0e 17 70 06 40 20 00 5a 64 a0 1c 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0f 02 e0 00 00 00 02 25 32 86 00 00 30 01 a6 d0 00 04 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 78 5d 01 a0 00 00 22 e7 ef e0 00 02 00 5a 45 80 1a 80 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 2b c3 05 80 00 00 02 7f b2 80 2c 00 00 01 a7 d0 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 bc fa f0 00 00 00 63 fd b4 08 00 06 00 5a 64 85 9a 00 18
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 80 00 1a 56 80 0b 00 00 00 f0 bb 80 00 00 00 01 a5 c0 50 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 f3 cc 19 a0 00 00 46 9d 20 06 00 00 00 5a 41 88 00 01 04
+00 00 00 00 00 00 00 00 40 00 00 00 00 00 00 0c 00 00 00 00 00 00 96 80 c0 00 40 08 00 00 00 00 00 00 30 0b c0 20 00 e0 00
+80 00 00 00 00 00 00 00 03 00 00 00 00 00 80 00 c0 00 00 00 00 00 0a 94 00 02 00 00 80 00 00 00 00 07 02 00 bc 14 00 19 00 0c
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 04 83 c0 00 00 00 00 00 00 00 04 2c 00 00 10 04 1a 00 e0 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 08 3c e0 00 00 00 00 00 00 02 06 40 00 10 01 dc d3 80 00 00
+00 00 00 00 00 00 00 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 83 c2 00 00 00 00 00 00 00 00 00 00 80 01 4c 2c 01 c0 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 08 3d 60 01 80 00 00 00 00 00 00 00 00 10 28 dc 10 1d 00 00
+00 02 00 00 00 00 00 00 00 00 00 00 00 00 01 40 00 00 00 07 00 00 00 00 00 00 00 00 00 00 00 04 30 00 00 01 54 18 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 18 00 00 00 00 00 00 00 00 00 00 c0 00 00 00 00 00 00 00 00 00 29 56 81 80 00 00
+00 00 00 00 00 00 02 88 00 00 00 00 00 00 40 00 00 00 00 00 00 00 00 00 00 00 10 00 00 00 00 00 40 00 00 01 4c 2a 00 a4 00
+00 00 20 00 00 00 1c 03 80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 18 00 00 00 00 00 00 03 80 00 10 28 dc 00 0a 80 00
+00 00 00 07 7d 6c 20 00 00 00 00 00 00 00 0c 00 00 00 00 00 00 00 00 00 00 00 00 02 12 0a 0b 00 7c 00 00 02 a8 19 00 e0 00
+00 00 00 10 ee 5e 5e 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 10 6a f7 38 07 40 00 00 29 57 95 80 0c 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 10 00 00 00 00 00 00 00 00 00 2f 00 01 8a 05 07 80 00 80 50 41 05 cd d0 00 00
+00 00 00 00 00 00 14 00 00 00 00 00 00 00 02 01 00 00 00 00 00 00 00 00 00 00 10 01 80 2a f7 30 00 00 04 00 20 57 e1 80 00 18
+00 00 00 00 00 00 00 00 00 a0 c3 c0 00 0d 00 00 00 00 00 00 00 00 00 00 00 00 00 02 8a 0a 02 00 30 00 00 0b c0 00 00 80 00
+00 00 00 00 00 00 00 00 00 00 08 3c 00 00 11 40 40 00 00 00 00 00 00 00 00 00 00 00 00 6a f5 38 00 40 00 00 bc 1e 03 01 00 00
+00 00 00 24 80 74 02 00 02 00 00 00 01 98 00 0c 00 00 00 00 00 40 87 e7 e0 0f 00 0c 02 0a 0b 9c 00 00 20 4a bc 28 19 00 00
+c0 00 00 02 21 16 80 7c 00 20 00 00 00 91 d0 c0 c0 00 00 00 00 00 08 1d 6f 00 e0 00 c8 2a f5 a2 02 00 02 00 81 57 93 9c 00 0c
+00 00 01 24 80 78 00 00 00 21 87 e6 b0 0c 00 00 00 00 00 00 00 00 91 e4 f1 88 00 00 00 aa 0b 40 30 00 00 09 4e cf 00 00 00
+00 00 00 03 21 16 dc 60 80 00 08 1f e9 71 90 00 00 00 00 00 00 04 0b 0e ec b1 90 00 08 0a 55 f0 c0 00 00 80 a8 e6 10 00 00 00
+00 00 00 24 80 34 00 00 00 00 87 c7 b0 00 80 80 00 00 00 00 00 00 93 cd 93 08 00 00 82 aa 03 00 00 00 00 0a 67 4c 10 00 00
+00 00 00 03 21 16 80 00 00 0a 08 1c d8 01 a4 00 00 00 00 00 00 00 18 35 6f 00 80 00 00 2a 57 ec 06 00 00 00 a9 41 98 18 00 00
+00 02 00 24 80 38 20 00 00 04 87 e4 f7 00 00 00 00 00 00 00 00 00 82 fc d0 29 01 00 0a 8d 10 14 00 00 00 08 28 1f 08 00 10
+00 00 00 03 21 17 de 00 00 02 08 1f e8 00 00 00 00 00 00 00 04 00 18 bd 6d 00 c0 08 00 28 d5 e2 c6 00 00 00 ab d6 b7 00 00 80
+00 00 00 64 80 74 40 00 00 00 c3 f7 e0 09 00 00 00 00 00 10 10 00 a2 f5 cf 08 00 40 80 05 0e dc 60 00 80 00 14 3f 00 80 00
+00 00 20 03 21 12 a6 60 20 08 09 1d 5e 10 10 00 00 00 00 00 00 00 1b 0e ee 99 90 00 00 0a f1 2c 67 40 20 00 2b d6 91 81 00 00
+00 00 00 a4 80 78 43 c0 03 04 86 be 97 00 00 00 00 00 00 00 00 00 a8 45 f0 00 00 00 02 47 9b 80 00 00 00 02 a8 29 30 00 00
+00 00 00 03 21 12 e6 04 00 30 0a 9f 4e 18 e0 00 00 00 00 00 00 00 0a 9e ce 00 00 00 01 28 b3 05 e3 80 00 80 29 4d c8 0e 1c 00
+00 00 01 24 80 34 03 80 00 40 8b c5 e7 00 00 14 00 00 00 00 00 00 93 cd e1 0d 00 10 02 47 38 00 7c 00 50 00 14 2f 00 d0 09
+40 00 00 03 21 13 80 00 00 60 08 1d ce 00 00 01 00 00 00 00 00 00 08 35 cf f0 10 01 48 24 77 20 07 00 04 00 2b ce 90 0f 19 10
+00 00 02 24 80 38 00 00 00 20 1d e4 e1 00 00 00 00 00 00 00 80 00 a2 c4 f0 0e 05 40 00 aa 0a c4 24 00 00 22 a8 28 f0 f1 00
+00 00 00 07 21 12 c0 00 00 00 03 b9 7c 80 80 00 00 00 00 00 00 00 08 3d cc 70 00 08 08 0a 57 b2 00 00 00 00 29 4d a0 00 00 00
+00 00
+62 00 3f
+72 00 80
+11 00
+82 00 00
+01 03
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00
+82 00 80
+01 03
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00
+11 01
+82 00 00
+01 03
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00
+82 00 80
+01 03
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00
+11 02
+82 00 00
+01 03
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00
+82 00 80
+01 03
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00
+11 03
+82 00 00
+01 03
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00
+82 00 80
+01 03
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00
+22
+84 b1
+01 06
+
diff --git a/fpga/readme.md b/fpga/readme.md
new file mode 100644
index 0000000..ad763a1
--- /dev/null
+++ b/fpga/readme.md
@@ -0,0 +1,72 @@
+ / _____) _ | |
+ ( (____ _____ ____ _| |_ _____ ____| |__
+ \____ \| ___ | (_ _) ___ |/ ___) _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+ (______/|_____)_|_|_| \__)_____)\____)_| |_|
+ (C)2013 Semtech-Cycleo
+
+FPGA images for LoRa Gateway SX1301AP2-PCB_E336
+===============================================
+
+1. Content
+----------
+
+This directory contains the FPGA images to be programmed in the Semtech's
+Reference Design board (SX1301AP2-PCB_E336) flash memory.
+
+The different images contain the following features:
+
+* SX1301_FPGA_200K_NOTCH_LBT_SPECTRAL_SCAN_915_v33.hex:
+ - 200KHz Notch filter for TX (not programmable)
+ - Listen-Before-Talk for 915+MHz frequency range (Japan)
+ - Background Spectral Scan (limited)
+
+* SX1301_FPGA_200K_NOTCH_LBT_SPECTRAL_SCAN_863_v33.hex:
+ - 200KHz Notch filter for TX (not programmable)
+ - Listen-Before-Talk for 863+MHz frequency range
+ - Background Spectral Scan (limited)
+Note: This image is the same as the 915+MHz version. It is just meant for
+testing "Japan-like" LBT feature on a EU868 board. It does not provide certified
+LBT for European band.
+
+* SX1301_FPGA_NOTCH_PROG_SPECTRAL_SCAN_v31.hex:
+ - Programmable notch filter for TX
+ - Background Spectral Scan (full)
+
+2. Usage
+--------
+
+The following parameters have to be set when using the Lattice Diamond
+Programmer software:
+
+Device Family -> iCE40
+Device -> iCE40LP1K
+Operation -> SPI Flash Programming
+ -> Programming file: select one of the provided bin image
+ -> SPI Vendor: Micron
+ -> SPI Device: SPI-M25P10-A
+
+3. Legal notice
+----------------
+
+The information presented in this project documentation does not form part of
+any quotation or contract, is believed to be accurate and reliable and may be
+changed without notice. No liability will be accepted by the publisher for any
+consequence of its use. Publication thereof does not convey nor imply any
+license under patent or other industrial or intellectual property rights.
+Semtech assumes no responsibility or liability whatsoever for any failure or
+unexpected operation resulting from misuse, neglect improper installation,
+repair or improper handling or unusual physical or electrical stress
+including, but not limited to, exposure to parameters beyond the specified
+maximum ratings or operation outside the specified range.
+
+SEMTECH PRODUCTS ARE NOT DESIGNED, INTENDED, AUTHORIZED OR WARRANTED TO BE
+SUITABLE FOR USE IN LIFE-SUPPORT APPLICATIONS, DEVICES OR SYSTEMS OR OTHER
+CRITICAL APPLICATIONS. INCLUSION OF SEMTECH PRODUCTS IN SUCH APPLICATIONS IS
+UNDERSTOOD TO BE UNDERTAKEN SOLELY AT THE CUSTOMER'S OWN RISK. Should a
+customer purchase or use Semtech products for any such unauthorized
+application, the customer shall indemnify and hold Semtech and its officers,
+employees, subsidiaries, affiliates, and distributors harmless against all
+claims, costs damages and attorney fees which could arise.
+
+*EOF*
diff --git a/libloragw/99-libftdi.rules b/libloragw/99-libftdi.rules
new file mode 100644
index 0000000..8487413
--- /dev/null
+++ b/libloragw/99-libftdi.rules
@@ -0,0 +1,8 @@
+# FTDI Devices: FT232BM/L/Q, FT245BM/L/Q, FT232RL/Q, FT245RL/Q, VNC1L with VDPS Firmware
+SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6001", MODE="0664", GROUP="plugdev"
+
+# FTDI Devices: FT2232C/D/L, FT2232HL/Q
+SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6010", MODE="0664", GROUP="plugdev"
+
+# FTDI Devices: FT4232HL/Q
+SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6011", MODE="0664", GROUP="plugdev"
diff --git a/libloragw/Makefile b/libloragw/Makefile
new file mode 100644
index 0000000..53c33d9
--- /dev/null
+++ b/libloragw/Makefile
@@ -0,0 +1,91 @@
+### get external defined data
+
+LIBLORAGW_VERSION := `cat ../VERSION`
+include library.cfg
+
+### constant symbols
+
+ARCH ?=
+CROSS_COMPILE ?=
+CC := $(CROSS_COMPILE)gcc
+AR := $(CROSS_COMPILE)ar
+
+CFLAGS := -O2 -Wall -Wextra -std=c99 -Iinc -I.
+
+OBJDIR = obj
+INCLUDES = $(wildcard inc/*.h)
+
+### linking options
+
+LIBS := -lloragw -lrt -lm
+
+### general build targets
+
+all: libloragw.a test_loragw_spi test_loragw_reg test_loragw_hal test_loragw_gps test_loragw_cal
+
+clean:
+ rm -f libloragw.a
+ rm -f test_loragw_*
+ rm -f $(OBJDIR)/*.o
+ rm -f inc/config.h
+
+### transpose library.cfg into a C header file : config.h
+
+inc/config.h: ../VERSION library.cfg
+ @echo "*** Checking libloragw library configuration ***"
+ @rm -f $@
+ #File initialization
+ @echo "#ifndef _LORAGW_CONFIGURATION_H" >> $@
+ @echo "#define _LORAGW_CONFIGURATION_H" >> $@
+ # Release version
+ @echo "Release version : $(LIBLORAGW_VERSION)"
+ @echo " #define LIBLORAGW_VERSION "\"$(LIBLORAGW_VERSION)\""" >> $@
+ # Debug options
+ @echo " #define DEBUG_AUX $(DEBUG_AUX)" >> $@
+ @echo " #define DEBUG_SPI $(DEBUG_SPI)" >> $@
+ @echo " #define DEBUG_REG $(DEBUG_REG)" >> $@
+ @echo " #define DEBUG_HAL $(DEBUG_HAL)" >> $@
+ @echo " #define DEBUG_GPS $(DEBUG_GPS)" >> $@
+ @echo " #define DEBUG_GPIO $(DEBUG_GPIO)" >> $@
+ @echo " #define DEBUG_LBT $(DEBUG_LBT)" >> $@
+ # end of file
+ @echo "#endif" >> $@
+ @echo "*** Configuration seems ok ***"
+
+### library module target
+
+$(OBJDIR):
+ mkdir -p $(OBJDIR)
+
+$(OBJDIR)/%.o: src/%.c $(INCLUDES) inc/config.h | $(OBJDIR)
+ $(CC) -c $(CFLAGS) $< -o $@
+
+$(OBJDIR)/loragw_spi.o: src/loragw_spi.native.c $(INCLUDES) inc/config.h | $(OBJDIR)
+ $(CC) -c $(CFLAGS) $< -o $@
+
+$(OBJDIR)/loragw_hal.o: src/loragw_hal.c $(INCLUDES) src/arb_fw.var src/agc_fw.var src/cal_fw.var inc/config.h | $(OBJDIR)
+ $(CC) -c $(CFLAGS) $< -o $@
+
+### static library
+
+libloragw.a: $(OBJDIR)/loragw_hal.o $(OBJDIR)/loragw_gps.o $(OBJDIR)/loragw_reg.o $(OBJDIR)/loragw_spi.o $(OBJDIR)/loragw_aux.o $(OBJDIR)/loragw_radio.o $(OBJDIR)/loragw_fpga.o $(OBJDIR)/loragw_lbt.o
+ $(AR) rcs $@ $^
+
+### test programs
+
+test_loragw_spi: tst/test_loragw_spi.c libloragw.a
+ $(CC) $(CFLAGS) -L. $< -o $@ $(LIBS)
+
+test_loragw_reg: tst/test_loragw_reg.c libloragw.a
+ $(CC) $(CFLAGS) -L. $< -o $@ $(LIBS)
+
+test_loragw_hal: tst/test_loragw_hal.c libloragw.a
+ $(CC) $(CFLAGS) -L. $< -o $@ $(LIBS)
+
+test_loragw_gps: tst/test_loragw_gps.c libloragw.a
+ $(CC) $(CFLAGS) -L. $< -o $@ $(LIBS)
+
+test_loragw_cal: tst/test_loragw_cal.c libloragw.a src/cal_fw.var
+ $(CC) $(CFLAGS) -L. $< -o $@ $(LIBS)
+
+### EOF
diff --git a/libloragw/inc/loragw_aux.h b/libloragw/inc/loragw_aux.h
new file mode 100644
index 0000000..35b39ab
--- /dev/null
+++ b/libloragw/inc/loragw_aux.h
@@ -0,0 +1,48 @@
+/*
+ / _____) _ | |
+( (____ _____ ____ _| |_ _____ ____| |__
+ \____ \| ___ | (_ _) ___ |/ ___) _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+ (C)2013 Semtech-Cycleo
+
+Description:
+ LoRa concentrator HAL common auxiliary functions
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+Maintainer: Sylvain Miermont
+*/
+
+
+#ifndef _LORAGW_AUX_H
+#define _LORAGW_AUX_H
+
+/* -------------------------------------------------------------------------- */
+/* --- DEPENDANCIES --------------------------------------------------------- */
+
+#include "config.h" /* library configuration options (dynamically generated) */
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC MACROS -------------------------------------------------------- */
+
+/**
+@brief Get a particular bit value from a byte
+@param b [in] Any byte from which we want a bit value
+@param p [in] Position of the bit in the byte [0..7]
+@param n [in] Number of bits we want to get
+@return The value corresponding the requested bits
+*/
+#define TAKE_N_BITS_FROM(b, p, n) (((b) >> (p)) & ((1 << (n)) - 1))
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC FUNCTIONS PROTOTYPES ------------------------------------------ */
+
+/**
+@brief Wait for a certain time (millisecond accuracy)
+@param t number of milliseconds to wait.
+*/
+void wait_ms(unsigned long t);
+
+#endif
+
+/* --- EOF ------------------------------------------------------------------ */
diff --git a/libloragw/inc/loragw_fpga.h b/libloragw/inc/loragw_fpga.h
new file mode 100644
index 0000000..f599f73
--- /dev/null
+++ b/libloragw/inc/loragw_fpga.h
@@ -0,0 +1,135 @@
+/*
+ / _____) _ | |
+( (____ _____ ____ _| |_ _____ ____| |__
+ \____ \| ___ | (_ _) ___ |/ ___) _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+ (C)2013 Semtech-Cycleo
+
+Description:
+ Functions used to handle FPGA register access for LoRa concentrator.
+ Registers are addressed by name.
+ Multi-bytes registers are handled automatically.
+ Read-modify-write is handled automatically.
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+Maintainer: Michael Coracin
+*/
+
+#ifndef _LORAGW_FPGA_REG_H
+#define _LORAGW_FPGA_REG_H
+
+/* -------------------------------------------------------------------------- */
+/* --- DEPENDANCIES --------------------------------------------------------- */
+
+#include <stdint.h> /* C99 types */
+#include <stdbool.h> /* bool type */
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC CONSTANTS ----------------------------------------------------- */
+
+#define LGW_REG_SUCCESS 0
+#define LGW_REG_ERROR -1
+
+#define LGW_MIN_NOTCH_FREQ 126000U /* 126 KHz */
+#define LGW_MAX_NOTCH_FREQ 250000U /* 250 KHz */
+#define LGW_DEFAULT_NOTCH_FREQ 129000U /* 129 KHz */
+
+/*
+auto generated register mapping for C code
+this file contains autogenerated C struct used to access the FPGA registers
+this file is autogenerated from registers description
+*/
+
+#define LGW_FPGA_SOFT_RESET 0
+#define LGW_FPGA_FEATURE 1
+#define LGW_FPGA_LBT_INITIAL_FREQ 2
+#define LGW_FPGA_VERSION 3
+#define LGW_FPGA_STATUS 4
+#define LGW_FPGA_CTRL_FEATURE_START 5
+#define LGW_FPGA_CTRL_RADIO_RESET 6
+#define LGW_FPGA_CTRL_INPUT_SYNC_I 7
+#define LGW_FPGA_CTRL_INPUT_SYNC_Q 8
+#define LGW_FPGA_CTRL_OUTPUT_SYNC 9
+#define LGW_FPGA_CTRL_INVERT_IQ 10
+#define LGW_FPGA_CTRL_ACCESS_HISTO_MEM 11
+#define LGW_FPGA_CTRL_CLEAR_HISTO_MEM 12
+#define LGW_FPGA_HISTO_RAM_ADDR 13
+#define LGW_FPGA_HISTO_RAM_DATA 14
+#define LGW_FPGA_HISTO_NB_READ 15
+#define LGW_FPGA_LBT_TIMESTAMP_CH 16
+#define LGW_FPGA_LBT_TIMESTAMP_SELECT_CH 17
+#define LGW_FPGA_LBT_CH0_FREQ_OFFSET 18
+#define LGW_FPGA_LBT_CH1_FREQ_OFFSET 19
+#define LGW_FPGA_LBT_CH2_FREQ_OFFSET 20
+#define LGW_FPGA_LBT_CH3_FREQ_OFFSET 21
+#define LGW_FPGA_LBT_CH4_FREQ_OFFSET 22
+#define LGW_FPGA_LBT_CH5_FREQ_OFFSET 23
+#define LGW_FPGA_LBT_CH6_FREQ_OFFSET 24
+#define LGW_FPGA_LBT_CH7_FREQ_OFFSET 25
+#define LGW_FPGA_SCAN_FREQ_OFFSET 26
+#define LGW_FPGA_LBT_SCAN_TIME_CH0 27
+#define LGW_FPGA_LBT_SCAN_TIME_CH1 28
+#define LGW_FPGA_LBT_SCAN_TIME_CH2 29
+#define LGW_FPGA_LBT_SCAN_TIME_CH3 30
+#define LGW_FPGA_LBT_SCAN_TIME_CH4 31
+#define LGW_FPGA_LBT_SCAN_TIME_CH5 32
+#define LGW_FPGA_LBT_SCAN_TIME_CH6 33
+#define LGW_FPGA_LBT_SCAN_TIME_CH7 34
+#define LGW_FPGA_RSSI_TARGET 35
+#define LGW_FPGA_HISTO_SCAN_FREQ 36
+#define LGW_FPGA_NOTCH_FREQ_OFFSET 37
+#define LGW_FPGA_TOTALREGS 38
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC FUNCTIONS PROTOTYPES ------------------------------------------ */
+
+/**
+@brief LoRa concentrator TX notch filter delay
+@return delay in microseconds introduced by TX notch filter
+*/
+float lgw_fpga_get_tx_notch_delay(void);
+
+/**
+@brief LoRa concentrator FPGA configuration
+@param tx_notch_freq TX notch filter frequency, in Hertz
+@return status of register operation (LGW_REG_SUCCESS/LGW_REG_ERROR)
+*/
+int lgw_fpga_configure(uint32_t tx_notch_freq);
+
+/**
+@brief LoRa concentrator FPGA register write
+@param register_id register number in the data structure describing registers
+@param reg_value signed value to write to the register (for u32, use cast)
+@return status of register operation (LGW_REG_SUCCESS/LGW_REG_ERROR)
+*/
+int lgw_fpga_reg_w(uint16_t register_id, int32_t reg_value);
+
+/**
+@brief LoRa concentrator FPGA register read
+@param register_id register number in the data structure describing registers
+@param reg_value pointer to a variable where to write register read value
+@return status of register operation (LGW_REG_SUCCESS/LGW_REG_ERROR)
+*/
+int lgw_fpga_reg_r(uint16_t register_id, int32_t *reg_value);
+
+/**
+@brief LoRa concentrator FPGA register burst write
+@param register_id register number in the data structure describing registers
+@param data pointer to byte array that will be sent to the LoRa concentrator
+@param size size of the transfer, in byte(s)
+@return status of register operation (LGW_REG_SUCCESS/LGW_REG_ERROR)
+*/
+int lgw_fpga_reg_wb(uint16_t register_id, uint8_t *data, uint16_t size);
+
+/**
+@brief LoRa concentrator FPGA register burst read
+@param register_id register number in the data structure describing registers
+@param data pointer to byte array that will be written from the LoRa concentrator
+@param size size of the transfer, in byte(s)
+@return status of register operation (LGW_REG_SUCCESS/LGW_REG_ERROR)
+*/
+int lgw_fpga_reg_rb(uint16_t register_id, uint8_t *data, uint16_t size);
+
+#endif
+/* --- EOF ------------------------------------------------------------------ */
diff --git a/libloragw/inc/loragw_gps.h b/libloragw/inc/loragw_gps.h
new file mode 100644
index 0000000..6dbd30b
--- /dev/null
+++ b/libloragw/inc/loragw_gps.h
@@ -0,0 +1,235 @@
+/*
+ / _____) _ | |
+( (____ _____ ____ _| |_ _____ ____| |__
+ \____ \| ___ | (_ _) ___ |/ ___) _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+ (C)2013 Semtech-Cycleo
+
+Description:
+ Library of functions to manage a GNSS module (typically GPS) for accurate
+ timestamping of packets and synchronisation of gateways.
+ A limited set of module brands/models are supported.
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+Maintainer: Michael Coracin
+*/
+
+
+#ifndef _LORAGW_GPS_H
+#define _LORAGW_GPS_H
+
+/* -------------------------------------------------------------------------- */
+/* --- DEPENDANCIES --------------------------------------------------------- */
+
+#define _GNU_SOURCE
+#include <stdint.h> /* C99 types */
+#include <time.h> /* time library */
+#include <termios.h> /* speed_t */
+#include <unistd.h> /* ssize_t */
+
+#include "config.h" /* library configuration options (dynamically generated) */
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC TYPES --------------------------------------------------------- */
+
+/**
+@struct coord_s
+@brief Time solution required for timestamp to absolute time conversion
+*/
+struct tref {
+ time_t systime; /*!> system time when solution was calculated */
+ uint32_t count_us; /*!> reference concentrator internal timestamp */
+ struct timespec utc; /*!> reference UTC time (from GPS/NMEA) */
+ struct timespec gps; /*!> reference GPS time (since 01.Jan.1980) */
+ double xtal_err; /*!> raw clock error (eg. <1 'slow' XTAL) */
+};
+
+/**
+@struct coord_s
+@brief Geodesic coordinates
+*/
+struct coord_s {
+ double lat; /*!> latitude [-90,90] (North +, South -) */
+ double lon; /*!> longitude [-180,180] (East +, West -)*/
+ short alt; /*!> altitude in meters (WGS 84 geoid ref.) */
+};
+
+/**
+@enum gps_msg
+@brief Type of GPS (and other GNSS) sentences
+*/
+enum gps_msg {
+ UNKNOWN, /*!> neutral value */
+ IGNORED, /*!> frame was not parsed by the system */
+ INVALID, /*!> system try to parse frame but failed */
+ INCOMPLETE, /*!> frame parsed was missing bytes */
+ /* NMEA messages of interest */
+ NMEA_RMC, /*!> Recommended Minimum data (time + date) */
+ NMEA_GGA, /*!> Global positioning system fix data (pos + alt) */
+ NMEA_GNS, /*!> GNSS fix data (pos + alt, sat number) */
+ NMEA_ZDA, /*!> Time and Date */
+ /* NMEA message useful for time reference quality assessment */
+ NMEA_GBS, /*!> GNSS Satellite Fault Detection */
+ NMEA_GST, /*!> GNSS Pseudo Range Error Statistics */
+ NMEA_GSA, /*!> GNSS DOP and Active Satellites (sat number) */
+ NMEA_GSV, /*!> GNSS Satellites in View (sat SNR) */
+ /* Misc. NMEA messages */
+ NMEA_GLL, /*!> Latitude and longitude, with time fix and status */
+ NMEA_TXT, /*!> Text Transmission */
+ NMEA_VTG, /*!> Course over ground and Ground speed */
+ /* uBlox proprietary NMEA messages of interest */
+ UBX_NAV_TIMEGPS, /*!> GPS Time Solution */
+ UBX_NAV_TIMEUTC /*!> UTC Time Solution */
+};
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC CONSTANTS ----------------------------------------------------- */
+
+#define LGW_GPS_SUCCESS 0
+#define LGW_GPS_ERROR -1
+
+#define LGW_GPS_MIN_MSG_SIZE (8)
+#define LGW_GPS_UBX_SYNC_CHAR (0xB5)
+#define LGW_GPS_NMEA_SYNC_CHAR (0x24)
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC FUNCTIONS PROTOTYPES ------------------------------------------ */
+
+/**
+@brief Configure a GPS module
+
+@param tty_path path to the TTY connected to the GPS
+@param gps_familly parameter (eg. ubx6 for uBlox gen.6)
+@param target_brate target baudrate for communication (0 keeps default target baudrate)
+@param fd_ptr pointer to a variable to receive file descriptor on GPS tty
+@return success if the function was able to connect and configure a GPS module
+*/
+int lgw_gps_enable(char* tty_path, char* gps_familly, speed_t target_brate, int* fd_ptr);
+
+/**
+@brief Restore GPS serial configuration and close serial device
+
+@param fd file descriptor on GPS tty
+@return success if the function was able to complete
+*/
+int lgw_gps_disable(int fd);
+
+/**
+@brief Parse messages coming from the GPS system (or other GNSS)
+
+@param serial_buff pointer to the string to be parsed
+@param buff_size maximum string lengths for NMEA parsing (incl. null char)
+@return type of frame parsed
+
+The RAW NMEA sentences are parsed to a global set of variables shared with the
+lgw_gps_get function.
+If the lgw_parse_nmea and lgw_gps_get are used in different threads, a mutex
+lock must be acquired before calling either function.
+*/
+enum gps_msg lgw_parse_nmea(const char* serial_buff, int buff_size);
+
+/**
+@brief Parse Ublox proprietary messages coming from the GPS system
+
+@param serial_buff pointer to the string to be parsed
+@param buff_size maximum string lengths for UBX parsing (incl. null char)
+@param msg_size number of bytes parsed as UBX message if found
+@return type of frame parsed
+
+The RAW UBX sentences are parsed to a global set of variables shared with the
+lgw_gps_get function.
+If the lgw_parse_ubx and lgw_gps_get are used in different threads, a mutex
+lock must be acquired before calling either function.
+*/
+enum gps_msg lgw_parse_ubx(const char* serial_buff, size_t buff_size, size_t *msg_size);
+
+/**
+@brief Get the GPS solution (space & time) for the concentrator
+
+@param utc pointer to store UTC time, with ns precision (NULL to ignore)
+@param gps_time pointer to store GPS time, with ns precision (NULL to ignore)
+@param loc pointer to store coordinates (NULL to ignore)
+@param err pointer to store coordinates standard deviation (NULL to ignore)
+@return success if the chosen elements could be returned
+
+This function read the global variables generated by the NMEA/UBX parsing
+functions lgw_parse_nmea/lgw_parse_ubx. It returns time and location data in a
+format that is exploitable by other functions in that library sub-module.
+If the lgw_parse_nmea/lgw_parse_ubx and lgw_gps_get are used in different
+threads, a mutex lock must be acquired before calling either function.
+*/
+int lgw_gps_get(struct timespec *utc, struct timespec *gps_time, struct coord_s *loc, struct coord_s *err);
+
+/**
+@brief Get time and position information from the serial GPS last message received
+@param utc UTC time, with ns precision (leap seconds are ignored)
+@param gps_time timestamp of last time pulse from the GPS module converted to the UNIX epoch
+ (leap seconds are ignored)
+@param loc location information
+@param err location error estimate if supported
+@return success if timestamp was read and time reference could be refreshed
+
+Set systime to 0 in ref to trigger initial synchronization.
+*/
+int lgw_gps_sync(struct tref *ref, uint32_t count_us, struct timespec utc, struct timespec gps_time);
+
+/**
+@brief Convert concentrator timestamp counter value to UTC time
+
+@param ref time reference structure required for time conversion
+@param count_us internal timestamp counter of the LoRa concentrator
+@param utc pointer to store UTC time, with ns precision (leap seconds ignored)
+@return success if the function was able to convert timestamp to UTC
+
+This function is typically used when a packet is received to transform the
+internal counter-based timestamp in an absolute timestamp with an accuracy in
+the order of a couple microseconds (ns resolution).
+*/
+int lgw_cnt2utc(struct tref ref, uint32_t count_us, struct timespec* utc);
+
+/**
+@brief Convert UTC time to concentrator timestamp counter value
+
+@param ref time reference structure required for time conversion
+@param utc UTC time, with ns precision (leap seconds are ignored)
+@param count_us pointer to store internal timestamp counter of LoRa concentrator
+@return success if the function was able to convert UTC to timestamp
+
+This function is typically used when a packet must be sent at an accurate time
+(eg. to send a piggy-back response after receiving a packet from a node) to
+transform an absolute UTC time into a matching internal concentrator timestamp.
+*/
+int lgw_utc2cnt(struct tref ref,struct timespec utc, uint32_t* count_us);
+
+/**
+@brief Convert concentrator timestamp counter value to GPS time
+
+@param ref time reference structure required for time conversion
+@param count_us internal timestamp counter of the LoRa concentrator
+@param gps_time pointer to store GPS time, with ns precision (leap seconds ignored)
+@return success if the function was able to convert timestamp to GPS time
+
+This function is typically used when a packet is received to transform the
+internal counter-based timestamp in an absolute timestamp with an accuracy in
+the order of a millisecond.
+*/
+int lgw_cnt2gps(struct tref ref, uint32_t count_us, struct timespec* gps_time);
+
+/**
+@brief Convert GPS time to concentrator timestamp counter value
+
+@param ref time reference structure required for time conversion
+@param gps_time GPS time, with ns precision (leap seconds are ignored)
+@param count_us pointer to store internal timestamp counter of LoRa concentrator
+@return success if the function was able to convert GPS time to timestamp
+
+This function is typically used when a packet must be sent at an accurate time
+(eg. to send a piggy-back response after receiving a packet from a node) to
+transform an absolute GPS time into a matching internal concentrator timestamp.
+*/
+int lgw_gps2cnt(struct tref ref, struct timespec gps_time, uint32_t* count_us);
+
+#endif
+
+/* --- EOF ------------------------------------------------------------------ */
diff --git a/libloragw/inc/loragw_hal.h b/libloragw/inc/loragw_hal.h
new file mode 100644
index 0000000..d5f9ade
--- /dev/null
+++ b/libloragw/inc/loragw_hal.h
@@ -0,0 +1,419 @@
+/*
+ / _____) _ | |
+( (____ _____ ____ _| |_ _____ ____| |__
+ \____ \| ___ | (_ _) ___ |/ ___) _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+ (C)2013 Semtech-Cycleo
+
+Description:
+ LoRa concentrator Hardware Abstraction Layer
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+Maintainer: Sylvain Miermont
+*/
+
+
+#ifndef _LORAGW_HAL_H
+#define _LORAGW_HAL_H
+
+/* -------------------------------------------------------------------------- */
+/* --- DEPENDANCIES --------------------------------------------------------- */
+
+#include <stdint.h> /* C99 types */
+#include <stdbool.h> /* bool type */
+
+#include "config.h" /* library configuration options (dynamically generated) */
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC MACROS -------------------------------------------------------- */
+
+#define IS_LORA_BW(bw) ((bw == BW_125KHZ) || (bw == BW_250KHZ) || (bw == BW_500KHZ))
+#define IS_LORA_STD_DR(dr) ((dr == DR_LORA_SF7) || (dr == DR_LORA_SF8) || (dr == DR_LORA_SF9) || (dr == DR_LORA_SF10) || (dr == DR_LORA_SF11) || (dr == DR_LORA_SF12))
+#define IS_LORA_MULTI_DR(dr) ((dr & ~DR_LORA_MULTI) == 0) /* ones outside of DR_LORA_MULTI bitmask -> not a combination of LoRa datarates */
+#define IS_LORA_CR(cr) ((cr == CR_LORA_4_5) || (cr == CR_LORA_4_6) || (cr == CR_LORA_4_7) || (cr == CR_LORA_4_8))
+
+#define IS_FSK_BW(bw) ((bw >= 1) && (bw <= 7))
+#define IS_FSK_DR(dr) ((dr >= DR_FSK_MIN) && (dr <= DR_FSK_MAX))
+
+#define IS_TX_MODE(mode) ((mode == IMMEDIATE) || (mode == TIMESTAMPED) || (mode == ON_GPS))
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC CONSTANTS ----------------------------------------------------- */
+
+/* return status code */
+#define LGW_HAL_SUCCESS 0
+#define LGW_HAL_ERROR -1
+#define LGW_LBT_ISSUE 1
+
+/* radio-specific parameters */
+#define LGW_XTAL_FREQU 32000000 /* frequency of the RF reference oscillator */
+#define LGW_RF_CHAIN_NB 2 /* number of RF chains */
+#define LGW_RF_RX_BANDWIDTH {1000000, 1000000} /* bandwidth of the radios */
+
+/* type of if_chain + modem */
+#define IF_UNDEFINED 0
+#define IF_LORA_STD 0x10 /* if + standard single-SF LoRa modem */
+#define IF_LORA_MULTI 0x11 /* if + LoRa receiver with multi-SF capability */
+#define IF_FSK_STD 0x20 /* if + standard FSK modem */
+
+/* concentrator chipset-specific parameters */
+/* to use array parameters, declare a local const and use 'if_chain' as index */
+#define LGW_IF_CHAIN_NB 10 /* number of IF+modem RX chains */
+#define LGW_PKT_FIFO_SIZE 16 /* depth of the RX packet FIFO */
+#define LGW_DATABUFF_SIZE 1024 /* size in bytes of the RX data buffer (contains payload & metadata) */
+#define LGW_REF_BW 125000 /* typical bandwidth of data channel */
+#define LGW_MULTI_NB 8 /* number of LoRa 'multi SF' chains */
+#define LGW_IFMODEM_CONFIG {\
+ IF_LORA_MULTI, \
+ IF_LORA_MULTI, \
+ IF_LORA_MULTI, \
+ IF_LORA_MULTI, \
+ IF_LORA_MULTI, \
+ IF_LORA_MULTI, \
+ IF_LORA_MULTI, \
+ IF_LORA_MULTI, \
+ IF_LORA_STD, \
+ IF_FSK_STD } /* configuration of available IF chains and modems on the hardware */
+
+/* values available for the 'modulation' parameters */
+/* NOTE: arbitrary values */
+#define MOD_UNDEFINED 0
+#define MOD_LORA 0x10
+#define MOD_FSK 0x20
+
+/* values available for the 'bandwidth' parameters (LoRa & FSK) */
+/* NOTE: directly encode FSK RX bandwidth, do not change */
+#define BW_UNDEFINED 0
+#define BW_500KHZ 0x01
+#define BW_250KHZ 0x02
+#define BW_125KHZ 0x03
+#define BW_62K5HZ 0x04
+#define BW_31K2HZ 0x05
+#define BW_15K6HZ 0x06
+#define BW_7K8HZ 0x07
+
+/* values available for the 'datarate' parameters */
+/* NOTE: LoRa values used directly to code SF bitmask in 'multi' modem, do not change */
+#define DR_UNDEFINED 0
+#define DR_LORA_SF7 0x02
+#define DR_LORA_SF8 0x04
+#define DR_LORA_SF9 0x08
+#define DR_LORA_SF10 0x10
+#define DR_LORA_SF11 0x20
+#define DR_LORA_SF12 0x40
+#define DR_LORA_MULTI 0x7E
+/* NOTE: for FSK directly use baudrate between 500 bauds and 250 kbauds */
+#define DR_FSK_MIN 500
+#define DR_FSK_MAX 250000
+
+/* values available for the 'coderate' parameters (LoRa only) */
+/* NOTE: arbitrary values */
+#define CR_UNDEFINED 0
+#define CR_LORA_4_5 0x01
+#define CR_LORA_4_6 0x02
+#define CR_LORA_4_7 0x03
+#define CR_LORA_4_8 0x04
+
+/* values available for the 'status' parameter */
+/* NOTE: values according to hardware specification */
+#define STAT_UNDEFINED 0x00
+#define STAT_NO_CRC 0x01
+#define STAT_CRC_BAD 0x11
+#define STAT_CRC_OK 0x10
+
+/* values available for the 'tx_mode' parameter */
+#define IMMEDIATE 0
+#define TIMESTAMPED 1
+#define ON_GPS 2
+//#define ON_EVENT 3
+//#define GPS_DELAYED 4
+//#define EVENT_DELAYED 5
+
+/* values available for 'select' in the status function */
+#define TX_STATUS 1
+#define RX_STATUS 2
+
+/* status code for TX_STATUS */
+/* NOTE: arbitrary values */
+#define TX_STATUS_UNKNOWN 0
+#define TX_OFF 1 /* TX modem disabled, it will ignore commands */
+#define TX_FREE 2 /* TX modem is free, ready to receive a command */
+#define TX_SCHEDULED 3 /* TX modem is loaded, ready to send the packet after an event and/or delay */
+#define TX_EMITTING 4 /* TX modem is emitting */
+
+/* status code for RX_STATUS */
+/* NOTE: arbitrary values */
+#define RX_STATUS_UNKNOWN 0
+#define RX_OFF 1 /* RX modem is disabled, it will ignore commands */
+#define RX_ON 2 /* RX modem is receiving */
+#define RX_SUSPENDED 3 /* RX is suspended while a TX is ongoing */
+
+/* Maximum size of Tx gain LUT */
+#define TX_GAIN_LUT_SIZE_MAX 16
+
+/* LBT constants */
+#define LBT_CHANNEL_FREQ_NB 8 /* Number of LBT channels */
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC TYPES --------------------------------------------------------- */
+
+/**
+@enum lgw_radio_type_e
+@brief Radio types that can be found on the LoRa Gateway
+*/
+enum lgw_radio_type_e {
+ LGW_RADIO_TYPE_NONE,
+ LGW_RADIO_TYPE_SX1255,
+ LGW_RADIO_TYPE_SX1257,
+ LGW_RADIO_TYPE_SX1272,
+ LGW_RADIO_TYPE_SX1276
+};
+
+/**
+@struct lgw_conf_board_s
+@brief Configuration structure for board specificities
+*/
+struct lgw_conf_board_s {
+ bool lorawan_public; /*!> Enable ONLY for *public* networks using the LoRa MAC protocol */
+ uint8_t clksrc; /*!> Index of RF chain which provides clock to concentrator */
+};
+
+/**
+@struct lgw_conf_lbt_chan_s
+@brief Configuration structure for LBT channels
+*/
+struct lgw_conf_lbt_chan_s {
+ uint32_t freq_hz;
+ uint16_t scan_time_us;
+};
+
+/**
+@struct lgw_conf_lbt_s
+@brief Configuration structure for LBT specificities
+*/
+struct lgw_conf_lbt_s {
+ bool enable; /*!> enable or disable LBT */
+ int8_t rssi_target; /*!> RSSI threshold to detect if channel is busy or not (dBm) */
+ uint8_t nb_channel; /*!> number of LBT channels */
+ struct lgw_conf_lbt_chan_s channels[LBT_CHANNEL_FREQ_NB];
+ int8_t rssi_offset; /*!> RSSI offset to be applied to SX127x RSSI values */
+};
+
+/**
+@struct lgw_conf_rxrf_s
+@brief Configuration structure for a RF chain
+*/
+struct lgw_conf_rxrf_s {
+ bool enable; /*!> enable or disable that RF chain */
+ uint32_t freq_hz; /*!> center frequency of the radio in Hz */
+ float rssi_offset; /*!> Board-specific RSSI correction factor */
+ enum lgw_radio_type_e type; /*!> Radio type for that RF chain (SX1255, SX1257....) */
+ bool tx_enable; /*!> enable or disable TX on that RF chain */
+ uint32_t tx_notch_freq; /*!> TX notch filter frequency [126KHz..250KHz] */
+};
+
+/**
+@struct lgw_conf_rxif_s
+@brief Configuration structure for an IF chain
+*/
+struct lgw_conf_rxif_s {
+ bool enable; /*!> enable or disable that IF chain */
+ uint8_t rf_chain; /*!> to which RF chain is that IF chain associated */
+ int32_t freq_hz; /*!> center frequ of the IF chain, relative to RF chain frequency */
+ uint8_t bandwidth; /*!> RX bandwidth, 0 for default */
+ uint32_t datarate; /*!> RX datarate, 0 for default */
+ uint8_t sync_word_size; /*!> size of FSK sync word (number of bytes, 0 for default) */
+ uint64_t sync_word; /*!> FSK sync word (ALIGN RIGHT, eg. 0xC194C1) */
+};
+
+/**
+@struct lgw_pkt_rx_s
+@brief Structure containing the metadata of a packet that was received and a pointer to the payload
+*/
+struct lgw_pkt_rx_s {
+ uint32_t freq_hz; /*!> central frequency of the IF chain */
+ uint8_t if_chain; /*!> by which IF chain was packet received */
+ uint8_t status; /*!> status of the received packet */
+ uint32_t count_us; /*!> internal concentrator counter for timestamping, 1 microsecond resolution */
+ uint8_t rf_chain; /*!> through which RF chain the packet was received */
+ uint8_t modulation; /*!> modulation used by the packet */
+ uint8_t bandwidth; /*!> modulation bandwidth (LoRa only) */
+ uint32_t datarate; /*!> RX datarate of the packet (SF for LoRa) */
+ uint8_t coderate; /*!> error-correcting code of the packet (LoRa only) */
+ float rssi; /*!> average packet RSSI in dB */
+ float snr; /*!> average packet SNR, in dB (LoRa only) */
+ float snr_min; /*!> minimum packet SNR, in dB (LoRa only) */
+ float snr_max; /*!> maximum packet SNR, in dB (LoRa only) */
+ uint16_t crc; /*!> CRC that was received in the payload */
+ uint16_t size; /*!> payload size in bytes */
+ uint8_t payload[256]; /*!> buffer containing the payload */
+};
+
+/**
+@struct lgw_pkt_tx_s
+@brief Structure containing the configuration of a packet to send and a pointer to the payload
+*/
+struct lgw_pkt_tx_s {
+ uint32_t freq_hz; /*!> center frequency of TX */
+ uint8_t tx_mode; /*!> select on what event/time the TX is triggered */
+ uint32_t count_us; /*!> timestamp or delay in microseconds for TX trigger */
+ uint8_t rf_chain; /*!> through which RF chain will the packet be sent */
+ int8_t rf_power; /*!> TX power, in dBm */
+ uint8_t modulation; /*!> modulation to use for the packet */
+ uint8_t bandwidth; /*!> modulation bandwidth (LoRa only) */
+ uint32_t datarate; /*!> TX datarate (baudrate for FSK, SF for LoRa) */
+ uint8_t coderate; /*!> error-correcting code of the packet (LoRa only) */
+ bool invert_pol; /*!> invert signal polarity, for orthogonal downlinks (LoRa only) */
+ uint8_t f_dev; /*!> frequency deviation, in kHz (FSK only) */
+ uint16_t preamble; /*!> set the preamble length, 0 for default */
+ bool no_crc; /*!> if true, do not send a CRC in the packet */
+ bool no_header; /*!> if true, enable implicit header mode (LoRa), fixed length (FSK) */
+ uint16_t size; /*!> payload size in bytes */
+ uint8_t payload[256]; /*!> buffer containing the payload */
+};
+
+/**
+@struct lgw_tx_gain_s
+@brief Structure containing all gains of Tx chain
+*/
+struct lgw_tx_gain_s {
+ uint8_t dig_gain; /*!> 2 bits, control of the digital gain of SX1301 */
+ uint8_t pa_gain; /*!> 2 bits, control of the external PA (SX1301 I/O) */
+ uint8_t dac_gain; /*!> 2 bits, control of the radio DAC */
+ uint8_t mix_gain; /*!> 4 bits, control of the radio mixer */
+ int8_t rf_power; /*!> measured TX power at the board connector, in dBm */
+};
+
+/**
+@struct lgw_tx_gain_lut_s
+@brief Structure defining the Tx gain LUT
+*/
+struct lgw_tx_gain_lut_s {
+ struct lgw_tx_gain_s lut[TX_GAIN_LUT_SIZE_MAX]; /*!> Array of Tx gain struct */
+ uint8_t size; /*!> Number of LUT indexes */
+};
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC FUNCTIONS PROTOTYPES ------------------------------------------ */
+
+/**
+@brief Configure the gateway board
+@param conf structure containing the configuration parameters
+@return LGW_HAL_ERROR id the operation failed, LGW_HAL_SUCCESS else
+*/
+int lgw_board_setconf(struct lgw_conf_board_s conf);
+
+/**
+@brief Configure the gateway lbt function
+@param conf structure containing the configuration parameters
+@return LGW_HAL_ERROR id the operation failed, LGW_HAL_SUCCESS else
+*/
+int lgw_lbt_setconf(struct lgw_conf_lbt_s conf);
+
+/**
+@brief Configure an RF chain (must configure before start)
+@param rf_chain number of the RF chain to configure [0, LGW_RF_CHAIN_NB - 1]
+@param conf structure containing the configuration parameters
+@return LGW_HAL_ERROR id the operation failed, LGW_HAL_SUCCESS else
+*/
+int lgw_rxrf_setconf(uint8_t rf_chain, struct lgw_conf_rxrf_s conf);
+
+/**
+@brief Configure an IF chain + modem (must configure before start)
+@param if_chain number of the IF chain + modem to configure [0, LGW_IF_CHAIN_NB - 1]
+@param conf structure containing the configuration parameters
+@return LGW_HAL_ERROR id the operation failed, LGW_HAL_SUCCESS else
+*/
+int lgw_rxif_setconf(uint8_t if_chain, struct lgw_conf_rxif_s conf);
+
+/**
+@brief Configure the Tx gain LUT
+@param pointer to structure defining the LUT
+@return LGW_HAL_ERROR id the operation failed, LGW_HAL_SUCCESS else
+*/
+int lgw_txgain_setconf(struct lgw_tx_gain_lut_s *conf);
+
+/**
+@brief Connect to the LoRa concentrator, reset it and configure it according to previously set parameters
+@return LGW_HAL_ERROR id the operation failed, LGW_HAL_SUCCESS else
+*/
+int lgw_start(void);
+
+/**
+@brief Stop the LoRa concentrator and disconnect it
+@return LGW_HAL_ERROR id the operation failed, LGW_HAL_SUCCESS else
+*/
+int lgw_stop(void);
+
+/**
+@brief A non-blocking function that will fetch up to 'max_pkt' packets from the LoRa concentrator FIFO and data buffer
+@param max_pkt maximum number of packet that must be retrieved (equal to the size of the array of struct)
+@param pkt_data pointer to an array of struct that will receive the packet metadata and payload pointers
+@return LGW_HAL_ERROR id the operation failed, else the number of packets retrieved
+*/
+int lgw_receive(uint8_t max_pkt, struct lgw_pkt_rx_s *pkt_data);
+
+/**
+@brief Schedule a packet to be send immediately or after a delay depending on tx_mode
+@param pkt_data structure containing the data and metadata for the packet to send
+@return LGW_HAL_ERROR id the operation failed, LGW_HAL_SUCCESS else
+
+/!\ When sending a packet, there is a delay (approx 1.5ms) for the analog
+circuitry to start and be stable. This delay is adjusted by the HAL depending
+on the board version (lgw_i_tx_start_delay_us).
+
+In 'timestamp' mode, this is transparent: the modem is started
+lgw_i_tx_start_delay_us microseconds before the user-set timestamp value is
+reached, the preamble of the packet start right when the internal timestamp
+counter reach target value.
+
+In 'immediate' mode, the packet is emitted as soon as possible: transferring the
+packet (and its parameters) from the host to the concentrator takes some time,
+then there is the lgw_i_tx_start_delay_us, then the packet is emitted.
+
+In 'triggered' mode (aka PPS/GPS mode), the packet, typically a beacon, is
+emitted lgw_i_tx_start_delay_us microsenconds after a rising edge of the
+trigger signal. Because there is no way to anticipate the triggering event and
+start the analog circuitry beforehand, that delay must be taken into account in
+the protocol.
+*/
+int lgw_send(struct lgw_pkt_tx_s pkt_data);
+
+/**
+@brief Give the the status of different part of the LoRa concentrator
+@param select is used to select what status we want to know
+@param code is used to return the status code
+@return LGW_HAL_ERROR id the operation failed, LGW_HAL_SUCCESS else
+*/
+int lgw_status(uint8_t select, uint8_t *code);
+
+/**
+@brief Abort a currently scheduled or ongoing TX
+@return LGW_HAL_ERROR id the operation failed, LGW_HAL_SUCCESS else
+*/
+int lgw_abort_tx(void);
+
+/**
+@brief Return value of internal counter when latest event (eg GPS pulse) was captured
+@param trig_cnt_us pointer to receive timestamp value
+@return LGW_HAL_ERROR id the operation failed, LGW_HAL_SUCCESS else
+*/
+int lgw_get_trigcnt(uint32_t* trig_cnt_us);
+
+/**
+@brief Allow user to check the version/options of the library once compiled
+@return pointer on a human-readable null terminated string
+*/
+const char* lgw_version_info(void);
+
+/**
+@brief Return time on air of given packet, in milliseconds
+@param packet is a pointer to the packet structure
+@return the packet time on air in milliseconds
+*/
+uint32_t lgw_time_on_air(struct lgw_pkt_tx_s *packet);
+
+#endif
+
+/* --- EOF ------------------------------------------------------------------ */
diff --git a/libloragw/inc/loragw_lbt.h b/libloragw/inc/loragw_lbt.h
new file mode 100644
index 0000000..cb8aada
--- /dev/null
+++ b/libloragw/inc/loragw_lbt.h
@@ -0,0 +1,70 @@
+/*
+ / _____) _ | |
+( (____ _____ ____ _| |_ _____ ____| |__
+ \____ \| ___ | (_ _) ___ |/ ___) _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+ (C)2013 Semtech-Cycleo
+
+Description:
+ Functions used to handle the Listen Before Talk feature
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+Maintainer: Michael Coracin
+*/
+
+#ifndef _LORAGW_LBT_H
+#define _LORAGW_LBT_H
+
+/* -------------------------------------------------------------------------- */
+/* --- DEPENDANCIES --------------------------------------------------------- */
+
+#include <stdint.h> /* C99 types */
+#include <stdbool.h> /* bool type */
+
+#include "loragw_hal.h"
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC CONSTANTS ----------------------------------------------------- */
+
+#define LGW_LBT_SUCCESS 0
+#define LGW_LBT_ERROR -1
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC FUNCTIONS PROTOTYPES ------------------------------------------ */
+
+/**
+@brief Set the configuration parameters for LBT feature
+@param conf structure containing the configuration parameters
+@return LGW_LBT_ERROR id the operation failed, LGW_LBT_SUCCESS else
+*/
+int lbt_setconf(struct lgw_conf_lbt_s * conf);
+
+/**
+@brief Configure the concentrator for LBT feature
+@return LGW_LBT_ERROR id the operation failed, LGW_LBT_SUCCESS else
+*/
+int lbt_setup(void);
+
+/**
+@brief Start the LBT FSM
+@return LGW_LBT_ERROR id the operation failed, LGW_LBT_SUCCESS else
+*/
+int lbt_start(void);
+
+/**
+@brief Configure the concentrator for LBT feature
+@param pkt_data pointer to downlink packet to be trabsmitted
+@param tx_allowed pointer to receive permission for transmission
+@return LGW_LBT_ERROR id the operation failed, LGW_LBT_SUCCESS else
+*/
+int lbt_is_channel_free(struct lgw_pkt_tx_s * pkt_data, uint16_t tx_start_delay, bool * tx_allowed);
+
+/**
+@brief Check if LBT is enabled
+@return true if enabled, false otherwise
+*/
+bool lbt_is_enabled(void);
+
+#endif
+/* --- EOF ------------------------------------------------------------------ */
diff --git a/libloragw/inc/loragw_radio.h b/libloragw/inc/loragw_radio.h
new file mode 100644
index 0000000..32d494b
--- /dev/null
+++ b/libloragw/inc/loragw_radio.h
@@ -0,0 +1,73 @@
+/*
+ / _____) _ | |
+( (____ _____ ____ _| |_ _____ ____| |__
+ \____ \| ___ | (_ _) ___ |/ ___) _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+ (C)2013 Semtech-Cycleo
+
+Description:
+ Functions used to handle LoRa concentrator radios.
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+Maintainer: Michael Coracin
+*/
+
+#ifndef _LORAGW_RADIO_H
+#define _LORAGW_RADIO_H
+
+/* -------------------------------------------------------------------------- */
+/* --- DEPENDANCIES --------------------------------------------------------- */
+
+#include <stdint.h> /* C99 types */
+#include <stdbool.h> /* bool type */
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC CONSTANTS ----------------------------------------------------- */
+
+#define LGW_REG_SUCCESS 0
+#define LGW_REG_ERROR -1
+
+#define SX125x_32MHz_FRAC 15625 /* irreductible fraction for PLL register caculation */
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC CONSTANTS ----------------------------------------------------- */
+
+enum lgw_sx127x_rxbw_e {
+ LGW_SX127X_RXBW_2K6_HZ,
+ LGW_SX127X_RXBW_3K1_HZ,
+ LGW_SX127X_RXBW_3K9_HZ,
+ LGW_SX127X_RXBW_5K2_HZ,
+ LGW_SX127X_RXBW_6K3_HZ,
+ LGW_SX127X_RXBW_7K8_HZ,
+ LGW_SX127X_RXBW_10K4_HZ,
+ LGW_SX127X_RXBW_12K5_HZ,
+ LGW_SX127X_RXBW_15K6_HZ,
+ LGW_SX127X_RXBW_20K8_HZ,
+ LGW_SX127X_RXBW_25K_HZ,
+ LGW_SX127X_RXBW_31K3_HZ,
+ LGW_SX127X_RXBW_41K7_HZ,
+ LGW_SX127X_RXBW_50K_HZ,
+ LGW_SX127X_RXBW_62K5_HZ,
+ LGW_SX127X_RXBW_83K3_HZ,
+ LGW_SX127X_RXBW_100K_HZ,
+ LGW_SX127X_RXBW_125K_HZ,
+ LGW_SX127X_RXBW_166K7_HZ,
+ LGW_SX127X_RXBW_200K_HZ,
+ LGW_SX127X_RXBW_250K_HZ
+};
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC FUNCTIONS PROTOTYPES ------------------------------------------ */
+
+int lgw_setup_sx125x(uint8_t rf_chain, uint8_t rf_clkout, bool rf_enable, uint8_t rf_radio_type, uint32_t freq_hz);
+
+int lgw_setup_sx127x(uint32_t frequency, uint8_t modulation, enum lgw_sx127x_rxbw_e rxbw_khz, int8_t rssi_offset);
+
+int lgw_sx127x_reg_w(uint8_t address, uint8_t reg_value);
+
+int lgw_sx127x_reg_r(uint8_t address, uint8_t *reg_value);
+
+
+#endif
+/* --- EOF ------------------------------------------------------------------ */
diff --git a/libloragw/inc/loragw_reg.h b/libloragw/inc/loragw_reg.h
new file mode 100644
index 0000000..2a944a7
--- /dev/null
+++ b/libloragw/inc/loragw_reg.h
@@ -0,0 +1,461 @@
+/*
+ / _____) _ | |
+( (____ _____ ____ _| |_ _____ ____| |__
+ \____ \| ___ | (_ _) ___ |/ ___) _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+ (C)2013 Semtech-Cycleo
+
+Description:
+ Functions used to handle a single LoRa concentrator.
+ Registers are addressed by name.
+ Multi-bytes registers are handled automatically.
+ Read-modify-write is handled automatically.
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+Maintainer: Sylvain Miermont
+*/
+
+
+#ifndef _LORAGW_REG_H
+#define _LORAGW_REG_H
+
+/* -------------------------------------------------------------------------- */
+/* --- DEPENDANCIES --------------------------------------------------------- */
+
+#include <stdint.h> /* C99 types */
+#include <stdbool.h> /* bool type */
+
+#include "config.h" /* library configuration options (dynamically generated) */
+
+/* -------------------------------------------------------------------------- */
+/* --- INTERNAL SHARED TYPES ------------------------------------------------ */
+
+struct lgw_reg_s {
+ int8_t page; /*!< page containing the register (-1 for all pages) */
+ uint8_t addr; /*!< base address of the register (7 bit) */
+ uint8_t offs; /*!< position of the register LSB (between 0 to 7) */
+ bool sign; /*!< 1 indicates the register is signed (2 complem.) */
+ uint8_t leng; /*!< number of bits in the register */
+ bool rdon; /*!< 1 indicates a read-only register */
+ int32_t dflt; /*!< register default value */
+};
+
+/* -------------------------------------------------------------------------- */
+/* --- INTERNAL SHARED FUNCTIONS -------------------------------------------- */
+
+int reg_w_align32(void *spi_target, uint8_t spi_mux_mode, uint8_t spi_mux_target, struct lgw_reg_s r, int32_t reg_value);
+int reg_r_align32(void *spi_target, uint8_t spi_mux_mode, uint8_t spi_mux_target, struct lgw_reg_s r, int32_t *reg_value);
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC CONSTANTS ----------------------------------------------------- */
+
+#define LGW_REG_SUCCESS 0
+#define LGW_REG_ERROR -1
+
+/*
+auto generated register mapping for C code : 11-Jul-2013 13:20:40
+this file contains autogenerated C struct used to access the LORA registers
+this file is autogenerated from registers description
+293 registers are defined
+*/
+
+#define LGW_PAGE_REG 0
+#define LGW_SOFT_RESET 1
+#define LGW_VERSION 2
+#define LGW_RX_DATA_BUF_ADDR 3
+#define LGW_RX_DATA_BUF_DATA 4
+#define LGW_TX_DATA_BUF_ADDR 5
+#define LGW_TX_DATA_BUF_DATA 6
+#define LGW_CAPTURE_RAM_ADDR 7
+#define LGW_CAPTURE_RAM_DATA 8
+#define LGW_MCU_PROM_ADDR 9
+#define LGW_MCU_PROM_DATA 10
+#define LGW_RX_PACKET_DATA_FIFO_NUM_STORED 11
+#define LGW_RX_PACKET_DATA_FIFO_ADDR_POINTER 12
+#define LGW_RX_PACKET_DATA_FIFO_STATUS 13
+#define LGW_RX_PACKET_DATA_FIFO_PAYLOAD_SIZE 14
+#define LGW_MBWSSF_MODEM_ENABLE 15
+#define LGW_CONCENTRATOR_MODEM_ENABLE 16
+#define LGW_FSK_MODEM_ENABLE 17
+#define LGW_GLOBAL_EN 18
+#define LGW_CLK32M_EN 19
+#define LGW_CLKHS_EN 20
+#define LGW_START_BIST0 21
+#define LGW_START_BIST1 22
+#define LGW_CLEAR_BIST0 23
+#define LGW_CLEAR_BIST1 24
+#define LGW_BIST0_FINISHED 25
+#define LGW_BIST1_FINISHED 26
+#define LGW_MCU_AGC_PROG_RAM_BIST_STATUS 27
+#define LGW_MCU_ARB_PROG_RAM_BIST_STATUS 28
+#define LGW_CAPTURE_RAM_BIST_STATUS 29
+#define LGW_CHAN_FIR_RAM0_BIST_STATUS 30
+#define LGW_CHAN_FIR_RAM1_BIST_STATUS 31
+#define LGW_CORR0_RAM_BIST_STATUS 32
+#define LGW_CORR1_RAM_BIST_STATUS 33
+#define LGW_CORR2_RAM_BIST_STATUS 34
+#define LGW_CORR3_RAM_BIST_STATUS 35
+#define LGW_CORR4_RAM_BIST_STATUS 36
+#define LGW_CORR5_RAM_BIST_STATUS 37
+#define LGW_CORR6_RAM_BIST_STATUS 38
+#define LGW_CORR7_RAM_BIST_STATUS 39
+#define LGW_MODEM0_RAM0_BIST_STATUS 40
+#define LGW_MODEM1_RAM0_BIST_STATUS 41
+#define LGW_MODEM2_RAM0_BIST_STATUS 42
+#define LGW_MODEM3_RAM0_BIST_STATUS 43
+#define LGW_MODEM4_RAM0_BIST_STATUS 44
+#define LGW_MODEM5_RAM0_BIST_STATUS 45
+#define LGW_MODEM6_RAM0_BIST_STATUS 46
+#define LGW_MODEM7_RAM0_BIST_STATUS 47
+#define LGW_MODEM0_RAM1_BIST_STATUS 48
+#define LGW_MODEM1_RAM1_BIST_STATUS 49
+#define LGW_MODEM2_RAM1_BIST_STATUS 50
+#define LGW_MODEM3_RAM1_BIST_STATUS 51
+#define LGW_MODEM4_RAM1_BIST_STATUS 52
+#define LGW_MODEM5_RAM1_BIST_STATUS 53
+#define LGW_MODEM6_RAM1_BIST_STATUS 54
+#define LGW_MODEM7_RAM1_BIST_STATUS 55
+#define LGW_MODEM0_RAM2_BIST_STATUS 56
+#define LGW_MODEM1_RAM2_BIST_STATUS 57
+#define LGW_MODEM2_RAM2_BIST_STATUS 58
+#define LGW_MODEM3_RAM2_BIST_STATUS 59
+#define LGW_MODEM4_RAM2_BIST_STATUS 60
+#define LGW_MODEM5_RAM2_BIST_STATUS 61
+#define LGW_MODEM6_RAM2_BIST_STATUS 62
+#define LGW_MODEM7_RAM2_BIST_STATUS 63
+#define LGW_MODEM_MBWSSF_RAM0_BIST_STATUS 64
+#define LGW_MODEM_MBWSSF_RAM1_BIST_STATUS 65
+#define LGW_MODEM_MBWSSF_RAM2_BIST_STATUS 66
+#define LGW_MCU_AGC_DATA_RAM_BIST0_STATUS 67
+#define LGW_MCU_AGC_DATA_RAM_BIST1_STATUS 68
+#define LGW_MCU_ARB_DATA_RAM_BIST0_STATUS 69
+#define LGW_MCU_ARB_DATA_RAM_BIST1_STATUS 70
+#define LGW_TX_TOP_RAM_BIST0_STATUS 71
+#define LGW_TX_TOP_RAM_BIST1_STATUS 72
+#define LGW_DATA_MNGT_RAM_BIST0_STATUS 73
+#define LGW_DATA_MNGT_RAM_BIST1_STATUS 74
+#define LGW_GPIO_SELECT_INPUT 75
+#define LGW_GPIO_SELECT_OUTPUT 76
+#define LGW_GPIO_MODE 77
+#define LGW_GPIO_PIN_REG_IN 78
+#define LGW_GPIO_PIN_REG_OUT 79
+#define LGW_MCU_AGC_STATUS 80
+#define LGW_MCU_ARB_STATUS 81
+#define LGW_CHIP_ID 82
+#define LGW_EMERGENCY_FORCE_HOST_CTRL 83
+#define LGW_RX_INVERT_IQ 84
+#define LGW_MODEM_INVERT_IQ 85
+#define LGW_MBWSSF_MODEM_INVERT_IQ 86
+#define LGW_RX_EDGE_SELECT 87
+#define LGW_MISC_RADIO_EN 88
+#define LGW_FSK_MODEM_INVERT_IQ 89
+#define LGW_FILTER_GAIN 90
+#define LGW_RADIO_SELECT 91
+#define LGW_IF_FREQ_0 92
+#define LGW_IF_FREQ_1 93
+#define LGW_IF_FREQ_2 94
+#define LGW_IF_FREQ_3 95
+#define LGW_IF_FREQ_4 96
+#define LGW_IF_FREQ_5 97
+#define LGW_IF_FREQ_6 98
+#define LGW_IF_FREQ_7 99
+#define LGW_IF_FREQ_8 100
+#define LGW_IF_FREQ_9 101
+#define LGW_CHANN_OVERRIDE_AGC_GAIN 102
+#define LGW_CHANN_AGC_GAIN 103
+#define LGW_CORR0_DETECT_EN 104
+#define LGW_CORR1_DETECT_EN 105
+#define LGW_CORR2_DETECT_EN 106
+#define LGW_CORR3_DETECT_EN 107
+#define LGW_CORR4_DETECT_EN 108
+#define LGW_CORR5_DETECT_EN 109
+#define LGW_CORR6_DETECT_EN 110
+#define LGW_CORR7_DETECT_EN 111
+#define LGW_CORR_SAME_PEAKS_OPTION_SF6 112
+#define LGW_CORR_SAME_PEAKS_OPTION_SF7 113
+#define LGW_CORR_SAME_PEAKS_OPTION_SF8 114
+#define LGW_CORR_SAME_PEAKS_OPTION_SF9 115
+#define LGW_CORR_SAME_PEAKS_OPTION_SF10 116
+#define LGW_CORR_SAME_PEAKS_OPTION_SF11 117
+#define LGW_CORR_SAME_PEAKS_OPTION_SF12 118
+#define LGW_CORR_SIG_NOISE_RATIO_SF6 119
+#define LGW_CORR_SIG_NOISE_RATIO_SF7 120
+#define LGW_CORR_SIG_NOISE_RATIO_SF8 121
+#define LGW_CORR_SIG_NOISE_RATIO_SF9 122
+#define LGW_CORR_SIG_NOISE_RATIO_SF10 123
+#define LGW_CORR_SIG_NOISE_RATIO_SF11 124
+#define LGW_CORR_SIG_NOISE_RATIO_SF12 125
+#define LGW_CORR_NUM_SAME_PEAK 126
+#define LGW_CORR_MAC_GAIN 127
+#define LGW_ADJUST_MODEM_START_OFFSET_RDX4 128
+#define LGW_ADJUST_MODEM_START_OFFSET_SF12_RDX4 129
+#define LGW_DBG_CORR_SELECT_SF 130
+#define LGW_DBG_CORR_SELECT_CHANNEL 131
+#define LGW_DBG_DETECT_CPT 132
+#define LGW_DBG_SYMB_CPT 133
+#define LGW_CHIRP_INVERT_RX 134
+#define LGW_DC_NOTCH_EN 135
+#define LGW_IMPLICIT_CRC_EN 136
+#define LGW_IMPLICIT_CODING_RATE 137
+#define LGW_IMPLICIT_PAYLOAD_LENGHT 138
+#define LGW_FREQ_TO_TIME_INVERT 139
+#define LGW_FREQ_TO_TIME_DRIFT 140
+#define LGW_PAYLOAD_FINE_TIMING_GAIN 141
+#define LGW_PREAMBLE_FINE_TIMING_GAIN 142
+#define LGW_TRACKING_INTEGRAL 143
+#define LGW_FRAME_SYNCH_PEAK1_POS 144
+#define LGW_FRAME_SYNCH_PEAK2_POS 145
+#define LGW_PREAMBLE_SYMB1_NB 146
+#define LGW_FRAME_SYNCH_GAIN 147
+#define LGW_SYNCH_DETECT_TH 148
+#define LGW_LLR_SCALE 149
+#define LGW_SNR_AVG_CST 150
+#define LGW_PPM_OFFSET 151
+#define LGW_MAX_PAYLOAD_LEN 152
+#define LGW_ONLY_CRC_EN 153
+#define LGW_ZERO_PAD 154
+#define LGW_DEC_GAIN_OFFSET 155
+#define LGW_CHAN_GAIN_OFFSET 156
+#define LGW_FORCE_HOST_RADIO_CTRL 157
+#define LGW_FORCE_HOST_FE_CTRL 158
+#define LGW_FORCE_DEC_FILTER_GAIN 159
+#define LGW_MCU_RST_0 160
+#define LGW_MCU_RST_1 161
+#define LGW_MCU_SELECT_MUX_0 162
+#define LGW_MCU_SELECT_MUX_1 163
+#define LGW_MCU_CORRUPTION_DETECTED_0 164
+#define LGW_MCU_CORRUPTION_DETECTED_1 165
+#define LGW_MCU_SELECT_EDGE_0 166
+#define LGW_MCU_SELECT_EDGE_1 167
+#define LGW_CHANN_SELECT_RSSI 168
+#define LGW_RSSI_BB_DEFAULT_VALUE 169
+#define LGW_RSSI_DEC_DEFAULT_VALUE 170
+#define LGW_RSSI_CHANN_DEFAULT_VALUE 171
+#define LGW_RSSI_BB_FILTER_ALPHA 172
+#define LGW_RSSI_DEC_FILTER_ALPHA 173
+#define LGW_RSSI_CHANN_FILTER_ALPHA 174
+#define LGW_IQ_MISMATCH_A_AMP_COEFF 175
+#define LGW_IQ_MISMATCH_A_PHI_COEFF 176
+#define LGW_IQ_MISMATCH_B_AMP_COEFF 177
+#define LGW_IQ_MISMATCH_B_SEL_I 178
+#define LGW_IQ_MISMATCH_B_PHI_COEFF 179
+#define LGW_TX_TRIG_IMMEDIATE 180
+#define LGW_TX_TRIG_DELAYED 181
+#define LGW_TX_TRIG_GPS 182
+#define LGW_TX_START_DELAY 183
+#define LGW_TX_FRAME_SYNCH_PEAK1_POS 184
+#define LGW_TX_FRAME_SYNCH_PEAK2_POS 185
+#define LGW_TX_RAMP_DURATION 186
+#define LGW_TX_OFFSET_I 187
+#define LGW_TX_OFFSET_Q 188
+#define LGW_TX_MODE 189
+#define LGW_TX_ZERO_PAD 190
+#define LGW_TX_EDGE_SELECT 191
+#define LGW_TX_EDGE_SELECT_TOP 192
+#define LGW_TX_GAIN 193
+#define LGW_TX_CHIRP_LOW_PASS 194
+#define LGW_TX_FCC_WIDEBAND 195
+#define LGW_TX_SWAP_IQ 196
+#define LGW_MBWSSF_IMPLICIT_HEADER 197
+#define LGW_MBWSSF_IMPLICIT_CRC_EN 198
+#define LGW_MBWSSF_IMPLICIT_CODING_RATE 199
+#define LGW_MBWSSF_IMPLICIT_PAYLOAD_LENGHT 200
+#define LGW_MBWSSF_AGC_FREEZE_ON_DETECT 201
+#define LGW_MBWSSF_FRAME_SYNCH_PEAK1_POS 202
+#define LGW_MBWSSF_FRAME_SYNCH_PEAK2_POS 203
+#define LGW_MBWSSF_PREAMBLE_SYMB1_NB 204
+#define LGW_MBWSSF_FRAME_SYNCH_GAIN 205
+#define LGW_MBWSSF_SYNCH_DETECT_TH 206
+#define LGW_MBWSSF_DETECT_MIN_SINGLE_PEAK 207
+#define LGW_MBWSSF_DETECT_TRIG_SAME_PEAK_NB 208
+#define LGW_MBWSSF_FREQ_TO_TIME_INVERT 209
+#define LGW_MBWSSF_FREQ_TO_TIME_DRIFT 210
+#define LGW_MBWSSF_PPM_CORRECTION 211
+#define LGW_MBWSSF_PAYLOAD_FINE_TIMING_GAIN 212
+#define LGW_MBWSSF_PREAMBLE_FINE_TIMING_GAIN 213
+#define LGW_MBWSSF_TRACKING_INTEGRAL 214
+#define LGW_MBWSSF_ZERO_PAD 215
+#define LGW_MBWSSF_MODEM_BW 216
+#define LGW_MBWSSF_RADIO_SELECT 217
+#define LGW_MBWSSF_RX_CHIRP_INVERT 218
+#define LGW_MBWSSF_LLR_SCALE 219
+#define LGW_MBWSSF_SNR_AVG_CST 220
+#define LGW_MBWSSF_PPM_OFFSET 221
+#define LGW_MBWSSF_RATE_SF 222
+#define LGW_MBWSSF_ONLY_CRC_EN 223
+#define LGW_MBWSSF_MAX_PAYLOAD_LEN 224
+#define LGW_TX_STATUS 225
+#define LGW_FSK_CH_BW_EXPO 226
+#define LGW_FSK_RSSI_LENGTH 227
+#define LGW_FSK_RX_INVERT 228
+#define LGW_FSK_PKT_MODE 229
+#define LGW_FSK_PSIZE 230
+#define LGW_FSK_CRC_EN 231
+#define LGW_FSK_DCFREE_ENC 232
+#define LGW_FSK_CRC_IBM 233
+#define LGW_FSK_ERROR_OSR_TOL 234
+#define LGW_FSK_RADIO_SELECT 235
+#define LGW_FSK_BR_RATIO 236
+#define LGW_FSK_REF_PATTERN_LSB 237
+#define LGW_FSK_REF_PATTERN_MSB 238
+#define LGW_FSK_PKT_LENGTH 239
+#define LGW_FSK_TX_GAUSSIAN_EN 240
+#define LGW_FSK_TX_GAUSSIAN_SELECT_BT 241
+#define LGW_FSK_TX_PATTERN_EN 242
+#define LGW_FSK_TX_PREAMBLE_SEQ 243
+#define LGW_FSK_TX_PSIZE 244
+#define LGW_FSK_NODE_ADRS 245
+#define LGW_FSK_BROADCAST 246
+#define LGW_FSK_AUTO_AFC_ON 247
+#define LGW_FSK_PATTERN_TIMEOUT_CFG 248
+#define LGW_SPI_RADIO_A__DATA 249
+#define LGW_SPI_RADIO_A__DATA_READBACK 250
+#define LGW_SPI_RADIO_A__ADDR 251
+#define LGW_SPI_RADIO_A__CS 252
+#define LGW_SPI_RADIO_B__DATA 253
+#define LGW_SPI_RADIO_B__DATA_READBACK 254
+#define LGW_SPI_RADIO_B__ADDR 255
+#define LGW_SPI_RADIO_B__CS 256
+#define LGW_RADIO_A_EN 257
+#define LGW_RADIO_B_EN 258
+#define LGW_RADIO_RST 259
+#define LGW_LNA_A_EN 260
+#define LGW_PA_A_EN 261
+#define LGW_LNA_B_EN 262
+#define LGW_PA_B_EN 263
+#define LGW_PA_GAIN 264
+#define LGW_LNA_A_CTRL_LUT 265
+#define LGW_PA_A_CTRL_LUT 266
+#define LGW_LNA_B_CTRL_LUT 267
+#define LGW_PA_B_CTRL_LUT 268
+#define LGW_CAPTURE_SOURCE 269
+#define LGW_CAPTURE_START 270
+#define LGW_CAPTURE_FORCE_TRIGGER 271
+#define LGW_CAPTURE_WRAP 272
+#define LGW_CAPTURE_PERIOD 273
+#define LGW_MODEM_STATUS 274
+#define LGW_VALID_HEADER_COUNTER_0 275
+#define LGW_VALID_PACKET_COUNTER_0 276
+#define LGW_VALID_HEADER_COUNTER_MBWSSF 277
+#define LGW_VALID_HEADER_COUNTER_FSK 278
+#define LGW_VALID_PACKET_COUNTER_MBWSSF 279
+#define LGW_VALID_PACKET_COUNTER_FSK 280
+#define LGW_CHANN_RSSI 281
+#define LGW_BB_RSSI 282
+#define LGW_DEC_RSSI 283
+#define LGW_DBG_MCU_DATA 284
+#define LGW_DBG_ARB_MCU_RAM_DATA 285
+#define LGW_DBG_AGC_MCU_RAM_DATA 286
+#define LGW_NEXT_PACKET_CNT 287
+#define LGW_ADDR_CAPTURE_COUNT 288
+#define LGW_TIMESTAMP 289
+#define LGW_DBG_CHANN0_GAIN 290
+#define LGW_DBG_CHANN1_GAIN 291
+#define LGW_DBG_CHANN2_GAIN 292
+#define LGW_DBG_CHANN3_GAIN 293
+#define LGW_DBG_CHANN4_GAIN 294
+#define LGW_DBG_CHANN5_GAIN 295
+#define LGW_DBG_CHANN6_GAIN 296
+#define LGW_DBG_CHANN7_GAIN 297
+#define LGW_DBG_DEC_FILT_GAIN 298
+#define LGW_SPI_DATA_FIFO_PTR 299
+#define LGW_PACKET_DATA_FIFO_PTR 300
+#define LGW_DBG_ARB_MCU_RAM_ADDR 301
+#define LGW_DBG_AGC_MCU_RAM_ADDR 302
+#define LGW_SPI_MASTER_CHIP_SELECT_POLARITY 303
+#define LGW_SPI_MASTER_CPOL 304
+#define LGW_SPI_MASTER_CPHA 305
+#define LGW_SIG_GEN_ANALYSER_MUX_SEL 306
+#define LGW_SIG_GEN_EN 307
+#define LGW_SIG_ANALYSER_EN 308
+#define LGW_SIG_ANALYSER_AVG_LEN 309
+#define LGW_SIG_ANALYSER_PRECISION 310
+#define LGW_SIG_ANALYSER_VALID_OUT 311
+#define LGW_SIG_GEN_FREQ 312
+#define LGW_SIG_ANALYSER_FREQ 313
+#define LGW_SIG_ANALYSER_I_OUT 314
+#define LGW_SIG_ANALYSER_Q_OUT 315
+#define LGW_GPS_EN 316
+#define LGW_GPS_POL 317
+#define LGW_SW_TEST_REG1 318
+#define LGW_SW_TEST_REG2 319
+#define LGW_SW_TEST_REG3 320
+#define LGW_DATA_MNGT_STATUS 321
+#define LGW_DATA_MNGT_CPT_FRAME_ALLOCATED 322
+#define LGW_DATA_MNGT_CPT_FRAME_FINISHED 323
+#define LGW_DATA_MNGT_CPT_FRAME_READEN 324
+#define LGW_TX_TRIG_ALL 325
+
+#define LGW_TOTALREGS 326
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC FUNCTIONS PROTOTYPES ------------------------------------------ */
+
+/**
+@brief Connect LoRa concentrator by opening SPI link
+@param spi_only indicates if we only want to create the SPI connexion to the
+concentrator, or if we also want to reset it and configure the FPGA (if present)
+@param tx_notch_filter TX notch filter frequency to be set in the FPGA (only
+used with SX1301AP2 reference design).
+@return status of register operation (LGW_REG_SUCCESS/LGW_REG_ERROR)
+*/
+int lgw_connect(bool spi_only, uint32_t tx_notch_freq);
+
+/**
+@brief Disconnect LoRa concentrator by closing SPI link
+@return status of register operation (LGW_REG_SUCCESS/LGW_REG_ERROR)
+*/
+int lgw_disconnect(void);
+
+/**
+@brief Use the soft-reset register to put the concentrator in initial state
+@return status of register operation (LGW_REG_SUCCESS/LGW_REG_ERROR)
+*/
+int lgw_soft_reset(void);
+
+/**
+@brief Check if the registers are ok, send diagnostics to stdio/stderr/file
+@param f file descriptor to to which the check result will be written
+@return status of register operation (LGW_REG_SUCCESS/LGW_REG_ERROR)
+*/
+int lgw_reg_check(FILE *f);
+
+/**
+@brief LoRa concentrator register write
+@param register_id register number in the data structure describing registers
+@param reg_value signed value to write to the register (for u32, use cast)
+@return status of register operation (LGW_REG_SUCCESS/LGW_REG_ERROR)
+*/
+int lgw_reg_w(uint16_t register_id, int32_t reg_value);
+
+/**
+@brief LoRa concentrator register read
+@param register_id register number in the data structure describing registers
+@param reg_value pointer to a variable where to write register read value
+@return status of register operation (LGW_REG_SUCCESS/LGW_REG_ERROR)
+*/
+int lgw_reg_r(uint16_t register_id, int32_t *reg_value);
+
+/**
+@brief LoRa concentrator register burst write
+@param register_id register number in the data structure describing registers
+@param data pointer to byte array that will be sent to the LoRa concentrator
+@param size size of the transfer, in byte(s)
+@return status of register operation (LGW_REG_SUCCESS/LGW_REG_ERROR)
+*/
+int lgw_reg_wb(uint16_t register_id, uint8_t *data, uint16_t size);
+
+/**
+@brief LoRa concentrator register burst read
+@param register_id register number in the data structure describing registers
+@param data pointer to byte array that will be written from the LoRa concentrator
+@param size size of the transfer, in byte(s)
+@return status of register operation (LGW_REG_SUCCESS/LGW_REG_ERROR)
+*/
+int lgw_reg_rb(uint16_t register_id, uint8_t *data, uint16_t size);
+
+
+#endif
+
+/* --- EOF ------------------------------------------------------------------ */
diff --git a/libloragw/inc/loragw_spi.h b/libloragw/inc/loragw_spi.h
new file mode 100644
index 0000000..fef1f48
--- /dev/null
+++ b/libloragw/inc/loragw_spi.h
@@ -0,0 +1,105 @@
+/*
+ / _____) _ | |
+( (____ _____ ____ _| |_ _____ ____| |__
+ \____ \| ___ | (_ _) ___ |/ ___) _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+ (C)2013 Semtech-Cycleo
+
+Description:
+ Host specific functions to address the LoRa concentrator registers through a
+ SPI interface.
+ Single-byte read/write and burst read/write.
+ Does not handle pagination.
+ Could be used with multiple SPI ports in parallel (explicit file descriptor)
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+Maintainer: Sylvain Miermont
+*/
+
+
+#ifndef _LORAGW_SPI_H
+#define _LORAGW_SPI_H
+
+/* -------------------------------------------------------------------------- */
+/* --- DEPENDANCIES --------------------------------------------------------- */
+
+#include <stdint.h> /* C99 types*/
+
+#include "config.h" /* library configuration options (dynamically generated) */
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC CONSTANTS ----------------------------------------------------- */
+
+#define LGW_SPI_SUCCESS 0
+#define LGW_SPI_ERROR -1
+#define LGW_BURST_CHUNK 1024
+
+#define LGW_SPI_MUX_MODE0 0x0 /* No FPGA */
+#define LGW_SPI_MUX_MODE1 0x1 /* FPGA, with spi mux header */
+
+#define LGW_SPI_MUX_TARGET_SX1301 0x0
+#define LGW_SPI_MUX_TARGET_FPGA 0x1
+#define LGW_SPI_MUX_TARGET_EEPROM 0x2
+#define LGW_SPI_MUX_TARGET_SX127X 0x3
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC FUNCTIONS PROTOTYPES ------------------------------------------ */
+
+/**
+@brief LoRa concentrator SPI setup (configure I/O and peripherals)
+@param spi_target_ptr pointer on a generic pointer to SPI target (implementation dependant)
+@return status of register operation (LGW_SPI_SUCCESS/LGW_SPI_ERROR)
+*/
+
+int lgw_spi_open(void **spi_target_ptr);
+
+/**
+@brief LoRa concentrator SPI close
+@param spi_target generic pointer to SPI target (implementation dependant)
+@return status of register operation (LGW_SPI_SUCCESS/LGW_SPI_ERROR)
+*/
+
+int lgw_spi_close(void *spi_target);
+
+/**
+@brief LoRa concentrator SPI single-byte write
+@param spi_target generic pointer to SPI target (implementation dependant)
+@param address 7-bit register address
+@param data data byte to write
+@return status of register operation (LGW_SPI_SUCCESS/LGW_SPI_ERROR)
+*/
+int lgw_spi_w(void *spi_target, uint8_t spi_mux_mode, uint8_t spi_mux_target, uint8_t address, uint8_t data);
+
+/**
+@brief LoRa concentrator SPI single-byte read
+@param spi_target generic pointer to SPI target (implementation dependant)
+@param address 7-bit register address
+@param data data byte to write
+@return status of register operation (LGW_SPI_SUCCESS/LGW_SPI_ERROR)
+*/
+int lgw_spi_r(void *spi_target, uint8_t spi_mux_mode, uint8_t spi_mux_target, uint8_t address, uint8_t *data);
+
+/**
+@brief LoRa concentrator SPI burst (multiple-byte) write
+@param spi_target generic pointer to SPI target (implementation dependant)
+@param address 7-bit register address
+@param data pointer to byte array that will be sent to the LoRa concentrator
+@param size size of the transfer, in byte(s)
+@return status of register operation (LGW_SPI_SUCCESS/LGW_SPI_ERROR)
+*/
+int lgw_spi_wb(void *spi_target, uint8_t spi_mux_mode, uint8_t spi_mux_target, uint8_t address, uint8_t *data, uint16_t size);
+
+/**
+@brief LoRa concentrator SPI burst (multiple-byte) read
+@param spi_target generic pointer to SPI target (implementation dependant)
+@param address 7-bit register address
+@param data pointer to byte array that will be written from the LoRa concentrator
+@param size size of the transfer, in byte(s)
+@return status of register operation (LGW_SPI_SUCCESS/LGW_SPI_ERROR)
+*/
+int lgw_spi_rb(void *spi_target, uint8_t spi_mux_mode, uint8_t spi_mux_target, uint8_t address, uint8_t *data, uint16_t size);
+
+#endif
+
+/* --- EOF ------------------------------------------------------------------ */
diff --git a/libloragw/inc/loragw_sx125x.h b/libloragw/inc/loragw_sx125x.h
new file mode 100644
index 0000000..120ee68
--- /dev/null
+++ b/libloragw/inc/loragw_sx125x.h
@@ -0,0 +1,49 @@
+/*
+ / _____) _ | |
+( (____ _____ ____ _| |_ _____ ____| |__
+ \____ \| ___ | (_ _) ___ |/ ___) _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+ (C)2013 Semtech
+
+Description: SX125x radio registers and constant definitions
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+
+Maintainer: Michael Coracin
+*/
+#ifndef __SX125X_REGS_H__
+#define __SX125X_REGS_H__
+
+/*
+SX1257 frequency setting :
+F_register(24bit) = F_rf (Hz) / F_step(Hz)
+ = F_rf (Hz) * 2^19 / F_xtal(Hz)
+ = F_rf (Hz) * 2^19 / 32e6
+ = F_rf (Hz) * 256/15625
+
+SX1255 frequency setting :
+F_register(24bit) = F_rf (Hz) / F_step(Hz)
+ = F_rf (Hz) * 2^20 / F_xtal(Hz)
+ = F_rf (Hz) * 2^20 / 32e6
+ = F_rf (Hz) * 512/15625
+*/
+
+#define SX125x_TX_DAC_CLK_SEL 1 /* 0:int, 1:ext */
+#define SX125x_TX_DAC_GAIN 2 /* 3:0, 2:-3, 1:-6, 0:-9 dBFS (default 2) */
+#define SX125x_TX_MIX_GAIN 14 /* -38 + 2*TxMixGain dB (default 14) */
+#define SX125x_TX_PLL_BW 1 /* 0:75, 1:150, 2:225, 3:300 kHz (default 3) */
+#define SX125x_TX_ANA_BW 0 /* 17.5 / 2*(41-TxAnaBw) MHz (default 0) */
+#define SX125x_TX_DAC_BW 5 /* 24 + 8*TxDacBw Nb FIR taps (default 2) */
+#define SX125x_RX_LNA_GAIN 1 /* 1 to 6, 1 highest gain */
+#define SX125x_RX_BB_GAIN 12 /* 0 to 15 , 15 highest gain */
+#define SX125x_LNA_ZIN 1 /* 0:50, 1:200 Ohms (default 1) */
+#define SX125x_RX_ADC_BW 7 /* 0 to 7, 2:100<BW<200, 5:200<BW<400,7:400<BW kHz SSB (default 7) */
+#define SX125x_RX_ADC_TRIM 6 /* 0 to 7, 6 for 32MHz ref, 5 for 36MHz ref */
+#define SX125x_RX_BB_BW 0 /* 0:750, 1:500, 2:375; 3:250 kHz SSB (default 1, max 3) */
+#define SX125x_RX_PLL_BW 0 /* 0:75, 1:150, 2:225, 3:300 kHz (default 3, max 3) */
+#define SX125x_ADC_TEMP 0 /* ADC temperature measurement mode (default 0) */
+#define SX125x_XOSC_GM_STARTUP 13 /* (default 13) */
+#define SX125x_XOSC_DISABLE 2 /* Disable of Xtal Oscillator blocks bit0:regulator, bit1:core(gm), bit2:amplifier */
+
+#endif // __SX125X_REGS_H__
diff --git a/libloragw/inc/loragw_sx1272_fsk.h b/libloragw/inc/loragw_sx1272_fsk.h
new file mode 100644
index 0000000..c202bc4
--- /dev/null
+++ b/libloragw/inc/loragw_sx1272_fsk.h
@@ -0,0 +1,113 @@
+/*
+ / _____) _ | |
+( (____ _____ ____ _| |_ _____ ____| |__
+ \____ \| ___ | (_ _) ___ |/ ___) _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+ (C)2013 Semtech
+
+Description: SX1272 FSK modem registers
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+
+Maintainer: Michael Coracin
+*/
+#ifndef _LORAGW_SX1272_REGS_FSK_H
+#define _LORAGW_SX1272_REGS_FSK_H
+
+/*!
+ * ============================================================================
+ * SX1272 Internal registers Address
+ * ============================================================================
+ */
+#define SX1272_REG_FIFO 0x00
+// Common settings
+#define SX1272_REG_OPMODE 0x01
+#define SX1272_REG_BITRATEMSB 0x02
+#define SX1272_REG_BITRATELSB 0x03
+#define SX1272_REG_FDEVMSB 0x04
+#define SX1272_REG_FDEVLSB 0x05
+#define SX1272_REG_FRFMSB 0x06
+#define SX1272_REG_FRFMID 0x07
+#define SX1272_REG_FRFLSB 0x08
+// Tx settings
+#define SX1272_REG_PACONFIG 0x09
+#define SX1272_REG_PARAMP 0x0A
+#define SX1272_REG_OCP 0x0B
+// Rx settings
+#define SX1272_REG_LNA 0x0C
+#define SX1272_REG_RXCONFIG 0x0D
+#define SX1272_REG_RSSICONFIG 0x0E
+#define SX1272_REG_RSSICOLLISION 0x0F
+#define SX1272_REG_RSSITHRESH 0x10
+#define SX1272_REG_RSSIVALUE 0x11
+#define SX1272_REG_RXBW 0x12
+#define SX1272_REG_AFCBW 0x13
+#define SX1272_REG_OOKPEAK 0x14
+#define SX1272_REG_OOKFIX 0x15
+#define SX1272_REG_OOKAVG 0x16
+#define SX1272_REG_RES17 0x17
+#define SX1272_REG_RES18 0x18
+#define SX1272_REG_RES19 0x19
+#define SX1272_REG_AFCFEI 0x1A
+#define SX1272_REG_AFCMSB 0x1B
+#define SX1272_REG_AFCLSB 0x1C
+#define SX1272_REG_FEIMSB 0x1D
+#define SX1272_REG_FEILSB 0x1E
+#define SX1272_REG_PREAMBLEDETECT 0x1F
+#define SX1272_REG_RXTIMEOUT1 0x20
+#define SX1272_REG_RXTIMEOUT2 0x21
+#define SX1272_REG_RXTIMEOUT3 0x22
+#define SX1272_REG_RXDELAY 0x23
+// Oscillator settings
+#define SX1272_REG_OSC 0x24
+// Packet handler settings
+#define SX1272_REG_PREAMBLEMSB 0x25
+#define SX1272_REG_PREAMBLELSB 0x26
+#define SX1272_REG_SYNCCONFIG 0x27
+#define SX1272_REG_SYNCVALUE1 0x28
+#define SX1272_REG_SYNCVALUE2 0x29
+#define SX1272_REG_SYNCVALUE3 0x2A
+#define SX1272_REG_SYNCVALUE4 0x2B
+#define SX1272_REG_SYNCVALUE5 0x2C
+#define SX1272_REG_SYNCVALUE6 0x2D
+#define SX1272_REG_SYNCVALUE7 0x2E
+#define SX1272_REG_SYNCVALUE8 0x2F
+#define SX1272_REG_PACKETCONFIG1 0x30
+#define SX1272_REG_PACKETCONFIG2 0x31
+#define SX1272_REG_PAYLOADLENGTH 0x32
+#define SX1272_REG_NODEADRS 0x33
+#define SX1272_REG_BROADCASTADRS 0x34
+#define SX1272_REG_FIFOTHRESH 0x35
+// SM settings
+#define SX1272_REG_SEQCONFIG1 0x36
+#define SX1272_REG_SEQCONFIG2 0x37
+#define SX1272_REG_TIMERRESOL 0x38
+#define SX1272_REG_TIMER1COEF 0x39
+#define SX1272_REG_TIMER2COEF 0x3A
+// Service settings
+#define SX1272_REG_IMAGECAL 0x3B
+#define SX1272_REG_TEMP 0x3C
+#define SX1272_REG_LOWBAT 0x3D
+// Status
+#define SX1272_REG_IRQFLAGS1 0x3E
+#define SX1272_REG_IRQFLAGS2 0x3F
+// I/O settings
+#define SX1272_REG_DIOMAPPING1 0x40
+#define SX1272_REG_DIOMAPPING2 0x41
+// Version
+#define SX1272_REG_VERSION 0x42
+// Additional settings
+#define SX1272_REG_AGCREF 0x43
+#define SX1272_REG_AGCTHRESH1 0x44
+#define SX1272_REG_AGCTHRESH2 0x45
+#define SX1272_REG_AGCTHRESH3 0x46
+#define SX1272_REG_PLLHOP 0x4B
+#define SX1272_REG_TCXO 0x58
+#define SX1272_REG_PADAC 0x5A
+#define SX1272_REG_PLL 0x5C
+#define SX1272_REG_PLLLOWPN 0x5E
+#define SX1272_REG_FORMERTEMP 0x6C
+#define SX1272_REG_BITRATEFRAC 0x70
+
+#endif // _LORAGW_SX1272_REGS_FSK_H
diff --git a/libloragw/inc/loragw_sx1272_lora.h b/libloragw/inc/loragw_sx1272_lora.h
new file mode 100644
index 0000000..7f7a7a5
--- /dev/null
+++ b/libloragw/inc/loragw_sx1272_lora.h
@@ -0,0 +1,89 @@
+/*
+ / _____) _ | |
+( (____ _____ ____ _| |_ _____ ____| |__
+ \____ \| ___ | (_ _) ___ |/ ___) _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+ (C)2013 Semtech
+
+Description: SX1272 LoRa modem registers and bits definitions
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+
+Maintainer: Michael Coracin
+*/
+#ifndef _LORAGW_SX1272_REGS_LORA_H
+#define _LORAGW_SX1272_REGS_LORA_H
+
+/*!
+ * ============================================================================
+ * SX1272 Internal registers Address
+ * ============================================================================
+ */
+#define SX1272_REG_LR_FIFO 0x00
+// Common settings
+#define SX1272_REG_LR_OPMODE 0x01
+#define SX1272_REG_LR_FRFMSB 0x06
+#define SX1272_REG_LR_FRFMID 0x07
+#define SX1272_REG_LR_FRFLSB 0x08
+// Tx settings
+#define SX1272_REG_LR_PACONFIG 0x09
+#define SX1272_REG_LR_PARAMP 0x0A
+#define SX1272_REG_LR_OCP 0x0B
+// Rx settings
+#define SX1272_REG_LR_LNA 0x0C
+// LoRa registers
+#define SX1272_REG_LR_FIFOADDRPTR 0x0D
+#define SX1272_REG_LR_FIFOTXBASEADDR 0x0E
+#define SX1272_REG_LR_FIFORXBASEADDR 0x0F
+#define SX1272_REG_LR_FIFORXCURRENTADDR 0x10
+#define SX1272_REG_LR_IRQFLAGSMASK 0x11
+#define SX1272_REG_LR_IRQFLAGS 0x12
+#define SX1272_REG_LR_RXNBBYTES 0x13
+#define SX1272_REG_LR_RXHEADERCNTVALUEMSB 0x14
+#define SX1272_REG_LR_RXHEADERCNTVALUELSB 0x15
+#define SX1272_REG_LR_RXPACKETCNTVALUEMSB 0x16
+#define SX1272_REG_LR_RXPACKETCNTVALUELSB 0x17
+#define SX1272_REG_LR_MODEMSTAT 0x18
+#define SX1272_REG_LR_PKTSNRVALUE 0x19
+#define SX1272_REG_LR_PKTRSSIVALUE 0x1A
+#define SX1272_REG_LR_RSSIVALUE 0x1B
+#define SX1272_REG_LR_HOPCHANNEL 0x1C
+#define SX1272_REG_LR_MODEMCONFIG1 0x1D
+#define SX1272_REG_LR_MODEMCONFIG2 0x1E
+#define SX1272_REG_LR_SYMBTIMEOUTLSB 0x1F
+#define SX1272_REG_LR_PREAMBLEMSB 0x20
+#define SX1272_REG_LR_PREAMBLELSB 0x21
+#define SX1272_REG_LR_PAYLOADLENGTH 0x22
+#define SX1272_REG_LR_PAYLOADMAXLENGTH 0x23
+#define SX1272_REG_LR_HOPPERIOD 0x24
+#define SX1272_REG_LR_FIFORXBYTEADDR 0x25
+#define SX1272_REG_LR_FEIMSB 0x28
+#define SX1272_REG_LR_FEIMID 0x29
+#define SX1272_REG_LR_FEILSB 0x2A
+#define SX1272_REG_LR_RSSIWIDEBAND 0x2C
+#define SX1272_REG_LR_DETECTOPTIMIZE 0x31
+#define SX1272_REG_LR_INVERTIQ 0x33
+#define SX1272_REG_LR_DETECTIONTHRESHOLD 0x37
+#define SX1272_REG_LR_SYNCWORD 0x39
+#define SX1272_REG_LR_INVERTIQ2 0x3B
+
+// end of documented register in datasheet
+// I/O settings
+#define SX1272_REG_LR_DIOMAPPING1 0x40
+#define SX1272_REG_LR_DIOMAPPING2 0x41
+// Version
+#define SX1272_REG_LR_VERSION 0x42
+// Additional settings
+#define SX1272_REG_LR_AGCREF 0x43
+#define SX1272_REG_LR_AGCTHRESH1 0x44
+#define SX1272_REG_LR_AGCTHRESH2 0x45
+#define SX1272_REG_LR_AGCTHRESH3 0x46
+#define SX1272_REG_LR_PLLHOP 0x4B
+#define SX1272_REG_LR_TCXO 0x58
+#define SX1272_REG_LR_PADAC 0x5A
+#define SX1272_REG_LR_PLL 0x5C
+#define SX1272_REG_LR_PLLLOWPN 0x5E
+#define SX1272_REG_LR_FORMERTEMP 0x6C
+
+#endif // _LORAGW_SX1272_REGS_LORA_H
diff --git a/libloragw/inc/loragw_sx1276_fsk.h b/libloragw/inc/loragw_sx1276_fsk.h
new file mode 100644
index 0000000..944958a
--- /dev/null
+++ b/libloragw/inc/loragw_sx1276_fsk.h
@@ -0,0 +1,112 @@
+/*
+ / _____) _ | |
+( (____ _____ ____ _| |_ _____ ____| |__
+ \____ \| ___ | (_ _) ___ |/ ___) _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+ (C)2013 Semtech
+
+Description: SX1276 FSK modem registers
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+
+Maintainer: Michael Coracin
+*/
+#ifndef _LORAGW_SX1276_REGS_FSK_H
+#define _LORAGW_SX1276_REGS_FSK_H
+
+/*!
+ * ============================================================================
+ * SX1276 Internal registers Address
+ * ============================================================================
+ */
+#define SX1276_REG_FIFO 0x00
+// Common settings
+#define SX1276_REG_OPMODE 0x01
+#define SX1276_REG_BITRATEMSB 0x02
+#define SX1276_REG_BITRATELSB 0x03
+#define SX1276_REG_FDEVMSB 0x04
+#define SX1276_REG_FDEVLSB 0x05
+#define SX1276_REG_FRFMSB 0x06
+#define SX1276_REG_FRFMID 0x07
+#define SX1276_REG_FRFLSB 0x08
+// Tx settings
+#define SX1276_REG_PACONFIG 0x09
+#define SX1276_REG_PARAMP 0x0A
+#define SX1276_REG_OCP 0x0B
+// Rx settings
+#define SX1276_REG_LNA 0x0C
+#define SX1276_REG_RXCONFIG 0x0D
+#define SX1276_REG_RSSICONFIG 0x0E
+#define SX1276_REG_RSSICOLLISION 0x0F
+#define SX1276_REG_RSSITHRESH 0x10
+#define SX1276_REG_RSSIVALUE 0x11
+#define SX1276_REG_RXBW 0x12
+#define SX1276_REG_AFCBW 0x13
+#define SX1276_REG_OOKPEAK 0x14
+#define SX1276_REG_OOKFIX 0x15
+#define SX1276_REG_OOKAVG 0x16
+#define SX1276_REG_RES17 0x17
+#define SX1276_REG_RES18 0x18
+#define SX1276_REG_RES19 0x19
+#define SX1276_REG_AFCFEI 0x1A
+#define SX1276_REG_AFCMSB 0x1B
+#define SX1276_REG_AFCLSB 0x1C
+#define SX1276_REG_FEIMSB 0x1D
+#define SX1276_REG_FEILSB 0x1E
+#define SX1276_REG_PREAMBLEDETECT 0x1F
+#define SX1276_REG_RXTIMEOUT1 0x20
+#define SX1276_REG_RXTIMEOUT2 0x21
+#define SX1276_REG_RXTIMEOUT3 0x22
+#define SX1276_REG_RXDELAY 0x23
+// Oscillator settings
+#define SX1276_REG_OSC 0x24
+// Packet handler settings
+#define SX1276_REG_PREAMBLEMSB 0x25
+#define SX1276_REG_PREAMBLELSB 0x26
+#define SX1276_REG_SYNCCONFIG 0x27
+#define SX1276_REG_SYNCVALUE1 0x28
+#define SX1276_REG_SYNCVALUE2 0x29
+#define SX1276_REG_SYNCVALUE3 0x2A
+#define SX1276_REG_SYNCVALUE4 0x2B
+#define SX1276_REG_SYNCVALUE5 0x2C
+#define SX1276_REG_SYNCVALUE6 0x2D
+#define SX1276_REG_SYNCVALUE7 0x2E
+#define SX1276_REG_SYNCVALUE8 0x2F
+#define SX1276_REG_PACKETCONFIG1 0x30
+#define SX1276_REG_PACKETCONFIG2 0x31
+#define SX1276_REG_PAYLOADLENGTH 0x32
+#define SX1276_REG_NODEADRS 0x33
+#define SX1276_REG_BROADCASTADRS 0x34
+#define SX1276_REG_FIFOTHRESH 0x35
+// SM settings
+#define SX1276_REG_SEQCONFIG1 0x36
+#define SX1276_REG_SEQCONFIG2 0x37
+#define SX1276_REG_TIMERRESOL 0x38
+#define SX1276_REG_TIMER1COEF 0x39
+#define SX1276_REG_TIMER2COEF 0x3A
+// Service settings
+#define SX1276_REG_IMAGECAL 0x3B
+#define SX1276_REG_TEMP 0x3C
+#define SX1276_REG_LOWBAT 0x3D
+// Status
+#define SX1276_REG_IRQFLAGS1 0x3E
+#define SX1276_REG_IRQFLAGS2 0x3F
+// I/O settings
+#define SX1276_REG_DIOMAPPING1 0x40
+#define SX1276_REG_DIOMAPPING2 0x41
+// Version
+#define SX1276_REG_VERSION 0x42
+// Additional settings
+#define SX1276_REG_PLLHOP 0x44
+#define SX1276_REG_TCXO 0x4B
+#define SX1276_REG_PADAC 0x4D
+#define SX1276_REG_FORMERTEMP 0x5B
+#define SX1276_REG_BITRATEFRAC 0x5D
+#define SX1276_REG_AGCREF 0x61
+#define SX1276_REG_AGCTHRESH1 0x62
+#define SX1276_REG_AGCTHRESH2 0x63
+#define SX1276_REG_AGCTHRESH3 0x64
+#define SX1276_REG_PLL 0x70
+
+#endif // __SX1276_REGS_FSK_H__
diff --git a/libloragw/inc/loragw_sx1276_lora.h b/libloragw/inc/loragw_sx1276_lora.h
new file mode 100644
index 0000000..d03e1ff
--- /dev/null
+++ b/libloragw/inc/loragw_sx1276_lora.h
@@ -0,0 +1,94 @@
+/*
+ / _____) _ | |
+( (____ _____ ____ _| |_ _____ ____| |__
+ \____ \| ___ | (_ _) ___ |/ ___) _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+ (C)2013 Semtech
+
+Description: SX1276 LoRa modem registers
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+
+Maintainer: Michael Coracin
+*/
+#ifndef _LORAGW_SX1276_REGS_LORA_H
+#define _LORAGW_SX1276_REGS_LORA_H
+
+/*!
+ * ============================================================================
+ * SX1276 Internal registers Address
+ * ============================================================================
+ */
+#define SX1276_REG_LR_FIFO 0x00
+// Common settings
+#define SX1276_REG_LR_OPMODE 0x01
+#define SX1276_REG_LR_FRFMSB 0x06
+#define SX1276_REG_LR_FRFMID 0x07
+#define SX1276_REG_LR_FRFLSB 0x08
+// Tx settings
+#define SX1276_REG_LR_PACONFIG 0x09
+#define SX1276_REG_LR_PARAMP 0x0A
+#define SX1276_REG_LR_OCP 0x0B
+// Rx settings
+#define SX1276_REG_LR_LNA 0x0C
+// LoRa registers
+#define SX1276_REG_LR_FIFOADDRPTR 0x0D
+#define SX1276_REG_LR_FIFOTXBASEADDR 0x0E
+#define SX1276_REG_LR_FIFORXBASEADDR 0x0F
+#define SX1276_REG_LR_FIFORXCURRENTADDR 0x10
+#define SX1276_REG_LR_IRQFLAGSMASK 0x11
+#define SX1276_REG_LR_IRQFLAGS 0x12
+#define SX1276_REG_LR_RXNBBYTES 0x13
+#define SX1276_REG_LR_RXHEADERCNTVALUEMSB 0x14
+#define SX1276_REG_LR_RXHEADERCNTVALUELSB 0x15
+#define SX1276_REG_LR_RXPACKETCNTVALUEMSB 0x16
+#define SX1276_REG_LR_RXPACKETCNTVALUELSB 0x17
+#define SX1276_REG_LR_MODEMSTAT 0x18
+#define SX1276_REG_LR_PKTSNRVALUE 0x19
+#define SX1276_REG_LR_PKTRSSIVALUE 0x1A
+#define SX1276_REG_LR_RSSIVALUE 0x1B
+#define SX1276_REG_LR_HOPCHANNEL 0x1C
+#define SX1276_REG_LR_MODEMCONFIG1 0x1D
+#define SX1276_REG_LR_MODEMCONFIG2 0x1E
+#define SX1276_REG_LR_SYMBTIMEOUTLSB 0x1F
+#define SX1276_REG_LR_PREAMBLEMSB 0x20
+#define SX1276_REG_LR_PREAMBLELSB 0x21
+#define SX1276_REG_LR_PAYLOADLENGTH 0x22
+#define SX1276_REG_LR_PAYLOADMAXLENGTH 0x23
+#define SX1276_REG_LR_HOPPERIOD 0x24
+#define SX1276_REG_LR_FIFORXBYTEADDR 0x25
+#define SX1276_REG_LR_MODEMCONFIG3 0x26
+#define SX1276_REG_LR_FEIMSB 0x28
+#define SX1276_REG_LR_FEIMID 0x29
+#define SX1276_REG_LR_FEILSB 0x2A
+#define SX1276_REG_LR_RSSIWIDEBAND 0x2C
+#define SX1276_REG_LR_TEST2F 0x2F
+#define SX1276_REG_LR_TEST30 0x30
+#define SX1276_REG_LR_DETECTOPTIMIZE 0x31
+#define SX1276_REG_LR_INVERTIQ 0x33
+#define SX1276_REG_LR_TEST36 0x36
+#define SX1276_REG_LR_DETECTIONTHRESHOLD 0x37
+#define SX1276_REG_LR_SYNCWORD 0x39
+#define SX1276_REG_LR_TEST3A 0x3A
+#define SX1276_REG_LR_INVERTIQ2 0x3B
+
+// end of documented register in datasheet
+// I/O settings
+#define SX1276_REG_LR_DIOMAPPING1 0x40
+#define SX1276_REG_LR_DIOMAPPING2 0x41
+// Version
+#define SX1276_REG_LR_VERSION 0x42
+// Additional settings
+#define SX1276_REG_LR_PLLHOP 0x44
+#define SX1276_REG_LR_TCXO 0x4B
+#define SX1276_REG_LR_PADAC 0x4D
+#define SX1276_REG_LR_FORMERTEMP 0x5B
+#define SX1276_REG_LR_BITRATEFRAC 0x5D
+#define SX1276_REG_LR_AGCREF 0x61
+#define SX1276_REG_LR_AGCTHRESH1 0x62
+#define SX1276_REG_LR_AGCTHRESH2 0x63
+#define SX1276_REG_LR_AGCTHRESH3 0x64
+#define SX1276_REG_LR_PLL 0x70
+
+#endif // _LORAGW_SX1276_REGS_LORA_H
diff --git a/libloragw/library.cfg b/libloragw/library.cfg
new file mode 100644
index 0000000..f962ba2
--- /dev/null
+++ b/libloragw/library.cfg
@@ -0,0 +1,12 @@
+# That file will be included in the Makefile files that have hardware dependencies
+
+### Debug options ###
+# Set the DEBUG_* to 1 to activate debug mode in individual modules.
+# Warning: that makes the module *very verbose*, do not use for production
+
+DEBUG_AUX= 0
+DEBUG_SPI= 0
+DEBUG_REG= 0
+DEBUG_HAL= 0
+DEBUG_LBT= 0
+DEBUG_GPS= 0
diff --git a/libloragw/readme.md b/libloragw/readme.md
new file mode 100644
index 0000000..bdbf97f
--- /dev/null
+++ b/libloragw/readme.md
@@ -0,0 +1,457 @@
+ / _____) _ | |
+ ( (____ _____ ____ _| |_ _____ ____| |__
+ \____ \| ___ | (_ _) ___ |/ ___) _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+ (______/|_____)_|_|_| \__)_____)\____)_| |_|
+ (C)2013 Semtech-Cycleo
+
+LoRa concentrator HAL user manual
+============================
+
+1. Introduction
+---------------
+
+The LoRa concentrator Hardware Abstraction Layer is a C library that allow you
+to use a Semtech concentrator chip through a reduced number of high level C
+functions to configure the hardware, send and receive packets.
+
+The Semtech LoRa concentrator is a digital multi-channel multi-standard packet
+radio used to send and receive packets wirelessly using LoRa or FSK modulations.
+
+2. Components of the library
+----------------------------
+
+The library is composed of 6(8) modules:
+
+* loragw_hal
+* loragw_reg
+* loragw_spi
+* loragw_aux
+* loragw_gps
+* loragw_radio
+* loragw_fpga (only for SX1301AP2 ref design)
+* loragw_lbt (only for SX1301AP2 ref design)
+
+The library also contains basic test programs to demonstrate code use and check
+functionality.
+
+### 2.1. loragw_hal ###
+
+This is the main module and contains the high level functions to configure and
+use the LoRa concentrator:
+
+* lgw_board_setconf, to set the configuration of the concentrator
+* lgw_rxrf_setconf, to set the configuration of the radio channels
+* lgw_rxif_setconf, to set the configuration of the IF+modem channels
+* lgw_txgain_setconf, to set the configuration of the concentrator gain table
+* lgw_start, to apply the set configuration to the hardware and start it
+* lgw_stop, to stop the hardware
+* lgw_receive, to fetch packets if any was received
+* lgw_send, to send a single packet (non-blocking, see warning in usage section)
+* lgw_status, to check when a packet has effectively been sent
+
+For an standard application, include only this module.
+The use of this module is detailed on the usage section.
+
+/!\ When sending a packet, there is a delay (approx 1.5ms) for the analog
+circuitry to start and be stable. This delay is adjusted by the HAL depending
+on the board version (lgw_i_tx_start_delay_us).
+
+In 'timestamp' mode, this is transparent: the modem is started
+lgw_i_tx_start_delay_us microseconds before the user-set timestamp value is
+reached, the preamble of the packet start right when the internal timestamp
+counter reach target value.
+
+In 'immediate' mode, the packet is emitted as soon as possible: transferring the
+packet (and its parameters) from the host to the concentrator takes some time,
+then there is the lgw_i_tx_start_delay_us, then the packet is emitted.
+
+In 'triggered' mode (aka PPS/GPS mode), the packet, typically a beacon, is
+emitted lgw_i_tx_start_delay_us microsenconds after a rising edge of the
+trigger signal. Because there is no way to anticipate the triggering event and
+start the analog circuitry beforehand, that delay must be taken into account in
+the protocol.
+
+### 2.2. loragw_reg ###
+
+This module is used to access to the LoRa concentrator registers by name instead
+of by address:
+
+* lgw_connect, to initialise and check the connection with the hardware
+* lgw_disconnect, to disconnect the hardware
+* lgw_soft_reset, to reset the whole hardware by resetting the register array
+* lgw_reg_check, to check all registers vs. their default value and output the
+result to a file
+* lgw_reg_r, read a named register
+* lgw_reg_w, write a named register
+* lgw_reg_rb, read a name register in burst
+* lgw_reg_wb, write a named register in burst
+
+This module handles pagination, read-only registers protection, multi-byte
+registers management, signed registers management, read-modify-write routines
+for sub-byte registers and read/write burst fragmentation to respect SPI
+maximum burst length constraints.
+
+It make the code much easier to read and to debug.
+Moreover, if registers are relocated between different hardware revisions but
+keep the same function, the code written using register names can be reused "as
+is".
+
+If you need access to all the registers, include this module in your
+application.
+
+**/!\ Warning** please be sure to have a good understanding of the LoRa
+concentrator inner working before accessing the internal registers directly.
+
+### 2.3. loragw_spi ###
+
+This module contains the functions to access the LoRa concentrator register
+array through the SPI interface:
+
+* lgw_spi_r to read one byte
+* lgw_spi_w to write one byte
+* lgw_spi_rb to read two bytes or more
+* lgw_spi_wb to write two bytes or more
+
+Please *do not* include that module directly into your application.
+
+**/!\ Warning** Accessing the LoRa concentrator register array without the
+checks and safety provided by the functions in loragw_reg is not recommended.
+
+### 2.4. loragw_aux ###
+
+This module contains a single host-dependant function wait_ms to pause for a
+defined amount of milliseconds.
+
+The procedure to start and configure the LoRa concentrator hardware contained in
+the loragw_hal module requires to wait for several milliseconds at certain
+steps, typically to allow for supply voltages or clocks to stabilize after been
+switched on.
+
+An accuracy of 1 ms or less is ideal.
+If your system does not allow that level of accuracy, make sure that the actual
+delay is *longer* that the time specified when the function is called (ie.
+wait_ms(X) **MUST NOT** before X milliseconds under any circumstance).
+
+If the minimum delays are not guaranteed during the configuration and start
+procedure, the hardware might not work at nominal performance.
+Most likely, it will not work at all.
+
+### 2.5. loragw_gps ###
+
+This module contains functions to synchronize the concentrator internal
+counter with an absolute time reference, in our case a GPS satellite receiver.
+
+The internal concentrator counter is used to timestamp incoming packets and to
+triggers outgoing packets with a microsecond accuracy.
+In some cases, it might be useful to be able to transform that internal
+timestamp (that is independent for each concentrator running in a typical
+networked system) into an absolute GPS time.
+
+In a typical implementation a GPS specific thread will be called, doing the
+following things after opening the serial port:
+
+* blocking reads on the serial port (using system read() function)
+* parse UBX messages (using lgw_parse_ubx) to get actual native GPS time
+* parse NMEA sentences (using lgw_parse_nmea) to get location and UTC time
+Note: the RMC sentence gives UTC time, not native GPS time.
+
+And each time an NAV-TIMEGPS UBX message has been received:
+
+* get the concentrator timestamp (using lgw_get_trigcnt, mutex needed to
+ protect access to the concentrator)
+* get the GPS time contained in the UBX message (using lgw_gps_get)
+* call the lgw_gps_sync function (use mutex to protect the time reference that
+ should be a global shared variable).
+
+Then, in other threads, you can simply used that continuously adjusted time
+reference to convert internal timestamps to GPS time (using lgw_cnt2gps) or
+the other way around (using lgw_gps2cnt). Inernal concentrator timestamp can
+also be converted to/from UTC time using lgw_cnt2utc/lgw_utc2cnt functions.
+
+### 2.6. loragw_radio ###
+
+This module contains functions to handle the configuration of SX125x and
+SX127x radios.
+
+### 2.7. loragw_fpga ###
+
+This module contains the description of the FPGA registers, the functions to
+read/write those registers, and a function to configure the FPGA features.
+
+This module is only required for SX1301AP2 reference design.
+
+### 2.8. loragw_lbt ###
+
+This module contains functions to configure and use the "Listen-Before-Talk"
+feature (refered as LBT below). It depends on the loragw_fpga and loragw_radio
+modules.
+
+LBT feature is only available on SX1301AP2 reference design, which provides the
+FPGA and the SX127x radio required to accomplish the feature.
+
+The FPGA implements the following Finite State Machine (FSM) to scan the defined
+LBT channels (8 max), and also compute the RSSI histogram for spectral scan,
+using the SX127x radio.
+
+
+ +-------+
+ +------------------>+ idle +------------------+
+ | +-------+ v
+ | | +-----------+
+ | | | clean mem |
+ | v +-----------+
+ | +----------+ |
+ | | set freq |<---------------+
+ | +----------+
+ | |
+ | v
+ | +----------+
+ | | wait pll |
+ | | lock |
+ | +----------+
+ | | (SCAN_CHANNEL)
+ | v +-----------+
+ | +-----------+ | |
+ | | +----------+ v
+ | +-->| read RSSI | +------------+
+ | | | +<---------------+ calc histo |
+ | | +-----------+ SCANNING +------------+
+ | | | |
+ | SCANNING | | (LBT_CHANNEL) |
+ | | v |
+ | | +-------------+ |
+ | | | compare | |
+ | +--+ with | |
+ | | RSSI_TARGET | HISTO_DONE |
+ | +-------------+ |
+ | | |
+ | SCAN DONE | |
+ | v |
+ | +------------+ |
+ | | increase | |
+ +-----------------+ +<--------------------+
+ | freq |
+ +------------+
+
+
+
+In order to configure the LBT, the following parameters have to be set:
+- RSSI_TARGET: signal strength target used to detect if the channel is clear
+ or not.
+ RSSI_TARGET_dBm = -RSSI_TARGET/2
+- LBT_CHx_FREQ_OFFSET: with x=[0..7], offset from the predefined LBT start
+ frequency (863MHz or 915MHz depending on FPGA image),
+ in 100KHz unit.
+- LBT_SCAN_TIME_CHx: with x=[0..7], the channel scan time to be used for this
+ LBT channel: 128µs or 5000µs
+
+With this FSM, the FPGA keeps the last instant when each channel was free during
+more than LBT_SCAN_TIME_CHx µs.
+
+Then, the HAL, when receiving a downlink request, will first determine on which
+LBT channel this downlink is supposed to be sent and then checks if the channel
+is busy or if downlink is allowed.
+
+In order to determine if a downlink is allowed or not, the HAL does:
+- read the LBT_TIMESTAMP_CH of the channel on which downlink is requested. This
+ gives the last time when channel was free (LBT_TIME).
+- compute the time on air of the downlink packet to determine the end time of
+ the packet emission (PKT_END_TIME).
+- if ((PKT_END_TIME - LBT_TIME) < TX_MAX_TIME)
+ ALLOWED = TRUE
+ else
+ ALLOWED = FALSE
+ endif
+ where TX_MAX_TIME is the maximum time allowed to send a packet since the
+ last channel free time (this depends on the channel scan time ).
+
+
+3. Software build process
+--------------------------
+
+### 3.1. Details of the software ###
+
+The library is written following ANSI C conventions but using C99 explicit
+length data type for all data exchanges with hardware and for parameters.
+
+The loragw_aux module contains POSIX dependant functions for millisecond
+accuracy pause.
+For embedded platforms, the function could be rewritten using hardware timers.
+
+### 3.2. Building options ###
+
+All modules use a fprintf(stderr,...) function to display debug diagnostic
+messages if the DEBUG_xxx is set to 1 in library.cfg
+
+### 3.3. Building procedures ###
+
+For cross-compilation set the ARCH and CROSS_COMPILE variables in the Makefile,
+or in your shell environment, with the correct toolchain name and path.
+ex:
+export PATH=/home/foo/rpi-toolchain/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin:$PATH
+export ARCH=arm
+export CROSS_COMPILE=arm-linux-gnueabihf-
+
+The Makefile in the libloragw directory will parse the library.cfg file and
+generate a config.h C header file containing #define options.
+Those options enables and disables sections of code in the loragw_xxx.h files
+and the *.c source files.
+
+The library.cfg is also used directly to select the proper set of dynamic
+libraries to be linked with.
+
+### 3.4. Export ###
+
+Once build, to use that library on another system, you need to export the
+following files :
+
+* libloragw/library.cfg -> root configuration file
+* libloragw/libloragw.a -> static library, to be linked with a program
+* libloragw/readme.md -> required for license compliance
+* libloragw/inc/config.h -> C configuration flags, derived from library.cfg
+* libloragw/inc/loragw_*.h -> take only the ones you need (eg. _hal and _gps)
+
+After statically linking the library to your application, only the license
+is required to be kept or copied inside your program documentation.
+
+4. Hardware dependencies
+------------------------
+
+### 4.1. Hardware revision ###
+
+The loragw_reg and loragw_hal are written for a specific version on the Semtech
+hardware (IP and/or silicon revision).
+
+This code has been written for:
+
+* Semtech SX1301 chip
+* Semtech SX1257 or SX1255 I/Q transceivers
+
+The library will not work if there is a mismatch between the hardware version
+and the library version. You can use the test program test_loragw_reg to check
+if the hardware registers match their software declaration.
+
+### 4.2. SPI communication ###
+
+loragw_spi contains 4 SPI functions (read, write, burst read, burst write) that
+are platform-dependant.
+The functions must be rewritten depending on the SPI bridge you use:
+
+* SPI master matched to the Linux SPI device driver (provided)
+* SPI over USB using FTDI components (not provided)
+* native SPI using a microcontroller peripheral (not provided)
+
+You can use the test program test_loragw_spi to check with a logic analyser
+that the SPI communication is working
+
+### 4.3. GPS receiver (or other GNSS system) ###
+
+To use the GPS module of the library, the host must be connected to a GPS
+receiver via a serial link (or an equivalent receiver using a different
+satellite constellation).
+The serial link must appear as a "tty" device in the /dev/ directory, and the
+user launching the program must have the proper system rights to read and
+write on that device.
+Use `chmod a+rw` to allow all users to access that specific tty device, or use
+sudo to run all your programs (eg. `sudo ./test_loragw_gps`).
+
+In the current revision, the library only reads data from the serial port,
+expecting to receive NMEA frames that are generally sent by GPS receivers as
+soon as they are powered up, and UBX messages which are proprietary to u-blox
+modules.
+
+The GPS receiver **MUST** send UBX messages shortly after sending a PPS pulse
+on to allow internal concentrator timestamps to be converted to absolute GPS time.
+If the GPS receiver sends a GGA NMEA sentence, the gateway 3D position will
+also be available.
+
+5. Usage
+--------
+
+### 5.1. Setting the software environment ###
+
+For a typical application you need to:
+
+* include loragw_hal.h in your program source
+* link to the libloragw.a static library during compilation
+* link to the librt library due to loragw_aux dependencies (timing functions)
+
+For an application that will also access the concentrator configuration
+registers directly (eg. for advanced configuration) you also need to:
+
+* include loragw_reg.h in your program source
+
+### 5.2. Using the software API ###
+
+To use the HAL in your application, you must follow some basic rules:
+
+* configure the radios path and IF+modem path before starting the radio
+* the configuration is only transferred to hardware when you call the *start*
+ function
+* you cannot receive packets until one (or +) radio is enabled AND one (or +)
+ IF+modem part is enabled AND the concentrator is started
+* you cannot send packets until one (or +) radio is enabled AND the concentrator
+ is started
+* you must stop the concentrator before changing the configuration
+
+A typical application flow for using the HAL is the following:
+
+ <configure the radios and IF+modems>
+ <start the LoRa concentrator>
+ loop {
+ <fetch packets that were received by the concentrator>
+ <process, store and/or forward received packets>
+ <send packets through the concentrator>
+ }
+ <stop the concentrator>
+
+**/!\ Warning** The lgw_send function is non-blocking and returns while the
+LoRa concentrator is still sending the packet, or even before the packet has
+started to be transmitted if the packet is triggered on a future event.
+While a packet is emitted, no packet can be received (limitation intrinsic to
+most radio frequency systems).
+
+Your application *must* take into account the time it takes to send a packet or
+check the status (using lgw_status) before attempting to send another packet.
+
+Trying to send a packet while the previous packet has not finished being send
+will result in the previous packet not being sent or being sent only partially
+(resulting in a CRC error in the receiver).
+
+### 5.3. Debugging mode ###
+
+To debug your application, it might help to compile the loragw_hal function
+with the debug messages activated (set DEBUG_HAL=1 in library.cfg).
+It then send a lot of details, including detailed error messages to *stderr*.
+
+6. License
+-----------
+
+Copyright (c) 2013, SEMTECH S.A.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+* Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+* Neither the name of the Semtech corporation nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL SEMTECH S.A. BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*EOF*
diff --git a/libloragw/src/agc_fw.var b/libloragw/src/agc_fw.var
new file mode 100644
index 0000000..5083a0e
--- /dev/null
+++ b/libloragw/src/agc_fw.var
@@ -0,0 +1,529 @@
+/*
+ / _____) _ | |
+( (____ _____ ____ _| |_ _____ ____| |__
+ \____ \| ___ | (_ _) ___ |/ ___) _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+ (C)2013 Semtech-Cycleo
+
+Description:
+ AGC firmware
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+Maintainer: Matthieu Leurent
+*/
+
+static uint8_t agc_firmware[MCU_AGC_FW_BYTE] = {
+0x8A, 0x51, 0x11, 0x28, 0xFF, 0xBF, 0xFF, 0xBF, 0x80, 0x40, 0x03, 0x4E, 0x83, 0x52, 0x03, 0x53,
+0xAC, 0x00, 0x04, 0x88, 0xAD, 0x40, 0x0A, 0xC8, 0xAE, 0x40, 0x01, 0x88, 0xAF, 0x80, 0x8A, 0x51,
+0x13, 0x68, 0x8A, 0x51, 0x59, 0x2D, 0x8B, 0xDC, 0x1A, 0x68, 0xA0, 0xE0, 0x8A, 0x51, 0x27, 0x60,
+0x40, 0xF0, 0x9B, 0x40, 0x10, 0xF0, 0x8B, 0x00, 0x2F, 0x88, 0x81, 0x80, 0x2E, 0x48, 0x8A, 0xC0,
+0x2D, 0x48, 0x84, 0x80, 0x2C, 0x8E, 0x83, 0xC0, 0x80, 0x0E, 0x00, 0xCE, 0x09, 0x80, 0x95, 0x41,
+0x96, 0x41, 0x97, 0x81, 0x98, 0x01, 0x99, 0x41, 0x9A, 0x41, 0x9B, 0x81, 0x9C, 0x41, 0x9E, 0x81,
+0x19, 0x54, 0x19, 0x95, 0x18, 0x56, 0x8B, 0x41, 0xD4, 0x41, 0x02, 0xF0, 0x54, 0x02, 0x03, 0x18,
+0x59, 0xA8, 0x54, 0x08, 0x51, 0x3E, 0x84, 0x80, 0x83, 0x93, 0x80, 0x81, 0x54, 0x08, 0x5D, 0xBE,
+0x84, 0x80, 0x07, 0x70, 0x80, 0x40, 0x54, 0x08, 0x72, 0x60, 0x8A, 0x51, 0x54, 0x08, 0x5D, 0xBE,
+0x84, 0x80, 0x00, 0xCE, 0xF0, 0x39, 0x96, 0x00, 0x54, 0x9C, 0x52, 0x68, 0x83, 0x52, 0x03, 0x53,
+0x18, 0x14, 0x55, 0xA8, 0x83, 0x52, 0x03, 0x53, 0x18, 0xD0, 0x18, 0x55, 0x18, 0x11, 0xD4, 0x8A,
+0x35, 0xA8, 0xD3, 0x81, 0x08, 0xF0, 0x53, 0x42, 0x03, 0x18, 0x6F, 0x28, 0x53, 0x48, 0x55, 0x7E,
+0x84, 0x80, 0x04, 0xF0, 0x83, 0x93, 0x80, 0x40, 0x53, 0x48, 0x55, 0x7E, 0x84, 0x80, 0x00, 0x48,
+0x96, 0x00, 0x53, 0x48, 0x95, 0x00, 0x98, 0x54, 0x98, 0x10, 0xD3, 0xCA, 0x5A, 0xA8, 0x10, 0xF0,
+0x9B, 0x40, 0x08, 0x40, 0xAB, 0x40, 0x51, 0x3E, 0x84, 0x80, 0x00, 0x48, 0xAA, 0x00, 0x23, 0x3E,
+0x84, 0x80, 0x8A, 0x51, 0x1D, 0xE5, 0x8A, 0x51, 0xA7, 0x40, 0x05, 0x30, 0x03, 0xD0, 0xA7, 0x0D,
+0xFF, 0x7E, 0x03, 0x9D, 0x7E, 0x28, 0x2A, 0x08, 0x2D, 0x7E, 0x84, 0x80, 0x8A, 0x51, 0x1D, 0xE5,
+0x8A, 0x51, 0xA8, 0xC0, 0x28, 0x47, 0x27, 0x44, 0x01, 0x38, 0xA9, 0x00, 0x2B, 0x48, 0x22, 0xFE,
+0x84, 0x80, 0x29, 0x08, 0x80, 0x40, 0x2B, 0x48, 0x22, 0xFE, 0x84, 0x80, 0x00, 0x48, 0x83, 0x96,
+0xA0, 0x80, 0x83, 0x52, 0x2B, 0x48, 0x83, 0x96, 0xA1, 0xC0, 0x0C, 0x30, 0xD3, 0xE1, 0x08, 0x40,
+0x18, 0x12, 0x80, 0xF0, 0x9B, 0x40, 0x10, 0xF0, 0x9E, 0x40, 0x13, 0x1F, 0xAB, 0xE8, 0x83, 0x52,
+0x03, 0x53, 0x18, 0x14, 0xAE, 0xE8, 0x83, 0x52, 0x03, 0x53, 0x18, 0xD0, 0x92, 0x1F, 0xB4, 0xA8,
+0x83, 0x96, 0x03, 0x53, 0xA4, 0x54, 0xB7, 0x28, 0x83, 0x96, 0x03, 0x53, 0xA4, 0x10, 0x83, 0x52,
+0x12, 0xDF, 0xBE, 0x28, 0x83, 0x96, 0x03, 0x53, 0x24, 0x14, 0xC1, 0x68, 0x83, 0x96, 0x03, 0x53,
+0x24, 0xD0, 0x83, 0x52, 0x5F, 0xC8, 0xA7, 0x40, 0x06, 0x30, 0x03, 0xD0, 0xA7, 0x0D, 0xFF, 0x7E,
+0x03, 0x9D, 0xC5, 0xA8, 0x12, 0xC8, 0x3F, 0xB9, 0x27, 0x44, 0xA5, 0x00, 0x83, 0x96, 0x24, 0x5C,
+0xD3, 0xE8, 0x83, 0x52, 0x9E, 0x15, 0x83, 0x52, 0x13, 0x08, 0x0F, 0x39, 0x3F, 0xFE, 0x84, 0x80,
+0x83, 0x93, 0x00, 0x48, 0xA1, 0xC0, 0x21, 0xC8, 0xA9, 0x00, 0x3F, 0x30, 0xA9, 0x85, 0x29, 0x08,
+0x83, 0x96, 0xA0, 0x80, 0x00, 0xB0, 0x83, 0x52, 0x13, 0xDB, 0x01, 0xF0, 0x83, 0x96, 0xA1, 0xC0,
+0x08, 0xF0, 0xD3, 0xE1, 0x8A, 0x51, 0x21, 0xDF, 0xF1, 0xE8, 0x83, 0x52, 0x03, 0x53, 0x19, 0x96,
+0xF4, 0xE8, 0x83, 0x52, 0x03, 0x53, 0x19, 0x52, 0xA1, 0x1F, 0xFA, 0x28, 0x83, 0x52, 0x03, 0x53,
+0x99, 0xD6, 0xFD, 0x68, 0x83, 0x52, 0x03, 0x53, 0x99, 0x92, 0x83, 0x96, 0xA4, 0x9C, 0x0D, 0xA9,
+0x6C, 0xB0, 0xA0, 0x80, 0x00, 0xB0, 0x83, 0x52, 0x13, 0xDB, 0x01, 0xF0, 0x83, 0x96, 0xA1, 0xC0,
+0x0A, 0x30, 0xD3, 0xE1, 0x8A, 0x51, 0x04, 0xF0, 0x19, 0xA9, 0x60, 0x30, 0xA0, 0x80, 0x00, 0xB0,
+0x83, 0x52, 0x13, 0xDB, 0x01, 0xF0, 0x83, 0x96, 0xA1, 0xC0, 0x0A, 0x30, 0xD3, 0xE1, 0x8A, 0x51,
+0x05, 0x30, 0x83, 0x96, 0xA0, 0x80, 0x00, 0xB0, 0x83, 0x52, 0x13, 0xDB, 0x01, 0xF0, 0x83, 0x96,
+0xA1, 0xC0, 0x0B, 0x70, 0xD3, 0xE1, 0x8A, 0x51, 0x25, 0x08, 0x83, 0x96, 0xA0, 0x80, 0x00, 0xB0,
+0x83, 0x52, 0x13, 0xDB, 0x01, 0xF0, 0x83, 0x96, 0xA1, 0xC0, 0x04, 0xF0, 0xD3, 0xE1, 0x8A, 0x51,
+0x11, 0xC8, 0x83, 0x96, 0xA0, 0x80, 0x00, 0xB0, 0x83, 0x52, 0x13, 0xDB, 0x01, 0xF0, 0x83, 0x96,
+0xA1, 0xC0, 0x05, 0x30, 0xD3, 0xE1, 0x8A, 0x51, 0x10, 0x88, 0x83, 0x96, 0xA0, 0x80, 0x00, 0xB0,
+0x83, 0x52, 0x13, 0xDB, 0x01, 0xF0, 0x83, 0x96, 0xA1, 0xC0, 0x06, 0x30, 0xD3, 0xE1, 0x8A, 0x51,
+0x83, 0x96, 0x00, 0xB0, 0xA0, 0xC1, 0xA0, 0x0A, 0x83, 0x52, 0x13, 0xDB, 0x01, 0xF0, 0x83, 0x96,
+0xA1, 0xC0, 0x00, 0xB0, 0xD3, 0xE1, 0x8A, 0x51, 0x35, 0xB0, 0xA7, 0x40, 0xA7, 0x0B, 0x56, 0xE9,
+0x05, 0x30, 0x83, 0x96, 0x03, 0x53, 0xA0, 0x80, 0x00, 0xB0, 0x83, 0x52, 0x13, 0xDB, 0x01, 0xF0,
+0x83, 0x96, 0xA1, 0xC0, 0x00, 0xB0, 0xD3, 0xE1, 0x8A, 0x51, 0x03, 0x30, 0xA8, 0xC0, 0x7D, 0x30,
+0xA7, 0x40, 0xA7, 0x0B, 0x69, 0xE9, 0xA8, 0x8B, 0x69, 0xE9, 0x83, 0x52, 0x03, 0x53, 0x13, 0x1F,
+0x73, 0x29, 0x19, 0x51, 0x74, 0xE9, 0x19, 0x10, 0x05, 0x30, 0xA7, 0x40, 0xA7, 0x0B, 0x76, 0x29,
+0x83, 0x52, 0x03, 0x53, 0x13, 0x1F, 0x7E, 0x69, 0x99, 0xD5, 0x7F, 0xA9, 0x99, 0x94, 0x15, 0x70,
+0xA8, 0xC0, 0xC6, 0xB0, 0xA7, 0x40, 0xA7, 0x0B, 0x83, 0xA9, 0xA8, 0x8B, 0x83, 0xA9, 0x00, 0x00,
+0x0D, 0x70, 0x83, 0x96, 0x03, 0x53, 0xA0, 0x80, 0x00, 0xB0, 0x83, 0x52, 0x13, 0xDB, 0x01, 0xF0,
+0x83, 0x96, 0xA1, 0xC0, 0x00, 0xB0, 0xD3, 0xE1, 0x8A, 0x51, 0x93, 0x1B, 0x95, 0xE9, 0x99, 0x92,
+0x19, 0x52, 0x83, 0x96, 0x00, 0xB0, 0xA0, 0xC1, 0xA0, 0x0A, 0x83, 0x52, 0x13, 0xDB, 0x01, 0xF0,
+0x83, 0x96, 0xA1, 0xC0, 0x00, 0xB0, 0xD3, 0xE1, 0x8A, 0x51, 0x13, 0x1F, 0xA9, 0xE9, 0x99, 0x91,
+0xAA, 0xE9, 0x99, 0x50, 0xE4, 0xB0, 0xA7, 0x40, 0xAD, 0x29, 0xAE, 0x29, 0xA7, 0x0B, 0xAC, 0xE9,
+0xB1, 0xE9, 0x00, 0x00, 0x83, 0x52, 0x03, 0x53, 0x13, 0x1F, 0xB8, 0xE9, 0x19, 0x95, 0xB9, 0x29,
+0x19, 0x54, 0x03, 0x30, 0x83, 0x96, 0xA0, 0x80, 0x00, 0xB0, 0x83, 0x52, 0x13, 0xDB, 0x01, 0xF0,
+0x83, 0x96, 0xA1, 0xC0, 0x00, 0xB0, 0xD3, 0xE1, 0x8A, 0x51, 0x05, 0x30, 0xA8, 0xC0, 0x26, 0x70,
+0xA7, 0x40, 0xA7, 0x0B, 0xC9, 0xE9, 0xA8, 0x8B, 0xC9, 0xE9, 0x00, 0x00, 0x83, 0x52, 0x03, 0x53,
+0x18, 0x56, 0x9E, 0x81, 0x08, 0x40, 0x83, 0x52, 0xA6, 0x00, 0x83, 0x96, 0x21, 0xC8, 0x03, 0x59,
+0xE0, 0xA9, 0x20, 0x88, 0x83, 0x52, 0x88, 0x80, 0x26, 0x08, 0x80, 0x38, 0x86, 0xC0, 0x08, 0x40,
+0x20, 0x88, 0x83, 0x52, 0x88, 0x80, 0x26, 0x08, 0x80, 0x38, 0x85, 0xC0, 0x08, 0x40, 0x95, 0x41,
+0x96, 0x41, 0x97, 0x81, 0x98, 0x01, 0x99, 0x41, 0x9A, 0x41, 0x9B, 0x81, 0x9C, 0x41, 0x9E, 0x81,
+0x19, 0x54, 0x19, 0x95, 0x18, 0x56, 0x8B, 0x41, 0xD4, 0x41, 0x02, 0xF0, 0x54, 0x02, 0x03, 0x18,
+0x19, 0xAA, 0x54, 0x08, 0x51, 0x3E, 0x84, 0x80, 0x83, 0x93, 0x80, 0x81, 0x54, 0x08, 0x5D, 0xBE,
+0x84, 0x80, 0x07, 0x70, 0x80, 0x40, 0x54, 0x08, 0x32, 0x62, 0x8A, 0x51, 0x54, 0x08, 0x5D, 0xBE,
+0x84, 0x80, 0x00, 0xCE, 0xF0, 0x39, 0x96, 0x00, 0x54, 0x9C, 0x12, 0x6A, 0x83, 0x52, 0x03, 0x53,
+0x18, 0x14, 0x15, 0xAA, 0x83, 0x52, 0x03, 0x53, 0x18, 0xD0, 0x18, 0x55, 0x18, 0x11, 0xD4, 0x8A,
+0xF5, 0x69, 0xD3, 0x81, 0x08, 0xF0, 0x53, 0x42, 0x03, 0x18, 0x2F, 0x2A, 0x53, 0x48, 0x55, 0x7E,
+0x84, 0x80, 0x04, 0xF0, 0x83, 0x93, 0x80, 0x40, 0x53, 0x48, 0x55, 0x7E, 0x84, 0x80, 0x00, 0x48,
+0x96, 0x00, 0x53, 0x48, 0x95, 0x00, 0x98, 0x54, 0x98, 0x10, 0xD3, 0xCA, 0x1A, 0xAA, 0x10, 0xF0,
+0x9B, 0x40, 0x08, 0x40, 0xB5, 0x40, 0x51, 0x3E, 0x84, 0x80, 0x00, 0x48, 0xB4, 0x00, 0x23, 0x3E,
+0x84, 0x80, 0x8A, 0x51, 0x1D, 0xE5, 0x8A, 0x51, 0xB1, 0x00, 0x05, 0x30, 0x03, 0xD0, 0xB1, 0xCD,
+0xFF, 0x7E, 0x03, 0x9D, 0x3E, 0x2A, 0x34, 0x08, 0x2D, 0x7E, 0x84, 0x80, 0x8A, 0x51, 0x1D, 0xE5,
+0x8A, 0x51, 0xB2, 0x00, 0x32, 0x87, 0x31, 0x04, 0x01, 0x38, 0xB3, 0x40, 0x35, 0x48, 0x22, 0xFE,
+0x84, 0x80, 0x33, 0x48, 0x80, 0x40, 0x35, 0x48, 0x22, 0xFE, 0x84, 0x80, 0x00, 0x48, 0x83, 0x96,
+0xA2, 0xC0, 0x83, 0x52, 0x35, 0x48, 0x83, 0x96, 0xA3, 0x00, 0x0C, 0x30, 0x92, 0xEB, 0x18, 0x12,
+0x80, 0xF0, 0x9B, 0x40, 0x10, 0xF0, 0x9E, 0x40, 0x13, 0x1F, 0x6A, 0xEA, 0x83, 0x52, 0x03, 0x53,
+0x18, 0x14, 0x6D, 0x2A, 0x83, 0x52, 0x03, 0x53, 0x18, 0xD0, 0x92, 0x1F, 0x73, 0x2A, 0x83, 0x96,
+0x03, 0x53, 0xA4, 0x54, 0x76, 0x2A, 0x83, 0x96, 0x03, 0x53, 0xA4, 0x10, 0x83, 0x52, 0x12, 0xDF,
+0x7D, 0x6A, 0x83, 0x96, 0x03, 0x53, 0x24, 0x14, 0x80, 0x2A, 0x83, 0x96, 0x03, 0x53, 0x24, 0xD0,
+0x83, 0x52, 0x5F, 0xC8, 0xB1, 0x00, 0x06, 0x30, 0x03, 0xD0, 0xB1, 0xCD, 0xFF, 0x7E, 0x03, 0x9D,
+0x84, 0x6A, 0x12, 0xC8, 0x3F, 0xB9, 0x31, 0x04, 0xA5, 0x00, 0x83, 0x96, 0x24, 0x5C, 0x92, 0xAA,
+0x83, 0x52, 0x9E, 0x15, 0x83, 0x52, 0x13, 0x08, 0x0F, 0x39, 0x3F, 0xFE, 0x84, 0x80, 0x83, 0x93,
+0x00, 0x48, 0xA1, 0xC0, 0x21, 0xC8, 0xB3, 0x40, 0x3F, 0x30, 0xB3, 0xC5, 0x33, 0x48, 0x83, 0x96,
+0xA2, 0xC0, 0x00, 0xB0, 0x83, 0x52, 0x13, 0xDB, 0x01, 0xF0, 0x83, 0x96, 0xA3, 0x00, 0x08, 0xF0,
+0x92, 0xA3, 0x8A, 0x51, 0x21, 0xDF, 0xB0, 0xAA, 0x83, 0x52, 0x03, 0x53, 0x19, 0x96, 0xB3, 0x2A,
+0x83, 0x52, 0x03, 0x53, 0x19, 0x52, 0xA1, 0x1F, 0xB9, 0x2A, 0x83, 0x52, 0x03, 0x53, 0x99, 0xD6,
+0xBC, 0x2A, 0x83, 0x52, 0x03, 0x53, 0x99, 0x92, 0x83, 0x96, 0xA4, 0x9C, 0xCC, 0xEA, 0x6C, 0xB0,
+0xA2, 0xC0, 0x00, 0xB0, 0x83, 0x52, 0x13, 0xDB, 0x01, 0xF0, 0x83, 0x96, 0xA3, 0x00, 0x0A, 0x30,
+0x92, 0xA3, 0x8A, 0x51, 0x04, 0xF0, 0xD8, 0xEA, 0x60, 0x30, 0xA2, 0xC0, 0x00, 0xB0, 0x83, 0x52,
+0x13, 0xDB, 0x01, 0xF0, 0x83, 0x96, 0xA3, 0x00, 0x0A, 0x30, 0x92, 0xA3, 0x8A, 0x51, 0x05, 0x30,
+0x83, 0x96, 0xA2, 0xC0, 0x00, 0xB0, 0x83, 0x52, 0x13, 0xDB, 0x01, 0xF0, 0x83, 0x96, 0xA3, 0x00,
+0x0B, 0x70, 0x92, 0xA3, 0x8A, 0x51, 0x25, 0x08, 0x83, 0x96, 0xA2, 0xC0, 0x00, 0xB0, 0x83, 0x52,
+0x13, 0xDB, 0x01, 0xF0, 0x83, 0x96, 0xA3, 0x00, 0x04, 0xF0, 0x92, 0xA3, 0x8A, 0x51, 0x11, 0xC8,
+0x83, 0x96, 0xA2, 0xC0, 0x00, 0xB0, 0x83, 0x52, 0x13, 0xDB, 0x01, 0xF0, 0x83, 0x96, 0xA3, 0x00,
+0x05, 0x30, 0x92, 0xA3, 0x8A, 0x51, 0x10, 0x88, 0x83, 0x96, 0xA2, 0xC0, 0x00, 0xB0, 0x83, 0x52,
+0x13, 0xDB, 0x01, 0xF0, 0x83, 0x96, 0xA3, 0x00, 0x06, 0x30, 0x92, 0xA3, 0x8A, 0x51, 0x83, 0x96,
+0x00, 0xB0, 0xA2, 0x01, 0xA2, 0x4A, 0x83, 0x52, 0x13, 0xDB, 0x01, 0xF0, 0x83, 0x96, 0xA3, 0x00,
+0x00, 0xB0, 0x92, 0xA3, 0x8A, 0x51, 0x35, 0xB0, 0xB1, 0x00, 0xB1, 0xCB, 0x15, 0xEB, 0x05, 0x30,
+0x83, 0x96, 0x03, 0x53, 0xA2, 0xC0, 0x00, 0xB0, 0x83, 0x52, 0x13, 0xDB, 0x01, 0xF0, 0x83, 0x96,
+0xA3, 0x00, 0x00, 0xB0, 0x92, 0xA3, 0x8A, 0x51, 0x03, 0x30, 0xB2, 0x00, 0x7D, 0x30, 0xB1, 0x00,
+0xB1, 0xCB, 0x28, 0xAB, 0xB2, 0xCB, 0x28, 0xAB, 0x83, 0x52, 0x03, 0x53, 0x13, 0x1F, 0x32, 0xEB,
+0x19, 0x51, 0x33, 0x2B, 0x19, 0x10, 0x05, 0x30, 0xB1, 0x00, 0xB1, 0xCB, 0x35, 0x2B, 0x83, 0x52,
+0x03, 0x53, 0x13, 0x1F, 0x3D, 0x6B, 0x99, 0xD5, 0x3E, 0x6B, 0x99, 0x94, 0x15, 0x70, 0xB2, 0x00,
+0xC6, 0xB0, 0xB1, 0x00, 0xB1, 0xCB, 0x42, 0xAB, 0xB2, 0xCB, 0x42, 0xAB, 0x00, 0x00, 0x0D, 0x70,
+0x83, 0x96, 0x03, 0x53, 0xA2, 0xC0, 0x00, 0xB0, 0x83, 0x52, 0x13, 0xDB, 0x01, 0xF0, 0x83, 0x96,
+0xA3, 0x00, 0x00, 0xB0, 0x92, 0xA3, 0x8A, 0x51, 0x93, 0x1B, 0x54, 0xEB, 0x99, 0x92, 0x19, 0x52,
+0x83, 0x96, 0x00, 0xB0, 0xA2, 0x01, 0xA2, 0x4A, 0x83, 0x52, 0x13, 0xDB, 0x01, 0xF0, 0x83, 0x96,
+0xA3, 0x00, 0x00, 0xB0, 0x92, 0xA3, 0x8A, 0x51, 0x13, 0x1F, 0x68, 0xEB, 0x99, 0x91, 0x69, 0x2B,
+0x99, 0x50, 0xE4, 0xB0, 0xB1, 0x00, 0x6C, 0x2B, 0x6D, 0x6B, 0xB1, 0xCB, 0x6B, 0x6B, 0x70, 0xEB,
+0x00, 0x00, 0x83, 0x52, 0x03, 0x53, 0x13, 0x1F, 0x77, 0xAB, 0x19, 0x95, 0x78, 0x2B, 0x19, 0x54,
+0x03, 0x30, 0x83, 0x96, 0xA2, 0xC0, 0x00, 0xB0, 0x83, 0x52, 0x13, 0xDB, 0x01, 0xF0, 0x83, 0x96,
+0xA3, 0x00, 0x00, 0xB0, 0x92, 0xA3, 0x8A, 0x51, 0x05, 0x30, 0xB2, 0x00, 0x26, 0x70, 0xB1, 0x00,
+0xB1, 0xCB, 0x88, 0xAB, 0xB2, 0xCB, 0x88, 0xAB, 0x00, 0x00, 0x83, 0x52, 0x03, 0x53, 0x18, 0x56,
+0x9E, 0x81, 0x08, 0x40, 0x83, 0x52, 0xB0, 0xC0, 0x83, 0x96, 0x23, 0x08, 0x03, 0x59, 0x9F, 0xAB,
+0x22, 0xC8, 0x83, 0x52, 0x88, 0x80, 0x30, 0xC8, 0x80, 0x38, 0x86, 0xC0, 0x08, 0x40, 0x22, 0xC8,
+0x83, 0x52, 0x88, 0x80, 0x30, 0xC8, 0x80, 0x38, 0x85, 0xC0, 0x08, 0x40, 0x11, 0x30, 0xBE, 0x80,
+0x04, 0xF0, 0xA0, 0x80, 0x8A, 0x51, 0xE7, 0x21, 0x8A, 0x51, 0xBD, 0xC1, 0x10, 0xF0, 0x3D, 0x82,
+0x03, 0x18, 0xDD, 0xAB, 0x3E, 0x88, 0x10, 0x7A, 0x03, 0x59, 0xBB, 0xAB, 0x8A, 0x51, 0x8A, 0xA5,
+0x8A, 0x51, 0xBE, 0x80, 0xB2, 0x2B, 0x3D, 0x88, 0x20, 0x38, 0x9B, 0x40, 0x3E, 0x88, 0x10, 0x7A,
+0x03, 0x9D, 0xC7, 0x6B, 0x8A, 0x51, 0x8A, 0xA5, 0x8A, 0x51, 0xBE, 0x80, 0xBE, 0xAB, 0x3E, 0x88,
+0x11, 0xBA, 0x03, 0x9D, 0xCE, 0x6B, 0x30, 0x30, 0x9B, 0x40, 0xDD, 0xAB, 0x3D, 0x88, 0x3F, 0xFE,
+0x84, 0x80, 0x3E, 0x88, 0x83, 0x93, 0x80, 0x40, 0x3D, 0x88, 0x30, 0x78, 0x9B, 0x40, 0xBD, 0x0A,
+0xAE, 0x6B, 0x8A, 0x51, 0x8A, 0xA5, 0x8A, 0x51, 0xBE, 0x80, 0x3E, 0x88, 0x10, 0x7A, 0x03, 0x9D,
+0xD9, 0x6B, 0x20, 0xF0, 0x9B, 0x40, 0x3E, 0x88, 0x10, 0x7A, 0x03, 0x9D, 0xEC, 0x6B, 0x8A, 0x51,
+0x8A, 0xA5, 0x8A, 0x51, 0xBE, 0x80, 0xE3, 0x6B, 0x3E, 0x88, 0xDF, 0xC0, 0x5F, 0xC8, 0x30, 0x78,
+0x9B, 0x40, 0x3E, 0x88, 0x10, 0x7A, 0x03, 0x59, 0xFA, 0xAB, 0x8A, 0x51, 0x8A, 0xA5, 0x8A, 0x51,
+0xBE, 0x80, 0xF1, 0x6B, 0x20, 0xF0, 0x9B, 0x40, 0x3E, 0x88, 0x10, 0x7A, 0x03, 0x9D, 0x05, 0x6C,
+0x8A, 0x51, 0x8A, 0xA5, 0x8A, 0x51, 0xBE, 0x80, 0xFC, 0xAB, 0x3E, 0x88, 0xBC, 0x40, 0x30, 0x78,
+0x9B, 0x40, 0x3E, 0x88, 0x10, 0x7A, 0x03, 0x59, 0x12, 0x6C, 0x8A, 0x51, 0x8A, 0xA5, 0x8A, 0x51,
+0xBE, 0x80, 0x09, 0x6C, 0x40, 0xF0, 0x9B, 0x40, 0x93, 0x5F, 0x1B, 0xEC, 0x8A, 0x51, 0x5F, 0x22,
+0x8A, 0x51, 0x40, 0xF0, 0x9B, 0x40, 0xD3, 0x81, 0x08, 0xF0, 0x53, 0x42, 0x03, 0x18, 0x53, 0xEC,
+0x53, 0x48, 0x95, 0x00, 0x85, 0x70, 0x0D, 0x02, 0x03, 0x5C, 0x33, 0xEC, 0x53, 0x48, 0x55, 0x7E,
+0x84, 0x80, 0x0E, 0x70, 0x83, 0x93, 0x00, 0x42, 0x03, 0x18, 0x33, 0xEC, 0x53, 0x48, 0x55, 0x7E,
+0x84, 0x80, 0x00, 0x8A, 0x44, 0x6C, 0x34, 0x70, 0x0D, 0x02, 0x03, 0x18, 0x51, 0xAC, 0x53, 0x48,
+0x55, 0x7E, 0x84, 0x80, 0x05, 0x30, 0x83, 0x93, 0x00, 0x42, 0x03, 0x5C, 0x51, 0xAC, 0x53, 0x48,
+0x55, 0x7E, 0x84, 0x80, 0x00, 0x48, 0xFF, 0x7E, 0xB6, 0x40, 0x53, 0x48, 0x55, 0x7E, 0x84, 0x80,
+0x36, 0x48, 0x80, 0x40, 0x53, 0x48, 0x55, 0x7E, 0x84, 0x80, 0x00, 0x48, 0x96, 0x00, 0x98, 0x54,
+0x98, 0x10, 0xD3, 0xCA, 0x1C, 0xAC, 0xD4, 0x41, 0x02, 0xF0, 0x54, 0x02, 0x03, 0x18, 0xC7, 0x2C,
+0x54, 0x9C, 0x5E, 0x2C, 0x83, 0x52, 0x03, 0x53, 0x18, 0x14, 0x61, 0xAC, 0x83, 0x52, 0x03, 0x53,
+0x18, 0xD0, 0x54, 0x08, 0x51, 0x3E, 0x84, 0x80, 0x83, 0x93, 0x00, 0x48, 0x03, 0x9D, 0x6A, 0xEC,
+0x64, 0x70, 0x6B, 0x2C, 0x73, 0xF0, 0xB7, 0x80, 0x0E, 0x08, 0x37, 0x82, 0x03, 0x18, 0x7C, 0x2C,
+0x54, 0x08, 0x5D, 0xBE, 0x84, 0x80, 0x0B, 0x70, 0x00, 0x42, 0x03, 0x18, 0x7C, 0x2C, 0x54, 0x08,
+0x5D, 0xBE, 0x84, 0x80, 0x00, 0x8A, 0x8C, 0xAC, 0x2D, 0xB0, 0x0E, 0x02, 0x03, 0x18, 0x9A, 0xEC,
+0x54, 0x08, 0x5D, 0xBE, 0x84, 0x80, 0x08, 0xF0, 0x00, 0x42, 0x03, 0x5C, 0x9A, 0xEC, 0x54, 0x08,
+0x5D, 0xBE, 0x84, 0x80, 0x00, 0x48, 0xFF, 0x7E, 0xB6, 0x40, 0x54, 0x08, 0x5D, 0xBE, 0x84, 0x80,
+0x36, 0x48, 0x80, 0x40, 0x54, 0x08, 0x5D, 0xBE, 0x84, 0x80, 0x00, 0xCE, 0xF0, 0x39, 0x96, 0x00,
+0x18, 0x55, 0x18, 0x11, 0x24, 0x30, 0x0F, 0x42, 0x03, 0x5C, 0xAA, 0xEC, 0x54, 0x08, 0x51, 0x3E,
+0x84, 0x80, 0x09, 0x30, 0x00, 0x42, 0x03, 0x18, 0xAA, 0xEC, 0x54, 0x08, 0x51, 0x3E, 0x84, 0x80,
+0x00, 0x8A, 0xB9, 0x2C, 0x10, 0xF0, 0x0F, 0x42, 0x03, 0x18, 0xC5, 0xEC, 0x54, 0x08, 0x51, 0x3E,
+0x84, 0x80, 0x80, 0x88, 0x03, 0x59, 0xC5, 0xEC, 0x54, 0x08, 0x51, 0x3E, 0x84, 0x80, 0x00, 0x48,
+0xFF, 0x7E, 0xB6, 0x40, 0x54, 0x08, 0x51, 0x3E, 0x84, 0x80, 0x36, 0x48, 0x80, 0x40, 0x54, 0x08,
+0x8A, 0x51, 0x32, 0x62, 0x8A, 0x51, 0x98, 0x95, 0x98, 0x51, 0xD4, 0x8A, 0x54, 0xAC, 0x51, 0x08,
+0x19, 0x3E, 0x84, 0x80, 0x8A, 0x51, 0x1D, 0xE5, 0x8A, 0x51, 0xBA, 0x40, 0x06, 0x30, 0xE0, 0xC0,
+0x5D, 0x88, 0xF9, 0xFE, 0x8A, 0x51, 0x99, 0xE5, 0x8A, 0x51, 0xBB, 0x80, 0x3A, 0xC7, 0x97, 0x40,
+0x52, 0x08, 0x19, 0x3E, 0x84, 0x80, 0x8A, 0x51, 0x1D, 0xE5, 0x8A, 0x51, 0xBA, 0x40, 0x06, 0x30,
+0xE0, 0xC0, 0x5E, 0x88, 0xF9, 0xFE, 0x8A, 0x51, 0x99, 0xE5, 0x8A, 0x51, 0xBB, 0x80, 0x3A, 0xC7,
+0x9C, 0x00, 0x3C, 0x48, 0x95, 0x00, 0x0D, 0x08, 0xB6, 0x40, 0x03, 0xD0, 0xB6, 0xCC, 0x03, 0xD0,
+0xB6, 0xCC, 0x03, 0xD0, 0xB6, 0xCC, 0x36, 0x48, 0x01, 0xBE, 0x84, 0x80, 0x8A, 0x51, 0x1D, 0xE5,
+0x8A, 0x51, 0xB9, 0x40, 0x06, 0x30, 0xE0, 0xC0, 0x3C, 0x48, 0x55, 0x7E, 0x84, 0x80, 0x83, 0x93,
+0x00, 0x48, 0xFC, 0xFE, 0x8A, 0x51, 0x99, 0xE5, 0x8A, 0x51, 0xB8, 0x00, 0x01, 0xF0, 0xB6, 0x40,
+0x3C, 0x8A, 0x0C, 0xAD, 0x03, 0xD0, 0xB6, 0x0D, 0xFF, 0x7E, 0x03, 0x9D, 0x0A, 0xAD, 0x36, 0x48,
+0x14, 0x05, 0x03, 0x59, 0x16, 0xED, 0x38, 0x08, 0x1C, 0x87, 0x18, 0xAD, 0x38, 0x08, 0x17, 0xC7,
+0xB6, 0x40, 0x39, 0x48, 0x36, 0xC7, 0x9A, 0x00, 0x14, 0x6C, 0x05, 0x30, 0x8A, 0xC0, 0x04, 0x88,
+0x84, 0x0A, 0x82, 0x47, 0x00, 0xF4, 0x00, 0xF4, 0x00, 0xF4, 0x00, 0xF4, 0x00, 0xF4, 0x00, 0xF4,
+0x02, 0x34, 0x04, 0x34, 0x05, 0x74, 0x06, 0x74, 0x07, 0xB4, 0x08, 0x34, 0x09, 0x74, 0x0A, 0x74,
+0x0A, 0x74, 0x0B, 0xB4, 0x0B, 0xB4, 0x0C, 0x74, 0x0D, 0xB4, 0x0D, 0xB4, 0x0E, 0xB4, 0x0E, 0xB4,
+0x0E, 0xB4, 0x0F, 0xF4, 0x0F, 0xF4, 0x00, 0xF4, 0x06, 0x74, 0x0C, 0x74, 0x12, 0x74, 0x18, 0x74,
+0x1E, 0xF4, 0x24, 0x74, 0x2A, 0xB4, 0x30, 0x74, 0x36, 0xF4, 0x01, 0x34, 0x01, 0x34, 0x01, 0x34,
+0x02, 0x34, 0x03, 0x74, 0x04, 0x34, 0x05, 0x74, 0x05, 0x74, 0x06, 0x74, 0x06, 0x74, 0x0F, 0xF4,
+0x0C, 0x74, 0x09, 0x74, 0x09, 0x74, 0x09, 0x74, 0x0C, 0x74, 0x0F, 0xF4, 0x0C, 0x74, 0x0F, 0xF4,
+0x0C, 0x74, 0x83, 0x93, 0x51, 0x70, 0x84, 0x80, 0x60, 0x30, 0x8A, 0x51, 0xA7, 0x25, 0x8A, 0x51,
+0x83, 0x96, 0xA4, 0x01, 0x83, 0x52, 0x38, 0x70, 0xBF, 0xC0, 0x3A, 0xB0, 0xC0, 0x80, 0x3C, 0xB0,
+0xC1, 0xC0, 0x78, 0xB0, 0xC2, 0xC0, 0x7A, 0xF0, 0xC3, 0x00, 0x7C, 0xF0, 0xC4, 0xC0, 0x7D, 0x30,
+0xC5, 0x00, 0x7F, 0x70, 0xC6, 0x00, 0xB9, 0xF0, 0xC7, 0x40, 0xBA, 0xF0, 0xC8, 0xC0, 0xBB, 0x30,
+0xC9, 0x00, 0xFA, 0x30, 0xCA, 0x00, 0xFB, 0x70, 0xCB, 0x40, 0xFC, 0x30, 0xCC, 0x00, 0xFD, 0x70,
+0xCD, 0x40, 0xFF, 0xB0, 0xCE, 0x40, 0x00, 0xB0, 0xCF, 0x80, 0x01, 0xF0, 0xD0, 0xC0, 0x83, 0x01,
+0x8A, 0x51, 0xA6, 0x2B, 0x50, 0xC8, 0xB1, 0x00, 0x4F, 0x88, 0xB0, 0xC0, 0x31, 0x08, 0x30, 0x06,
+0x03, 0x59, 0x97, 0x6D, 0x14, 0xC8, 0xB0, 0xC0, 0x14, 0xC8, 0xB1, 0x00, 0x8E, 0x2D, 0x31, 0x08,
+0x08, 0x40, 0xB1, 0x00, 0xB0, 0x01, 0x60, 0xC8, 0x31, 0x58, 0xB0, 0x87, 0x03, 0xD0, 0xE0, 0x8D,
+0x03, 0xD0, 0xB1, 0x8C, 0xB1, 0x48, 0x03, 0x9D, 0x9B, 0x6D, 0x30, 0xC8, 0x08, 0x40, 0x64, 0xC0,
+0x80, 0x81, 0x84, 0x0A, 0x04, 0xC6, 0x03, 0x59, 0x00, 0xF4, 0x04, 0xC6, 0xA8, 0xED, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF
+};
diff --git a/libloragw/src/arb_fw.var b/libloragw/src/arb_fw.var
new file mode 100644
index 0000000..7f06906
--- /dev/null
+++ b/libloragw/src/arb_fw.var
@@ -0,0 +1,529 @@
+/*
+ / _____) _ | |
+( (____ _____ ____ _| |_ _____ ____| |__
+ \____ \| ___ | (_ _) ___ |/ ___) _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+ (C)2013 Semtech-Cycleo
+
+Description:
+ Arbiter firmware
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+Maintainer: Matthieu Leurent
+*/
+
+static uint8_t arb_firmware[MCU_ARB_FW_BYTE] = {
+0x8A, 0x51, 0xAE, 0x6E, 0x00, 0xB0, 0x8A, 0xC0, 0x04, 0x88, 0x84, 0x0A, 0x82, 0x47, 0x00, 0xF4,
+0x07, 0xB4, 0x06, 0x74, 0x05, 0x74, 0x04, 0x34, 0x03, 0x74, 0x02, 0x34, 0x01, 0x34, 0x00, 0xF4,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0x64, 0xC0, 0x80, 0x81,
+0x84, 0x0A, 0x04, 0xC6, 0x03, 0x59, 0x00, 0xF4, 0x04, 0xC6, 0xA7, 0x6E, 0xD9, 0x81, 0x83, 0x93,
+0x22, 0x30, 0x84, 0x80, 0x59, 0xB0, 0x8A, 0x51, 0xA6, 0xE6, 0x83, 0x01, 0x8A, 0x51, 0xB8, 0x2E,
+0x01, 0xF0, 0xA0, 0x80, 0x8A, 0x51, 0x01, 0x67, 0x8A, 0x51, 0x0D, 0x58, 0xD4, 0x2E, 0xD3, 0x81,
+0x59, 0x94, 0x53, 0x48, 0x8A, 0x51, 0xDB, 0x66, 0x8A, 0x51, 0x83, 0x52, 0x03, 0x53, 0xD9, 0x1C,
+0xCC, 0x2E, 0x8A, 0x51, 0x85, 0xE7, 0x8A, 0x51, 0x0D, 0x58, 0xBD, 0xAE, 0x08, 0xF0, 0xD3, 0xCA,
+0x53, 0x42, 0x03, 0x18, 0xBD, 0xAE, 0xC0, 0xAE, 0x59, 0xDC, 0xBD, 0xAE, 0x8A, 0x51, 0x32, 0xE7,
+0x8A, 0x51, 0x59, 0x50, 0xBD, 0xAE, 0xDB, 0x80, 0xD9, 0x90, 0x5B, 0x88, 0x96, 0x00, 0x15, 0x70,
+0xDA, 0x40, 0xDA, 0x0B, 0xE1, 0x2E, 0x83, 0x52, 0x03, 0x53, 0x8D, 0xDC, 0x08, 0x40, 0xD9, 0xD4,
+0x15, 0x54, 0x15, 0x70, 0xDA, 0x40, 0xDA, 0x0B, 0xEB, 0xAE, 0x83, 0x52, 0x03, 0x53, 0x0D, 0xDD,
+0xED, 0xAE, 0x10, 0x88, 0xD4, 0x00, 0x11, 0xC8, 0xD5, 0x40, 0x0F, 0x48, 0xD7, 0x80, 0x0E, 0x08,
+0xD2, 0x00, 0x12, 0xC8, 0xD6, 0x40, 0x15, 0x10, 0x15, 0x70, 0xDA, 0x40, 0xDA, 0x0B, 0xFE, 0xEE,
+0x08, 0x40, 0x95, 0x41, 0x96, 0x41, 0x97, 0x81, 0x98, 0x01, 0x99, 0x41, 0x9A, 0x41, 0x9B, 0x81,
+0x9C, 0x41, 0x9E, 0x81, 0xD8, 0x41, 0x08, 0xF0, 0x58, 0x02, 0x03, 0x18, 0x29, 0x2F, 0x58, 0x08,
+0x32, 0x3E, 0x84, 0x80, 0x80, 0x81, 0x58, 0x08, 0x3A, 0x7E, 0x84, 0x80, 0x80, 0x81, 0x58, 0x08,
+0x4A, 0x3E, 0x84, 0x80, 0x80, 0x81, 0x58, 0x08, 0x22, 0xFE, 0x84, 0x80, 0x80, 0x81, 0x58, 0x08,
+0x42, 0xFE, 0x84, 0x80, 0x80, 0x81, 0x58, 0x08, 0x2A, 0x3E, 0x84, 0x80, 0x80, 0x81, 0xD8, 0x8A,
+0x0B, 0x2F, 0xD4, 0x41, 0xD5, 0x81, 0xD7, 0xC1, 0xD2, 0x41, 0xD6, 0x81, 0x59, 0x50, 0xD9, 0x90,
+0xA1, 0x01, 0x08, 0x40, 0xD8, 0x41, 0x08, 0xF0, 0x58, 0x02, 0x03, 0x18, 0x08, 0x40, 0x58, 0x08,
+0x2A, 0x3E, 0x84, 0x80, 0x83, 0x93, 0x00, 0xCB, 0x83, 0x2F, 0x58, 0x08, 0x2A, 0x3E, 0x84, 0x80,
+0x80, 0x81, 0x58, 0x08, 0x42, 0xFE, 0x84, 0x80, 0x00, 0x48, 0x97, 0x40, 0x58, 0x08, 0x22, 0xFE,
+0x84, 0x80, 0x00, 0x48, 0x98, 0xC0, 0x58, 0x08, 0x32, 0x3E, 0x84, 0x80, 0x00, 0x48, 0x99, 0x00,
+0x58, 0x08, 0x3A, 0x7E, 0x84, 0x80, 0x00, 0x48, 0x9A, 0x00, 0x58, 0x08, 0x01, 0xBE, 0x84, 0x80,
+0x8A, 0x51, 0x02, 0xA0, 0x8A, 0x51, 0x9B, 0x40, 0x58, 0x08, 0x4A, 0x3E, 0x84, 0x80, 0x00, 0x48,
+0x9C, 0x00, 0x95, 0x94, 0x15, 0x70, 0xDA, 0x40, 0xDA, 0x0B, 0x64, 0x2F, 0x83, 0x52, 0x03, 0x53,
+0x95, 0x50, 0x15, 0x70, 0xDA, 0x40, 0xDA, 0x0B, 0x6B, 0xAF, 0x01, 0xF0, 0x83, 0x52, 0x03, 0x53,
+0xDA, 0x40, 0x58, 0x08, 0x01, 0xBE, 0x84, 0x80, 0x8A, 0x51, 0x02, 0xA0, 0x8A, 0x51, 0x01, 0xBE,
+0x7B, 0xEF, 0x03, 0xD0, 0xDA, 0x0D, 0xFF, 0x7E, 0x03, 0x9D, 0x79, 0xAF, 0x5A, 0x48, 0x13, 0x45,
+0x03, 0x59, 0x6D, 0xAF, 0xA1, 0x4A, 0xD8, 0x8A, 0x33, 0x6F, 0x59, 0x91, 0xD8, 0x41, 0x08, 0xF0,
+0x58, 0x02, 0x03, 0x18, 0xBD, 0xEF, 0x0A, 0x30, 0x57, 0x82, 0x03, 0x18, 0x91, 0x2F, 0x59, 0xD5,
+0xB9, 0xAF, 0x01, 0xF0, 0xDA, 0x40, 0x58, 0x08, 0x01, 0xBE, 0x84, 0x80, 0x8A, 0x51, 0x02, 0xA0,
+0x8A, 0x51, 0x01, 0xBE, 0x9D, 0xAF, 0x03, 0xD0, 0xDA, 0x0D, 0xFF, 0x7E, 0x03, 0x9D, 0x9B, 0xAF,
+0x5A, 0x48, 0x13, 0x45, 0x03, 0x9D, 0xAA, 0x6F, 0x58, 0x08, 0x2A, 0x3E, 0x84, 0x80, 0x83, 0x93,
+0x00, 0xCB, 0xB9, 0xAF, 0x58, 0x08, 0x42, 0xFE, 0x84, 0x80, 0x83, 0x93, 0x00, 0x48, 0x56, 0x86,
+0x03, 0x9D, 0xB9, 0xAF, 0x58, 0x08, 0x22, 0xFE, 0x84, 0x80, 0x00, 0x48, 0x52, 0x46, 0x03, 0x59,
+0x8F, 0xAF, 0x59, 0xD9, 0xBD, 0xEF, 0xD8, 0x8A, 0x87, 0x6F, 0x59, 0xD9, 0x08, 0x40, 0xD8, 0x41,
+0x08, 0xF0, 0x58, 0x02, 0x03, 0x18, 0x08, 0x40, 0x01, 0xF0, 0xDA, 0x40, 0x58, 0x08, 0x01, 0xBE,
+0x84, 0x80, 0x8A, 0x51, 0x02, 0xA0, 0x8A, 0x51, 0x01, 0xBE, 0xD0, 0x2F, 0x03, 0xD0, 0xDA, 0x0D,
+0xFF, 0x7E, 0x03, 0x9D, 0xCE, 0xAF, 0x5A, 0x48, 0x13, 0x45, 0x03, 0x9D, 0xFE, 0x2F, 0x58, 0x08,
+0x2A, 0x3E, 0x84, 0x80, 0x83, 0x93, 0x00, 0x48, 0x03, 0x9D, 0xFE, 0x2F, 0x58, 0x08, 0x32, 0x3E,
+0x84, 0x80, 0x54, 0x08, 0x80, 0x40, 0x58, 0x08, 0x3A, 0x7E, 0x84, 0x80, 0x55, 0x48, 0x80, 0x40,
+0x58, 0x08, 0x4A, 0x3E, 0x84, 0x80, 0x57, 0x88, 0x80, 0x40, 0x58, 0x08, 0x22, 0xFE, 0x84, 0x80,
+0x52, 0x08, 0x80, 0x40, 0x58, 0x08, 0x42, 0xFE, 0x84, 0x80, 0x56, 0x48, 0x80, 0x40, 0x58, 0x08,
+0x2A, 0x3E, 0x84, 0x80, 0x01, 0xF0, 0x80, 0x40, 0x59, 0xD5, 0x08, 0x40, 0xD8, 0x8A, 0xC0, 0xEF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF
+};
diff --git a/libloragw/src/cal_fw.var b/libloragw/src/cal_fw.var
new file mode 100644
index 0000000..8c9389e
--- /dev/null
+++ b/libloragw/src/cal_fw.var
@@ -0,0 +1,529 @@
+/*
+ / _____) _ | |
+( (____ _____ ____ _| |_ _____ ____| |__
+ \____ \| ___ | (_ _) ___ |/ ___) _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+ (C)2013 Semtech-Cycleo
+
+Description:
+ Calibration firmware
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+Maintainer: Matthieu Leurent
+*/
+
+static uint8_t cal_firmware[MCU_AGC_FW_BYTE] = {
+0x8A, 0x51, 0x6F, 0x28, 0x00, 0xB0, 0x8A, 0xC0, 0x04, 0x88, 0x84, 0x0A, 0x82, 0x47, 0x00, 0xF4,
+0x18, 0x74, 0x1C, 0xB4, 0x1E, 0xF4, 0x20, 0x34, 0x22, 0x74, 0x23, 0xB4, 0x24, 0x74, 0x25, 0xB4,
+0x26, 0xB4, 0x27, 0xF4, 0x28, 0x74, 0x28, 0x74, 0x29, 0xB4, 0x2A, 0xB4, 0x2A, 0xB4, 0x2B, 0xF4,
+0x2B, 0xF4, 0x2C, 0xB4, 0x2C, 0xB4, 0x2D, 0xF4, 0x2D, 0xF4, 0x2D, 0xF4, 0x2E, 0xF4, 0x2E, 0xF4,
+0x2E, 0xF4, 0x2F, 0x34, 0x2F, 0x34, 0x2F, 0x34, 0x30, 0x74, 0x30, 0x74, 0x00, 0xF4, 0x00, 0xF4,
+0x06, 0x74, 0x0A, 0x74, 0x0C, 0x74, 0x0E, 0xB4, 0x10, 0x34, 0x11, 0x74, 0x12, 0x74, 0x13, 0xB4,
+0x14, 0x74, 0x15, 0xB4, 0x16, 0xB4, 0x16, 0xB4, 0x17, 0xF4, 0x18, 0x74, 0x0F, 0xF4, 0x0C, 0x74,
+0x09, 0x74, 0x09, 0x74, 0x09, 0x74, 0x0C, 0x74, 0x0F, 0xF4, 0x0C, 0x74, 0x0F, 0xF4, 0x0C, 0x74,
+0x01, 0x34, 0x01, 0x34, 0x01, 0x34, 0x02, 0x34, 0x03, 0x74, 0x04, 0x34, 0x05, 0x74, 0x05, 0x74,
+0x06, 0x74, 0x06, 0x74, 0x02, 0x34, 0x02, 0x34, 0x03, 0x74, 0x04, 0x34, 0x05, 0x74, 0x06, 0x74,
+0x07, 0xB4, 0x40, 0x34, 0x20, 0x34, 0x10, 0x34, 0x08, 0x34, 0x04, 0x34, 0x02, 0x34, 0x01, 0x34,
+0x06, 0x74, 0x06, 0x74, 0x07, 0xB4, 0x07, 0xB4, 0x07, 0xB4, 0x10, 0x34, 0x08, 0x34, 0x04, 0x34,
+0x02, 0x34, 0x01, 0x34, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0x64, 0xC0,
+0x80, 0x81, 0x84, 0x0A, 0x04, 0xC6, 0x03, 0x59, 0x00, 0xF4, 0x04, 0xC6, 0x68, 0x68, 0xE6, 0x81,
+0xE7, 0xC1, 0x83, 0x93, 0x55, 0xB0, 0x84, 0x80, 0x66, 0xB0, 0x8A, 0x51, 0x67, 0xA0, 0x8A, 0x51,
+0xDA, 0xF0, 0x84, 0x80, 0xEE, 0x30, 0x8A, 0x51, 0x67, 0xA0, 0x8A, 0x51, 0x83, 0xD7, 0xA0, 0x30,
+0x84, 0x80, 0xAE, 0xF0, 0x8A, 0x51, 0x67, 0xA0, 0x83, 0x96, 0x01, 0xF0, 0xEE, 0x80, 0x83, 0x52,
+0x01, 0xF0, 0xE8, 0x00, 0x07, 0x70, 0xE9, 0x40, 0x06, 0x30, 0xEA, 0x40, 0x0F, 0xB0, 0xEB, 0x80,
+0x01, 0xF0, 0xEC, 0x40, 0x05, 0x30, 0xED, 0x80, 0x02, 0xF0, 0xEE, 0x80, 0x0E, 0x70, 0xEF, 0xC0,
+0x83, 0x01, 0x8A, 0x51, 0x4C, 0xAC, 0xA3, 0x41, 0x23, 0x08, 0xEA, 0xBE, 0x84, 0x80, 0x23, 0x08,
+0xA1, 0xC0, 0x00, 0xB0, 0x22, 0x21, 0x8A, 0x51, 0x83, 0x93, 0x80, 0x40, 0x23, 0x08, 0xE0, 0x3E,
+0x84, 0x80, 0x23, 0x08, 0xA1, 0xC0, 0x01, 0xF0, 0x22, 0x21, 0x8A, 0x51, 0x80, 0x40, 0x23, 0x08,
+0xDE, 0xFE, 0x84, 0x80, 0x23, 0x08, 0xA1, 0xC0, 0x02, 0xF0, 0x22, 0x21, 0x8A, 0x51, 0x80, 0x40,
+0x23, 0x08, 0xDA, 0xBE, 0x84, 0x80, 0x23, 0x08, 0xA1, 0xC0, 0x03, 0x30, 0x22, 0x21, 0x8A, 0x51,
+0x80, 0x40, 0x23, 0x08, 0xE8, 0x7E, 0x84, 0x80, 0x23, 0x08, 0xA1, 0xC0, 0x04, 0xF0, 0x22, 0x21,
+0x8A, 0x51, 0x80, 0x40, 0x23, 0x08, 0xE6, 0xBE, 0x84, 0x80, 0x23, 0x08, 0xA1, 0xC0, 0x05, 0x30,
+0x22, 0x21, 0x8A, 0x51, 0x80, 0x40, 0x23, 0x08, 0xE4, 0x7E, 0x84, 0x80, 0x23, 0x08, 0xA1, 0xC0,
+0x06, 0x30, 0x22, 0x21, 0x8A, 0x51, 0x80, 0x40, 0x23, 0x08, 0xAC, 0x7E, 0x84, 0x80, 0x23, 0x08,
+0xA1, 0xC0, 0x08, 0xF0, 0x22, 0x21, 0x8A, 0x51, 0x83, 0xD7, 0x80, 0x40, 0x23, 0x08, 0xA8, 0x3E,
+0x84, 0x80, 0x23, 0x08, 0xA1, 0xC0, 0x0A, 0x30, 0x22, 0x21, 0x8A, 0x51, 0x80, 0x40, 0x23, 0x08,
+0xAA, 0x7E, 0x84, 0x80, 0x23, 0x08, 0xA1, 0xC0, 0x0B, 0x70, 0x22, 0x21, 0x8A, 0x51, 0x80, 0x40,
+0x23, 0x08, 0xA2, 0x3E, 0x84, 0x80, 0x23, 0x08, 0xA1, 0xC0, 0x0C, 0x30, 0x22, 0x21, 0x8A, 0x51,
+0x80, 0x40, 0x23, 0x08, 0xA4, 0x3E, 0x84, 0x80, 0x23, 0x08, 0xA1, 0xC0, 0x0D, 0x70, 0x22, 0x21,
+0x8A, 0x51, 0x80, 0x40, 0x23, 0x08, 0xA6, 0x7E, 0x84, 0x80, 0x23, 0x08, 0xA1, 0xC0, 0x0E, 0x70,
+0x22, 0x21, 0x8A, 0x51, 0x80, 0x40, 0x23, 0x08, 0xA0, 0xFE, 0x84, 0x80, 0x23, 0x08, 0xA1, 0xC0,
+0x10, 0xF0, 0x22, 0x21, 0x8A, 0x51, 0x80, 0x40, 0x02, 0xF0, 0xA3, 0x8A, 0x23, 0x02, 0x03, 0x18,
+0x08, 0x40, 0x9C, 0xA8, 0xA2, 0xC0, 0x21, 0xC8, 0x03, 0x59, 0x2B, 0xE9, 0x22, 0xC8, 0x86, 0xC0,
+0x22, 0xC8, 0x86, 0xC0, 0x2F, 0x29, 0x22, 0xC8, 0x85, 0xC0, 0x22, 0xC8, 0x85, 0xC0, 0x08, 0x88,
+0x08, 0x40, 0xB4, 0x00, 0x34, 0x8E, 0xF0, 0x39, 0x0C, 0x78, 0xB8, 0x00, 0xBB, 0xC1, 0x38, 0x08,
+0xA1, 0xC0, 0x02, 0xF0, 0xA2, 0xC0, 0x54, 0x70, 0xA7, 0x23, 0x8A, 0x51, 0x38, 0x08, 0x02, 0xBE,
+0xA1, 0xC0, 0x02, 0xF0, 0xA2, 0xC0, 0x54, 0x70, 0xA7, 0x23, 0x8A, 0x51, 0x02, 0xF0, 0xA1, 0xC0,
+0x54, 0x70, 0x30, 0x24, 0x8A, 0x51, 0xE5, 0x40, 0xE5, 0x9F, 0x46, 0xA9, 0x02, 0xF0, 0xA1, 0xC0,
+0x57, 0xF0, 0x30, 0x24, 0x8A, 0x51, 0xB5, 0x40, 0x02, 0xF0, 0xA1, 0xC0, 0x58, 0x70, 0x30, 0x24,
+0x8A, 0x51, 0xB6, 0x40, 0x3B, 0x88, 0x25, 0x3E, 0x84, 0x80, 0x35, 0x48, 0x44, 0x24, 0x8A, 0x51,
+0xA4, 0xC0, 0x36, 0x48, 0x44, 0x24, 0x8A, 0x51, 0x24, 0x47, 0x83, 0x93, 0x80, 0x40, 0x0F, 0xB0,
+0xBB, 0x0A, 0x3B, 0x82, 0x03, 0x5C, 0x37, 0x29, 0xBA, 0x81, 0x25, 0x08, 0xB9, 0x40, 0xB7, 0xC1,
+0xBB, 0xC1, 0x3B, 0x88, 0x25, 0x3E, 0x84, 0x80, 0x39, 0x48, 0x00, 0x42, 0x03, 0x18, 0x7F, 0xA9,
+0x3B, 0x88, 0x25, 0x3E, 0x84, 0x80, 0x00, 0x48, 0xB9, 0x40, 0x3B, 0x88, 0xB7, 0x80, 0x0F, 0xB0,
+0xBB, 0x0A, 0x3B, 0x82, 0x03, 0x5C, 0x71, 0xE9, 0x37, 0x88, 0x25, 0x3E, 0x84, 0x80, 0xFF, 0xB0,
+0x80, 0x40, 0x08, 0xF0, 0xBA, 0xCA, 0x3A, 0x42, 0x03, 0x5C, 0x6D, 0x29, 0x39, 0x48, 0x08, 0x40,
+0xB2, 0x00, 0xC9, 0x41, 0xCA, 0x41, 0xA1, 0xC0, 0x02, 0xF0, 0xA2, 0xC0, 0x53, 0xB0, 0xA7, 0x23,
+0xC7, 0x81, 0x49, 0x08, 0xB3, 0x40, 0x4A, 0x08, 0xBC, 0x40, 0x47, 0x48, 0x4A, 0x3E, 0x84, 0x80,
+0x8A, 0x51, 0x02, 0xA0, 0x8A, 0x51, 0x49, 0x87, 0xB4, 0x00, 0x47, 0x48, 0x4A, 0x3E, 0x84, 0x80,
+0x8A, 0x51, 0x02, 0xA0, 0x8A, 0x51, 0x4A, 0x87, 0xBD, 0x80, 0x47, 0x48, 0x4A, 0x3E, 0x84, 0x80,
+0x8A, 0x51, 0x02, 0xA0, 0x8A, 0x51, 0x49, 0x87, 0xB5, 0x40, 0x47, 0x48, 0x4A, 0x3E, 0x84, 0x80,
+0x8A, 0x51, 0x02, 0xA0, 0x8A, 0x51, 0x4A, 0x02, 0xBE, 0x80, 0x47, 0x48, 0x4A, 0x3E, 0x84, 0x80,
+0x8A, 0x51, 0x02, 0xA0, 0x8A, 0x51, 0x49, 0x02, 0xB6, 0x40, 0x47, 0x48, 0x4A, 0x3E, 0x84, 0x80,
+0x8A, 0x51, 0x02, 0xA0, 0x8A, 0x51, 0x4A, 0x87, 0xBF, 0xC0, 0x47, 0x48, 0x4A, 0x3E, 0x84, 0x80,
+0x8A, 0x51, 0x02, 0xA0, 0x8A, 0x51, 0x49, 0x02, 0xB7, 0x80, 0x47, 0x48, 0x4A, 0x3E, 0x84, 0x80,
+0x8A, 0x51, 0x02, 0xA0, 0x8A, 0x51, 0x4A, 0x02, 0xC0, 0x80, 0xC8, 0x01, 0x48, 0xC8, 0x33, 0x7E,
+0x84, 0x80, 0x00, 0x48, 0xA1, 0xC0, 0x27, 0xB0, 0xA2, 0x01, 0xA2, 0x4A, 0xA7, 0x23, 0x8A, 0x51,
+0x48, 0xC8, 0x3C, 0x7E, 0x84, 0x80, 0x00, 0x48, 0xA1, 0xC0, 0x28, 0x30, 0xA2, 0x01, 0xA2, 0x4A,
+0xA7, 0x23, 0x47, 0x48, 0x43, 0x3E, 0x84, 0x80, 0x8A, 0x51, 0x02, 0xA0, 0x8A, 0x51, 0xD2, 0xE3,
+0x8A, 0x51, 0xC6, 0x00, 0x48, 0xC8, 0x03, 0x59, 0x01, 0x2A, 0x45, 0x08, 0x46, 0x02, 0x03, 0x18,
+0x0D, 0xAA, 0x46, 0x08, 0xC5, 0x00, 0x48, 0xC8, 0x33, 0x7E, 0x84, 0x80, 0x00, 0x48, 0xC9, 0x00,
+0x48, 0xC8, 0x3C, 0x7E, 0x84, 0x80, 0x00, 0x48, 0xCA, 0x00, 0x05, 0x30, 0xC8, 0x4A, 0x48, 0xC2,
+0x03, 0x5C, 0xDE, 0x69, 0x07, 0x70, 0xC7, 0xCA, 0x47, 0x42, 0x49, 0x08, 0xB3, 0x40, 0x4A, 0x08,
+0xBC, 0x40, 0x03, 0x5C, 0x9D, 0x29, 0x49, 0x4A, 0xB4, 0x00, 0x4A, 0x4A, 0xBD, 0x80, 0x49, 0x4A,
+0xB5, 0x40, 0x4A, 0x43, 0xBE, 0x80, 0x49, 0x43, 0xB6, 0x40, 0x4A, 0x4A, 0xBF, 0xC0, 0x49, 0x43,
+0xB7, 0x80, 0x4A, 0x43, 0xC0, 0x80, 0x49, 0x08, 0xB8, 0x00, 0x4A, 0x4A, 0xC1, 0xC0, 0x49, 0x08,
+0xB9, 0x40, 0x4A, 0x43, 0xC2, 0xC0, 0x49, 0x4A, 0xBA, 0x40, 0x4A, 0x08, 0xC3, 0x00, 0x49, 0x43,
+0xBB, 0x80, 0x4A, 0x08, 0xC4, 0xC0, 0xC8, 0x01, 0x48, 0xC8, 0x33, 0x7E, 0x84, 0x80, 0x00, 0x48,
+0xA1, 0xC0, 0x27, 0xB0, 0xA2, 0x01, 0xA2, 0x4A, 0xA7, 0x23, 0x8A, 0x51, 0x48, 0xC8, 0x3C, 0x7E,
+0x84, 0x80, 0x00, 0x48, 0xA1, 0xC0, 0x28, 0x30, 0xA2, 0x01, 0xA2, 0x4A, 0xA7, 0x23, 0x8A, 0x51,
+0x07, 0x70, 0xD2, 0xE3, 0x8A, 0x51, 0xC6, 0x00, 0x48, 0xC8, 0x03, 0x59, 0x5B, 0x2A, 0x45, 0x08,
+0x46, 0x02, 0x03, 0x18, 0x67, 0x2A, 0x46, 0x08, 0xC5, 0x00, 0x48, 0xC8, 0x33, 0x7E, 0x84, 0x80,
+0x00, 0x48, 0xC9, 0x00, 0x48, 0xC8, 0x3C, 0x7E, 0x84, 0x80, 0x00, 0x48, 0xCA, 0x00, 0x09, 0x30,
+0xC8, 0x4A, 0x48, 0xC2, 0x03, 0x5C, 0x3C, 0xEA, 0x49, 0x08, 0xA1, 0xC0, 0x27, 0xB0, 0xA2, 0x01,
+0xA2, 0x4A, 0xA7, 0x23, 0x8A, 0x51, 0x4A, 0x08, 0xA1, 0xC0, 0x28, 0x30, 0xA2, 0x01, 0xA2, 0x4A,
+0xA7, 0x6B, 0xB3, 0x40, 0xCB, 0x81, 0xCC, 0x41, 0x33, 0xCB, 0x82, 0x6A, 0x74, 0xB0, 0xC7, 0x40,
+0x75, 0xF0, 0x85, 0xAA, 0x72, 0xB0, 0xC7, 0x40, 0x73, 0xF0, 0xC8, 0xC0, 0x33, 0x48, 0xA1, 0xC0,
+0x02, 0xF0, 0xA2, 0xC0, 0x53, 0xB0, 0xA7, 0x23, 0xCA, 0x41, 0x4B, 0x48, 0xB5, 0x40, 0x4C, 0x08,
+0xBE, 0x80, 0x4A, 0x08, 0x56, 0x7E, 0x84, 0x80, 0x8A, 0x51, 0x02, 0xA0, 0x8A, 0x51, 0x4B, 0xC7,
+0xB6, 0x40, 0x4A, 0x08, 0x56, 0x7E, 0x84, 0x80, 0x8A, 0x51, 0x02, 0xA0, 0x8A, 0x51, 0x4C, 0x87,
+0xBF, 0xC0, 0x4A, 0x08, 0x56, 0x7E, 0x84, 0x80, 0x8A, 0x51, 0x02, 0xA0, 0x8A, 0x51, 0x4B, 0xC7,
+0xB7, 0x80, 0x4A, 0x08, 0x56, 0x7E, 0x84, 0x80, 0x8A, 0x51, 0x02, 0xA0, 0x8A, 0x51, 0x4C, 0x02,
+0xC0, 0x80, 0x4A, 0x08, 0x56, 0x7E, 0x84, 0x80, 0x8A, 0x51, 0x02, 0xA0, 0x8A, 0x51, 0x4B, 0x42,
+0xB8, 0x00, 0x4A, 0x08, 0x56, 0x7E, 0x84, 0x80, 0x8A, 0x51, 0x02, 0xA0, 0x8A, 0x51, 0x4C, 0x87,
+0xC1, 0xC0, 0x4A, 0x08, 0x56, 0x7E, 0x84, 0x80, 0x8A, 0x51, 0x02, 0xA0, 0x8A, 0x51, 0x4B, 0x42,
+0xB9, 0x40, 0x4A, 0x08, 0x56, 0x7E, 0x84, 0x80, 0x8A, 0x51, 0x02, 0xA0, 0x8A, 0x51, 0x4C, 0x02,
+0xC2, 0xC0, 0xCD, 0x81, 0x1F, 0xF0, 0xA1, 0xC0, 0xE0, 0x70, 0xA2, 0xC0, 0x4D, 0x48, 0x35, 0x7E,
+0x84, 0x80, 0x00, 0x48, 0xBB, 0x63, 0x8A, 0x51, 0xB2, 0x00, 0x4D, 0x48, 0x35, 0x7E, 0x84, 0x80,
+0x32, 0x08, 0x80, 0x40, 0x1F, 0xF0, 0xA1, 0xC0, 0xE0, 0x70, 0xA2, 0xC0, 0x4D, 0x48, 0x3E, 0xBE,
+0x84, 0x80, 0x00, 0x48, 0xBB, 0x63, 0x8A, 0x51, 0xB2, 0x00, 0x4D, 0x48, 0x3E, 0xBE, 0x84, 0x80,
+0x32, 0x08, 0x80, 0x40, 0x4D, 0x48, 0x35, 0x7E, 0x84, 0x80, 0x00, 0x48, 0xA1, 0xC0, 0xA2, 0x01,
+0x47, 0x48, 0xA7, 0x23, 0x8A, 0x51, 0x4D, 0x48, 0x3E, 0xBE, 0x84, 0x80, 0x00, 0x48, 0xA1, 0xC0,
+0xA2, 0x01, 0x48, 0xC8, 0xA7, 0x23, 0x4A, 0x08, 0x51, 0x3E, 0x84, 0x80, 0x8A, 0x51, 0x02, 0xA0,
+0x8A, 0x51, 0xD2, 0xE3, 0x8A, 0x51, 0xC9, 0x00, 0x4D, 0x48, 0x03, 0x59, 0x13, 0xEB, 0x34, 0x08,
+0x49, 0x02, 0x03, 0x18, 0x1F, 0x6B, 0x49, 0x08, 0xB4, 0x00, 0x4D, 0x48, 0x35, 0x7E, 0x84, 0x80,
+0x00, 0x48, 0xCB, 0x40, 0x4D, 0x48, 0x3E, 0xBE, 0x84, 0x80, 0x00, 0x48, 0xCC, 0x00, 0x05, 0x30,
+0xCD, 0xCA, 0x4D, 0x42, 0x03, 0x5C, 0xD2, 0xEA, 0x05, 0x30, 0xCA, 0x8A, 0x4A, 0x02, 0x4B, 0x48,
+0xB5, 0x40, 0x4C, 0x08, 0xBE, 0x80, 0x03, 0x5C, 0x91, 0xAA, 0x4B, 0x8A, 0xB6, 0x40, 0x4C, 0x4A,
+0xBF, 0xC0, 0x4B, 0x8A, 0xB7, 0x80, 0x4C, 0x43, 0xC0, 0x80, 0x4B, 0x83, 0xB8, 0x00, 0x4C, 0x4A,
+0xC1, 0xC0, 0x4B, 0x83, 0xB9, 0x40, 0x4C, 0x43, 0xC2, 0xC0, 0x4B, 0x48, 0xBA, 0x40, 0x4C, 0x4A,
+0xC3, 0x00, 0x4B, 0x48, 0xBB, 0x80, 0x4C, 0x43, 0xC4, 0xC0, 0x4B, 0x8A, 0xBC, 0x40, 0x4C, 0x08,
+0xC5, 0x00, 0x4B, 0x83, 0xBD, 0x80, 0x4C, 0x08, 0xC6, 0x00, 0xCD, 0x81, 0x1F, 0xF0, 0xA1, 0xC0,
+0xE0, 0x70, 0xA2, 0xC0, 0x4D, 0x48, 0x35, 0x7E, 0x84, 0x80, 0x00, 0x48, 0xBB, 0x63, 0x8A, 0x51,
+0xB2, 0x00, 0x4D, 0x48, 0x35, 0x7E, 0x84, 0x80, 0x32, 0x08, 0x80, 0x40, 0x1F, 0xF0, 0xA1, 0xC0,
+0xE0, 0x70, 0xA2, 0xC0, 0x4D, 0x48, 0x3E, 0xBE, 0x84, 0x80, 0x00, 0x48, 0xBB, 0x63, 0x8A, 0x51,
+0xB2, 0x00, 0x4D, 0x48, 0x3E, 0xBE, 0x84, 0x80, 0x32, 0x08, 0x80, 0x40, 0x4D, 0x48, 0x35, 0x7E,
+0x84, 0x80, 0x00, 0x48, 0xA1, 0xC0, 0xA2, 0x01, 0x47, 0x48, 0xA7, 0x23, 0x8A, 0x51, 0x4D, 0x48,
+0x3E, 0xBE, 0x84, 0x80, 0x00, 0x48, 0xA1, 0xC0, 0xA2, 0x01, 0x48, 0xC8, 0xA7, 0x23, 0x8A, 0x51,
+0x07, 0x70, 0xD2, 0xE3, 0x8A, 0x51, 0xC9, 0x00, 0x4D, 0x48, 0x03, 0x59, 0x8B, 0x2B, 0x34, 0x08,
+0x49, 0x02, 0x03, 0x18, 0x97, 0x6B, 0x49, 0x08, 0xB4, 0x00, 0x4D, 0x48, 0x35, 0x7E, 0x84, 0x80,
+0x00, 0x48, 0xCB, 0x40, 0x4D, 0x48, 0x3E, 0xBE, 0x84, 0x80, 0x00, 0x48, 0xCC, 0x00, 0x09, 0x30,
+0xCD, 0xCA, 0x4D, 0x42, 0x03, 0x5C, 0x4E, 0x2B, 0x4B, 0x48, 0xA1, 0xC0, 0xA2, 0x01, 0x47, 0x48,
+0xA7, 0x23, 0x8A, 0x51, 0x4C, 0x08, 0xA1, 0xC0, 0xA2, 0x01, 0x48, 0xC8, 0xA7, 0x6B, 0xA3, 0x00,
+0x22, 0x0A, 0x03, 0x59, 0xB5, 0x6B, 0x22, 0xC8, 0x63, 0x86, 0x03, 0x59, 0xB5, 0x6B, 0x22, 0xC8,
+0x88, 0x80, 0x80, 0xF0, 0x8C, 0xC0, 0x22, 0xC8, 0xE3, 0x40, 0x21, 0xC8, 0x88, 0x80, 0x23, 0x08,
+0x80, 0x38, 0x8C, 0xC0, 0x08, 0x40, 0xA4, 0xC0, 0x21, 0xC8, 0x80, 0x7A, 0xA3, 0x00, 0x24, 0xC8,
+0x80, 0x7A, 0xA3, 0x42, 0x03, 0x18, 0xC6, 0x2B, 0x21, 0xC8, 0x08, 0x40, 0x24, 0xC8, 0x80, 0x7A,
+0xA3, 0x00, 0x22, 0xC8, 0x80, 0x7A, 0xA3, 0x42, 0x03, 0x18, 0xD0, 0xEB, 0x22, 0xC8, 0x08, 0x40,
+0x24, 0xC8, 0x08, 0x40, 0xAA, 0x00, 0x2A, 0x8E, 0xF0, 0x39, 0x0C, 0x78, 0xAE, 0x40, 0xB1, 0x41,
+0x2E, 0x48, 0xA1, 0xC0, 0x02, 0xF0, 0xA2, 0xC0, 0x54, 0x70, 0xA7, 0x23, 0x8A, 0x51, 0x2E, 0x48,
+0x02, 0xBE, 0xA1, 0xC0, 0x02, 0xF0, 0xA2, 0xC0, 0x54, 0x70, 0xA7, 0x23, 0x8A, 0x51, 0x02, 0xF0,
+0xA1, 0xC0, 0x54, 0x70, 0x30, 0x24, 0x8A, 0x51, 0xE5, 0x40, 0xE5, 0x9F, 0xE7, 0xAB, 0x02, 0xF0,
+0xA1, 0xC0, 0x57, 0xF0, 0x30, 0x24, 0x8A, 0x51, 0xAB, 0x40, 0x02, 0xF0, 0xA1, 0xC0, 0x58, 0x70,
+0x30, 0x24, 0x8A, 0x51, 0xAC, 0x00, 0x31, 0x08, 0x25, 0x3E, 0x84, 0x80, 0x2B, 0x48, 0x44, 0x24,
+0x8A, 0x51, 0xA4, 0xC0, 0x2C, 0x08, 0x44, 0x24, 0x8A, 0x51, 0x24, 0x47, 0x80, 0x40, 0x05, 0x30,
+0xB1, 0x8A, 0x31, 0x02, 0x03, 0x5C, 0xD8, 0x2B, 0xB0, 0x01, 0x25, 0x08, 0xAF, 0x80, 0xAD, 0x81,
+0xB1, 0x41, 0x31, 0x08, 0x25, 0x3E, 0x84, 0x80, 0x2F, 0x88, 0x00, 0x42, 0x03, 0x18, 0x1F, 0x2C,
+0x31, 0x08, 0x25, 0x3E, 0x84, 0x80, 0x00, 0x48, 0xAF, 0x80, 0x31, 0x08, 0xAD, 0x40, 0x05, 0x30,
+0xB1, 0x8A, 0x31, 0x02, 0x03, 0x5C, 0x11, 0x6C, 0x2D, 0x48, 0x25, 0x3E, 0x84, 0x80, 0xFF, 0xB0,
+0x80, 0x40, 0x03, 0x30, 0xB0, 0x4A, 0x30, 0xC2, 0x03, 0x5C, 0x0D, 0xAC, 0x2F, 0x88, 0x08, 0x40,
+0xA2, 0xC0, 0x21, 0x0A, 0x03, 0x59, 0x3E, 0x2C, 0x21, 0xC8, 0x63, 0x86, 0x03, 0x59, 0x3E, 0x2C,
+0x21, 0xC8, 0x88, 0x80, 0x80, 0xF0, 0x8C, 0xC0, 0x21, 0xC8, 0xE3, 0x40, 0x22, 0xC8, 0x8C, 0xC0,
+0x22, 0xC8, 0x8C, 0xC0, 0x08, 0x88, 0x08, 0x40, 0xA1, 0xC0, 0xA1, 0x1F, 0x4A, 0xAC, 0x21, 0x03,
+0xFF, 0x3A, 0x08, 0x40, 0x21, 0xC8, 0x08, 0x40, 0x02, 0xF0, 0xA0, 0x80, 0x95, 0x41, 0x96, 0x41,
+0x97, 0x81, 0x98, 0x01, 0x99, 0x41, 0x9A, 0x41, 0x9B, 0x81, 0x9C, 0x41, 0x10, 0xF0, 0x9E, 0x40,
+0x8B, 0x41, 0x83, 0x96, 0xD0, 0x01, 0xD1, 0x41, 0x83, 0x52, 0xD4, 0x41, 0x54, 0x08, 0xA0, 0xFE,
+0x84, 0x80, 0x80, 0x81, 0x54, 0x08, 0xA8, 0x3E, 0x84, 0x80, 0x80, 0x81, 0x54, 0x08, 0xB0, 0x3E,
+0x84, 0x80, 0x80, 0x81, 0x54, 0x08, 0xB8, 0x7E, 0x84, 0x80, 0x80, 0x81, 0x54, 0x08, 0xC0, 0xFE,
+0x84, 0x80, 0x80, 0x81, 0x54, 0x08, 0xC8, 0x3E, 0x84, 0x80, 0x80, 0x81, 0x54, 0x08, 0xD2, 0x7E,
+0x84, 0x80, 0x08, 0xF0, 0x80, 0x81, 0xD4, 0x8A, 0x54, 0x02, 0x03, 0x5C, 0x5E, 0x2C, 0x00, 0xB0,
+0xA1, 0x01, 0xA1, 0x43, 0x8A, 0x51, 0x30, 0x24, 0x8A, 0x51, 0x03, 0xBA, 0x03, 0x9D, 0x7F, 0xAC,
+0x03, 0x30, 0xE3, 0x40, 0xC8, 0x70, 0xA1, 0xC0, 0x02, 0xF0, 0xA2, 0xC0, 0x56, 0xB0, 0x8A, 0x51,
+0xA7, 0x23, 0x8A, 0x51, 0x02, 0xF0, 0xA1, 0xC0, 0x56, 0xB0, 0x8A, 0x51, 0x30, 0x24, 0x8A, 0x51,
+0xE5, 0x40, 0xC8, 0xFA, 0x03, 0x59, 0x1B, 0x94, 0xC9, 0xB0, 0xA1, 0xC0, 0x04, 0xF0, 0xA2, 0x01,
+0x8A, 0x95, 0xF0, 0x27, 0x8A, 0x51, 0x04, 0xF0, 0xA1, 0x01, 0x8A, 0x51, 0x22, 0x21, 0x8A, 0x51,
+0xE5, 0x40, 0xC9, 0x3A, 0x03, 0x59, 0x9B, 0xD4, 0xCA, 0xB0, 0xA1, 0xC0, 0x04, 0xF0, 0xA2, 0x01,
+0xA2, 0x4A, 0x8A, 0x95, 0xF0, 0x27, 0x8A, 0x51, 0x04, 0xF0, 0xA1, 0x01, 0xA1, 0x4A, 0x8A, 0x51,
+0x22, 0x21, 0x8A, 0x51, 0xE5, 0x40, 0xCA, 0x3A, 0x03, 0x59, 0x1B, 0xD5, 0x14, 0xC8, 0xCE, 0x40,
+0x06, 0x30, 0x03, 0xD0, 0xCE, 0xCC, 0xFF, 0x7E, 0x03, 0x9D, 0xC1, 0xAC, 0x4E, 0x48, 0xD1, 0x00,
+0x14, 0x5C, 0xCE, 0x2C, 0x83, 0x52, 0x03, 0x53, 0x66, 0xD6, 0xD1, 0xEC, 0x83, 0x52, 0x03, 0x53,
+0x66, 0x92, 0x94, 0x9C, 0xD7, 0x6C, 0x83, 0x52, 0x03, 0x53, 0xE6, 0x16, 0xDA, 0x2C, 0x83, 0x52,
+0x03, 0x53, 0xE6, 0xD2, 0x14, 0x9D, 0xE0, 0xAC, 0x83, 0x52, 0x03, 0x53, 0xE6, 0x57, 0xE3, 0x2C,
+0x83, 0x52, 0x03, 0x53, 0xE6, 0x13, 0x94, 0xDD, 0xE9, 0x2C, 0x83, 0x52, 0x03, 0x53, 0x67, 0xD4,
+0xEC, 0x2C, 0x83, 0x52, 0x03, 0x53, 0x67, 0x90, 0x14, 0x9E, 0xF2, 0x2C, 0x83, 0x52, 0x03, 0x53,
+0x66, 0x94, 0xF5, 0x6C, 0x83, 0x52, 0x03, 0x53, 0x66, 0x50, 0x94, 0xDE, 0xFB, 0xAC, 0x83, 0x52,
+0x03, 0x53, 0x66, 0x17, 0xFE, 0xAC, 0x83, 0x52, 0x03, 0x53, 0x66, 0xD3, 0xD1, 0x48, 0x03, 0x9D,
+0x05, 0xAD, 0x83, 0x52, 0x03, 0x53, 0xE6, 0x15, 0x08, 0x6D, 0x83, 0x52, 0x03, 0x53, 0xE6, 0xD1,
+0x51, 0x8B, 0x0E, 0xED, 0x83, 0x52, 0x03, 0x53, 0xE6, 0xD4, 0x11, 0xAD, 0x83, 0x52, 0x03, 0x53,
+0xE6, 0x90, 0x51, 0x08, 0x02, 0x7A, 0x03, 0x9D, 0x19, 0xED, 0x83, 0x52, 0x03, 0x53, 0x66, 0xD5,
+0x1C, 0xED, 0x83, 0x52, 0x03, 0x53, 0x66, 0x91, 0x8A, 0x51, 0x9B, 0xA0, 0x8A, 0x51, 0xD4, 0x41,
+0x54, 0x08, 0xE0, 0x3E, 0x84, 0x80, 0x83, 0x93, 0x00, 0x48, 0xCE, 0x40, 0x54, 0x08, 0xE2, 0x7E,
+0x84, 0x80, 0x4E, 0x48, 0x80, 0x40, 0x54, 0x08, 0xDE, 0xFE, 0x84, 0x80, 0x00, 0x48, 0xCE, 0x40,
+0x54, 0x08, 0x55, 0x7E, 0x84, 0x80, 0x4E, 0x48, 0x80, 0x40, 0x54, 0x08, 0xDA, 0xBE, 0x84, 0x80,
+0x00, 0x48, 0xCE, 0x40, 0x54, 0x08, 0xDC, 0xBE, 0x84, 0x80, 0x4E, 0x48, 0x80, 0x40, 0x54, 0x08,
+0xE8, 0x7E, 0x84, 0x80, 0x00, 0x48, 0xCE, 0x40, 0x54, 0x08, 0x5B, 0xBE, 0x84, 0x80, 0x4E, 0x48,
+0x80, 0x40, 0x54, 0x08, 0xE6, 0xBE, 0x84, 0x80, 0x00, 0x48, 0xCE, 0x40, 0x54, 0x08, 0x59, 0x7E,
+0x84, 0x80, 0x4E, 0x48, 0x80, 0x40, 0x54, 0x08, 0xE4, 0x7E, 0x84, 0x80, 0x00, 0x48, 0xCE, 0x40,
+0x54, 0x08, 0x57, 0xBE, 0x84, 0x80, 0x4E, 0x48, 0x80, 0x40, 0x02, 0xF0, 0xD4, 0x8A, 0x54, 0x02,
+0x03, 0x5C, 0x20, 0x6D, 0x69, 0xB0, 0xA1, 0x01, 0xA2, 0x01, 0x8A, 0x51, 0xA7, 0x23, 0x8A, 0x51,
+0x19, 0x10, 0x19, 0x51, 0x99, 0x50, 0x99, 0x91, 0x21, 0x30, 0xA1, 0x01, 0xA1, 0x4A, 0xA2, 0x01,
+0xA2, 0x4A, 0x8A, 0x51, 0xA7, 0x23, 0x8A, 0x51, 0x21, 0x30, 0xA1, 0x01, 0xA2, 0x01, 0xA2, 0x4A,
+0x8A, 0x51, 0xA7, 0x23, 0x8A, 0x51, 0x07, 0x70, 0xA1, 0xC0, 0x02, 0xF0, 0xA2, 0xC0, 0x30, 0x30,
+0x8A, 0x51, 0xA7, 0x23, 0x8A, 0x51, 0xE6, 0xD8, 0xE8, 0x41, 0x27, 0xB0, 0xA1, 0x01, 0xA2, 0x01,
+0xA2, 0x4A, 0x8A, 0x51, 0xA7, 0x23, 0x8A, 0x51, 0x28, 0x30, 0xA1, 0x01, 0xA2, 0x01, 0xA2, 0x4A,
+0x8A, 0x51, 0xA7, 0x23, 0x8A, 0x51, 0x66, 0x1E, 0x3E, 0x6E, 0xE6, 0x5D, 0x66, 0xD9, 0x9A, 0x2D,
+0xE6, 0x1C, 0xBD, 0xAD, 0x18, 0x14, 0xE6, 0x1C, 0xB2, 0x2D, 0x03, 0x30, 0xA1, 0xC0, 0x02, 0xF0,
+0xA2, 0xC0, 0x2C, 0x70, 0x8A, 0x51, 0xA7, 0x23, 0x8A, 0x51, 0x99, 0xD5, 0x29, 0x70, 0xD0, 0xC0,
+0x96, 0xB0, 0xCF, 0x80, 0xA6, 0xB0, 0xCE, 0x40, 0xCE, 0x0B, 0xAC, 0x2D, 0xCF, 0x4B, 0xAC, 0x2D,
+0xD0, 0x8B, 0xAC, 0x2D, 0x03, 0x30, 0x83, 0x52, 0x03, 0x53, 0xEE, 0x80, 0x0F, 0xB0, 0xEF, 0xC0,
+0x00, 0xB0, 0x8A, 0x95, 0x02, 0x26, 0x8A, 0x51, 0xC7, 0x6D, 0x18, 0xD0, 0x02, 0xF0, 0xEE, 0x80,
+0x0E, 0x70, 0xEF, 0xC0, 0x01, 0xF0, 0xAA, 0x41, 0x8A, 0x95, 0x75, 0x25, 0x8A, 0x51, 0x6C, 0x48,
+0x83, 0x96, 0xD2, 0x00, 0x83, 0x52, 0x6B, 0x88, 0x83, 0x96, 0xD3, 0x40, 0x83, 0x52, 0x64, 0x08,
+0x83, 0x96, 0xD4, 0x00, 0x83, 0x52, 0x02, 0xF0, 0xA1, 0x01, 0xA2, 0xC0, 0x53, 0xB0, 0x8A, 0x51,
+0xA7, 0x23, 0x8A, 0x51, 0x14, 0x30, 0xA1, 0xC0, 0x02, 0xF0, 0xA2, 0xC0, 0x56, 0xB0, 0x8A, 0x51,
+0xA7, 0x23, 0x8A, 0x51, 0x02, 0xF0, 0x8A, 0x51, 0x31, 0x61, 0x8A, 0x51, 0xD2, 0x00, 0xEC, 0xF0,
+0xA1, 0xC0, 0x02, 0xF0, 0xA2, 0xC0, 0x56, 0xB0, 0x8A, 0x51, 0xA7, 0x23, 0x8A, 0x51, 0x00, 0xB0,
+0x8A, 0x51, 0x79, 0xE2, 0x8A, 0x51, 0x07, 0x70, 0x8A, 0x51, 0x31, 0x61, 0x8A, 0x51, 0xD3, 0x40,
+0x02, 0xF0, 0xA1, 0x01, 0xA2, 0xC0, 0x2F, 0xF0, 0x8A, 0x51, 0xA7, 0x23, 0x8A, 0x51, 0x24, 0x30,
+0xA1, 0xC0, 0x02, 0xF0, 0xA2, 0xC0, 0x2F, 0xF0, 0x8A, 0x51, 0xA7, 0x23, 0x8A, 0x51, 0x2A, 0x70,
+0xCF, 0x80, 0x8D, 0xB0, 0xCE, 0x40, 0xCE, 0x0B, 0x0B, 0xEE, 0xCF, 0x4B, 0x0B, 0xEE, 0x10, 0x6E,
+0x83, 0x52, 0x02, 0xF0, 0x03, 0x53, 0xA1, 0x01, 0xA2, 0xC0, 0x2F, 0xF0, 0x8A, 0x51, 0xA7, 0x23,
+0x8A, 0x51, 0xE6, 0x5D, 0x66, 0xD9, 0x1E, 0x2E, 0xE6, 0x1C, 0x25, 0xEE, 0x99, 0x91, 0x03, 0x30,
+0xA1, 0xC0, 0x00, 0xB0, 0xA2, 0x01, 0xA2, 0x4A, 0x29, 0xEE, 0x03, 0x30, 0xA1, 0xC0, 0x00, 0xB0,
+0xA2, 0x01, 0x8A, 0x95, 0xF0, 0x27, 0x8A, 0x51, 0x52, 0x08, 0x8A, 0x95, 0xEB, 0x24, 0x8A, 0x51,
+0xCE, 0x40, 0x53, 0x48, 0x8A, 0x95, 0xEB, 0x24, 0x8A, 0x51, 0x4E, 0x42, 0x1E, 0x7E, 0x83, 0x96,
+0xD0, 0xC0, 0x32, 0x70, 0x50, 0xC2, 0x83, 0x52, 0x03, 0x18, 0x9B, 0x15, 0x83, 0x52, 0xE6, 0x5E,
+0xEE, 0xAE, 0xE6, 0x5D, 0x66, 0xD9, 0x46, 0xEE, 0xE6, 0x1C, 0x69, 0x2E, 0x18, 0xD0, 0xE6, 0x1C,
+0x5E, 0x6E, 0x03, 0x30, 0xA1, 0xC0, 0x02, 0xF0, 0xA2, 0xC0, 0x2C, 0x70, 0x8A, 0x51, 0xA7, 0x23,
+0x8A, 0x51, 0x99, 0x94, 0x29, 0x70, 0xD0, 0xC0, 0x96, 0xB0, 0xCF, 0x80, 0xA6, 0xB0, 0xCE, 0x40,
+0xCE, 0x0B, 0x58, 0xEE, 0xCF, 0x4B, 0x58, 0xEE, 0xD0, 0x8B, 0x58, 0xEE, 0x03, 0x30, 0x83, 0x52,
+0x03, 0x53, 0xEE, 0x80, 0x0F, 0xB0, 0xEF, 0xC0, 0x01, 0xF0, 0x8A, 0x95, 0x02, 0x26, 0x8A, 0x51,
+0x74, 0x2E, 0x18, 0x14, 0x02, 0xF0, 0xEE, 0x80, 0x0E, 0x70, 0xEF, 0xC0, 0x01, 0xF0, 0xAA, 0x41,
+0xAA, 0x8A, 0x8A, 0x95, 0x75, 0x25, 0x8A, 0x51, 0x6C, 0x48, 0x83, 0x96, 0xD2, 0x00, 0x83, 0x52,
+0x6B, 0x88, 0x83, 0x96, 0xD3, 0x40, 0x83, 0x52, 0x64, 0x08, 0x83, 0x96, 0xD4, 0x00, 0x83, 0x52,
+0x02, 0xF0, 0xA1, 0x01, 0xA1, 0x4A, 0xA2, 0xC0, 0x53, 0xB0, 0x8A, 0x51, 0xA7, 0x23, 0x8A, 0x51,
+0x14, 0x30, 0xA1, 0xC0, 0x02, 0xF0, 0xA2, 0xC0, 0x56, 0xB0, 0x8A, 0x51, 0xA7, 0x23, 0x8A, 0x51,
+0x02, 0xF0, 0x8A, 0x51, 0x31, 0x61, 0x8A, 0x51, 0xD2, 0x00, 0xEC, 0xF0, 0xA1, 0xC0, 0x02, 0xF0,
+0xA2, 0xC0, 0x56, 0xB0, 0x8A, 0x51, 0xA7, 0x23, 0x8A, 0x51, 0x01, 0xF0, 0x8A, 0x51, 0x79, 0xE2,
+0x8A, 0x51, 0x07, 0x70, 0x8A, 0x51, 0x31, 0x61, 0x8A, 0x51, 0xD3, 0x40, 0x02, 0xF0, 0xA1, 0x01,
+0xA2, 0xC0, 0x2F, 0xF0, 0x8A, 0x51, 0xA7, 0x23, 0x8A, 0x51, 0x25, 0x70, 0xA1, 0xC0, 0x02, 0xF0,
+0xA2, 0xC0, 0x2F, 0xF0, 0x8A, 0x51, 0xA7, 0x23, 0x8A, 0x51, 0x2A, 0x70, 0xCF, 0x80, 0x8D, 0xB0,
+0xCE, 0x40, 0xCE, 0x0B, 0xB9, 0x6E, 0xCF, 0x4B, 0xB9, 0x6E, 0xBE, 0xAE, 0x83, 0x52, 0x02, 0xF0,
+0x03, 0x53, 0xA1, 0x01, 0xA2, 0xC0, 0x2F, 0xF0, 0x8A, 0x51, 0xA7, 0x23, 0x8A, 0x51, 0xE6, 0x5D,
+0x66, 0xD9, 0xCC, 0x2E, 0xE6, 0x1C, 0xD4, 0x2E, 0xE6, 0x1C, 0xCF, 0xAE, 0x99, 0x50, 0x03, 0x30,
+0xA1, 0xC0, 0x00, 0xB0, 0xA2, 0x01, 0xD9, 0x6E, 0x03, 0x30, 0xA1, 0xC0, 0x00, 0xB0, 0xA2, 0x01,
+0xA2, 0x4A, 0x8A, 0x95, 0xF0, 0x27, 0x8A, 0x51, 0x52, 0x08, 0x8A, 0x95, 0xEB, 0x24, 0x8A, 0x51,
+0xCE, 0x40, 0x53, 0x48, 0x8A, 0x95, 0xEB, 0x24, 0x8A, 0x51, 0x4E, 0x42, 0x1E, 0x7E, 0x83, 0x96,
+0xD1, 0x00, 0x32, 0x70, 0x51, 0x02, 0x83, 0x52, 0x03, 0x18, 0x1B, 0xD6, 0x83, 0x52, 0x66, 0xDC,
+0xF3, 0xAE, 0x03, 0x30, 0xF4, 0x6E, 0x02, 0xF0, 0xEE, 0x80, 0x01, 0xF0, 0xE1, 0x00, 0x14, 0x30,
+0xA1, 0xC0, 0x02, 0xF0, 0xA2, 0xC0, 0x56, 0xB0, 0x8A, 0x51, 0xA7, 0x23, 0x8A, 0x51, 0xE6, 0x9F,
+0x72, 0x6F, 0x18, 0xD0, 0x02, 0xF0, 0xA1, 0x01, 0xA2, 0xC0, 0x53, 0xB0, 0x8A, 0x51, 0xA7, 0x23,
+0x8A, 0x51, 0x9B, 0x16, 0xD4, 0x41, 0x27, 0xB0, 0xA1, 0x01, 0xA2, 0x01, 0xA2, 0x4A, 0x8A, 0x51,
+0xA7, 0x23, 0x8A, 0x51, 0x28, 0x30, 0xA1, 0x01, 0xA2, 0x01, 0xA2, 0x4A, 0x8A, 0x51, 0xA7, 0x23,
+0x8A, 0x51, 0x54, 0x08, 0x08, 0xBE, 0xEF, 0xC0, 0x00, 0xB0, 0xAA, 0x41, 0xD4, 0x48, 0x03, 0x59,
+0x01, 0xF0, 0x8A, 0x95, 0x75, 0x25, 0x8A, 0x51, 0x54, 0x08, 0xD2, 0x7E, 0x84, 0x80, 0x6B, 0x0E,
+0xF0, 0x39, 0x64, 0x04, 0x83, 0x93, 0x80, 0x40, 0x03, 0x30, 0x8A, 0x51, 0x31, 0x61, 0x8A, 0x51,
+0xD2, 0x00, 0x00, 0xB0, 0x8A, 0x51, 0x90, 0x21, 0x8A, 0x51, 0x07, 0x70, 0x8A, 0x51, 0x31, 0x61,
+0x8A, 0x51, 0xD3, 0x40, 0x52, 0x08, 0x8A, 0x95, 0xEB, 0x24, 0x8A, 0x51, 0xCE, 0x40, 0x53, 0x48,
+0x8A, 0x95, 0xEB, 0x24, 0x8A, 0x51, 0x4E, 0x42, 0x18, 0xFE, 0xCF, 0x80, 0x54, 0x08, 0xC0, 0xFE,
+0x84, 0x80, 0x4F, 0x88, 0x80, 0x40, 0x54, 0x08, 0xA0, 0xFE, 0x84, 0x80, 0x27, 0xB0, 0xA1, 0x01,
+0xA1, 0x4A, 0x8A, 0x51, 0x30, 0x24, 0x8A, 0x51, 0x80, 0x40, 0x54, 0x08, 0xA8, 0x3E, 0x84, 0x80,
+0x28, 0x30, 0xA1, 0x01, 0xA1, 0x4A, 0x8A, 0x51, 0x30, 0x24, 0x8A, 0x51, 0x80, 0x40, 0x54, 0x08,
+0xC0, 0xFE, 0x84, 0x80, 0x14, 0x30, 0x00, 0x42, 0x03, 0x5C, 0x9B, 0xD2, 0x08, 0xF0, 0xD4, 0x8A,
+0x54, 0x02, 0x03, 0x5C, 0x0B, 0x2F, 0x03, 0x30, 0xA1, 0xC0, 0x00, 0xB0, 0xA2, 0x01, 0x8A, 0x95,
+0xF0, 0x27, 0x8A, 0x51, 0x67, 0x1C, 0xE8, 0x6F, 0x18, 0x14, 0x02, 0xF0, 0xA1, 0x01, 0xA1, 0x4A,
+0xA2, 0xC0, 0x53, 0xB0, 0x8A, 0x51, 0xA7, 0x23, 0x8A, 0x51, 0x1B, 0x17, 0xD4, 0x41, 0x27, 0xB0,
+0xA1, 0x01, 0xA2, 0x01, 0xA2, 0x4A, 0x8A, 0x51, 0xA7, 0x23, 0x8A, 0x51, 0x28, 0x30, 0xA1, 0x01,
+0xA2, 0x01, 0xA2, 0x4A, 0x8A, 0x51, 0xA7, 0x23, 0x8A, 0x51, 0x54, 0x08, 0x08, 0xBE, 0xEF, 0xC0,
+0x00, 0xB0, 0xAA, 0x41, 0xAA, 0x8A, 0xD4, 0x48, 0x03, 0x59, 0x01, 0xF0, 0x8A, 0x95, 0x75, 0x25,
+0x8A, 0x51, 0x54, 0x08, 0xD2, 0x7E, 0x84, 0x80, 0x6B, 0x0E, 0xF0, 0x39, 0x64, 0x04, 0x83, 0x93,
+0x80, 0x40, 0x03, 0x30, 0x8A, 0x51, 0x31, 0x61, 0x8A, 0x51, 0xD2, 0x00, 0x01, 0xF0, 0x8A, 0x51,
+0x90, 0x21, 0x8A, 0x51, 0x07, 0x70, 0x8A, 0x51, 0x31, 0x61, 0x8A, 0x51, 0xD3, 0x40, 0x52, 0x08,
+0x8A, 0x95, 0xEB, 0x24, 0x8A, 0x51, 0xCE, 0x40, 0x53, 0x48, 0x8A, 0x95, 0xEB, 0x24, 0x8A, 0x51,
+0x4E, 0x42, 0x18, 0xFE, 0xCF, 0x80, 0x54, 0x08, 0xC8, 0x3E, 0x84, 0x80, 0x4F, 0x88, 0x80, 0x40,
+0x54, 0x08, 0xB0, 0x3E, 0x84, 0x80, 0x27, 0xB0, 0xA1, 0x01, 0xA1, 0x4A, 0x8A, 0x51, 0x30, 0x24,
+0x8A, 0x51, 0x80, 0x40, 0x54, 0x08, 0xB8, 0x7E, 0x84, 0x80, 0x28, 0x30, 0xA1, 0x01, 0xA1, 0x4A,
+0x8A, 0x51, 0x30, 0x24, 0x8A, 0x51, 0x80, 0x40, 0x54, 0x08, 0xC8, 0x3E, 0x84, 0x80, 0x14, 0x30,
+0x00, 0x42, 0x03, 0x5C, 0x1B, 0xD3, 0x08, 0xF0, 0xD4, 0x8A, 0x54, 0x02, 0x03, 0x5C, 0x7F, 0x2F,
+0x03, 0x30, 0xA1, 0xC0, 0x00, 0xB0, 0xA2, 0x01, 0xA2, 0x4A, 0x8A, 0x95, 0xF0, 0x27, 0x8A, 0x51,
+0x18, 0x56, 0x18, 0x12, 0x8A, 0x95, 0x5B, 0x67, 0x8A, 0x51, 0xE4, 0xB0, 0xCE, 0x40, 0xF0, 0x6F,
+0xF1, 0xAF, 0xCE, 0x0B, 0xEF, 0x2F, 0xF4, 0xAF, 0x00, 0x00, 0x0E, 0x70, 0x83, 0x52, 0x03, 0x53,
+0xA1, 0xC0, 0x69, 0xB0, 0xA2, 0x01, 0x8A, 0x51, 0xA7, 0x23, 0x8A, 0x51, 0x9B, 0x57, 0xFF, 0x6F,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF,
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xA2, 0xC0, 0x10, 0xF0, 0x22, 0xC2, 0x22, 0xC8, 0x03, 0x18,
+0xF6, 0x6C, 0x1F, 0xBE, 0x84, 0x80, 0x8A, 0x51, 0x02, 0xA0, 0x08, 0x40, 0xA1, 0xC0, 0x03, 0xD0,
+0xA1, 0x4C, 0x03, 0xD0, 0xA1, 0x4C, 0x03, 0xD0, 0xA1, 0x4C, 0x21, 0xC8, 0x01, 0xBE, 0x84, 0x80,
+0x8A, 0x51, 0x02, 0xA0, 0x08, 0x40, 0xA8, 0xC0, 0x28, 0x5C, 0x0A, 0xAD, 0x83, 0x52, 0x03, 0x53,
+0x18, 0x14, 0x0D, 0xED, 0x83, 0x52, 0x03, 0x53, 0x18, 0xD0, 0x07, 0x70, 0xE4, 0x00, 0x64, 0x8E,
+0xF0, 0x39, 0x96, 0x00, 0x18, 0x55, 0x18, 0x11, 0xA9, 0x41, 0x28, 0xC8, 0xA4, 0xC0, 0x00, 0xB0,
+0x56, 0xE5, 0x8A, 0x95, 0x98, 0x95, 0x98, 0x51, 0xA7, 0x81, 0x74, 0xB0, 0x0E, 0x02, 0x03, 0x5C,
+0x27, 0x2D, 0x0B, 0x70, 0x64, 0x02, 0x03, 0x18, 0x27, 0x2D, 0xE4, 0x8A, 0x31, 0xED, 0x2D, 0xB0,
+0x0E, 0x02, 0x03, 0x18, 0x36, 0x2D, 0x08, 0xF0, 0x64, 0x02, 0x03, 0x5C, 0x36, 0x2D, 0xFF, 0xB0,
+0xE4, 0xC7, 0x64, 0x8E, 0xF0, 0x39, 0x96, 0x00, 0x18, 0x55, 0x18, 0x11, 0x24, 0x30, 0x0F, 0x42,
+0x03, 0x5C, 0x40, 0x6D, 0x09, 0x30, 0x29, 0x02, 0x03, 0x18, 0x40, 0x6D, 0xA9, 0x8A, 0x49, 0xED,
+0x10, 0xF0, 0x0F, 0x42, 0x03, 0x18, 0x50, 0xAD, 0x29, 0x08, 0x03, 0x59, 0x50, 0xAD, 0xFF, 0xB0,
+0xA9, 0xC7, 0x28, 0xC8, 0xA4, 0xC0, 0x29, 0x08, 0x56, 0xE5, 0x8A, 0x95, 0x98, 0x95, 0x98, 0x51,
+0x14, 0x30, 0xA7, 0xCA, 0x27, 0x42, 0x03, 0x18, 0x08, 0x40, 0x1D, 0x2D, 0xA6, 0x00, 0x39, 0x7E,
+0x84, 0x80, 0x8A, 0x51, 0x02, 0xA0, 0x8A, 0x95, 0xEC, 0x40, 0x26, 0x08, 0x2F, 0xBE, 0x84, 0x80,
+0x8A, 0x51, 0x02, 0xA0, 0x8A, 0x95, 0xEB, 0x80, 0x6C, 0x48, 0xA5, 0x00, 0x05, 0x30, 0x03, 0xD0,
+0xA5, 0xCD, 0xFF, 0x7E, 0x03, 0xD0, 0x03, 0x9D, 0x68, 0xED, 0x6B, 0x0D, 0x25, 0x04, 0x68, 0x04,
+0xA1, 0xC0, 0x24, 0xC8, 0xA2, 0xC0, 0x0C, 0x30, 0xF0, 0x6F, 0xAD, 0x40, 0x01, 0xF0, 0x83, 0x96,
+0xED, 0x80, 0x83, 0x52, 0x2A, 0x08, 0xAA, 0xE6, 0x8A, 0x95, 0x2D, 0x48, 0x03, 0x59, 0xFE, 0xED,
+0x2A, 0x08, 0xE2, 0x7E, 0x84, 0x80, 0x00, 0x48, 0xAB, 0x40, 0x2A, 0x08, 0x5B, 0xBE, 0x84, 0x80,
+0x2B, 0x48, 0x80, 0x40, 0x66, 0x5F, 0x92, 0xED, 0x2A, 0x08, 0x55, 0x7E, 0x84, 0x80, 0x00, 0x48,
+0x28, 0xFE, 0x97, 0x6D, 0x2A, 0x08, 0x55, 0x7E, 0x84, 0x80, 0x00, 0x48, 0x14, 0xFE, 0xAB, 0x40,
+0x2A, 0x08, 0x59, 0x7E, 0x84, 0x80, 0x2B, 0x48, 0x80, 0x40, 0x2A, 0x08, 0x55, 0x7E, 0x84, 0x80,
+0x00, 0x48, 0xAB, 0x40, 0x2A, 0x08, 0x59, 0x7E, 0x84, 0x80, 0x00, 0x48, 0xAC, 0x00, 0x2B, 0x48,
+0x2C, 0x02, 0x2A, 0x08, 0x03, 0x18, 0xB6, 0x6D, 0x5B, 0xBE, 0x84, 0x80, 0x00, 0x8A, 0xAB, 0x40,
+0x2A, 0x08, 0x5B, 0xBE, 0x84, 0x80, 0x2B, 0x48, 0x80, 0x40, 0x2A, 0x08, 0xDC, 0xBE, 0x84, 0x80,
+0x00, 0x48, 0xAB, 0x40, 0x2A, 0x08, 0x57, 0xBE, 0x84, 0x80, 0x2B, 0x48, 0x80, 0x40, 0x2A, 0x08,
+0x5B, 0xBE, 0x84, 0x80, 0x00, 0x48, 0xA1, 0xC0, 0x2A, 0x08, 0xA2, 0xC0, 0x04, 0xF0, 0xF0, 0x27,
+0x8A, 0x95, 0x2A, 0x08, 0x59, 0x7E, 0x84, 0x80, 0x00, 0x48, 0xA1, 0xC0, 0x2A, 0x08, 0xA2, 0xC0,
+0x05, 0x30, 0xF0, 0x27, 0x8A, 0x95, 0x2A, 0x08, 0x57, 0xBE, 0x84, 0x80, 0x00, 0x48, 0xA1, 0xC0,
+0x2A, 0x08, 0xA2, 0xC0, 0x06, 0x30, 0xF0, 0x27, 0x8A, 0x95, 0xA1, 0x01, 0xA1, 0x4A, 0x2A, 0x08,
+0xA2, 0xC0, 0x00, 0xB0, 0xF0, 0x27, 0x8A, 0x95, 0xE4, 0xB0, 0xAB, 0x40, 0xE7, 0xAD, 0xE8, 0x2D,
+0xAB, 0x0B, 0xE6, 0x6D, 0xEB, 0xAD, 0x00, 0x00, 0x0F, 0xB0, 0x83, 0x52, 0x03, 0x53, 0xA1, 0xC0,
+0x2A, 0x08, 0xA2, 0xC0, 0x00, 0xB0, 0xF0, 0x27, 0x8A, 0x95, 0xD0, 0x70, 0xAC, 0x00, 0xC9, 0xB0,
+0xAB, 0x40, 0xAB, 0x0B, 0xF9, 0xAD, 0xAC, 0xCB, 0xF9, 0xAD, 0xFE, 0xED, 0x83, 0x52, 0x03, 0x53,
+0x2A, 0x08, 0x03, 0xAD, 0xAC, 0x00, 0x2C, 0x08, 0x03, 0x59, 0x0A, 0xAE, 0xAD, 0x81, 0xAD, 0xCA,
+0xAE, 0x81, 0x0D, 0xEE, 0xAD, 0x81, 0xAE, 0x81, 0xAE, 0xCA, 0x83, 0x96, 0xED, 0xC1, 0x0E, 0x70,
+0x83, 0x52, 0xEF, 0xC0, 0x02, 0xF0, 0xEE, 0x80, 0x2D, 0x48, 0xAA, 0xE6, 0x8A, 0x95, 0x2E, 0x48,
+0xAA, 0xE6, 0x8A, 0x95, 0x2D, 0x48, 0xE2, 0x7E, 0x84, 0x80, 0x00, 0x48, 0xAA, 0x00, 0x2E, 0x48,
+0x5B, 0xBE, 0x84, 0x80, 0x2A, 0x08, 0x80, 0x40, 0x66, 0x5F, 0x2C, 0xEE, 0x2D, 0x48, 0x55, 0x7E,
+0x84, 0x80, 0x00, 0x48, 0x28, 0xFE, 0x31, 0xEE, 0x2D, 0x48, 0x55, 0x7E, 0x84, 0x80, 0x00, 0x48,
+0x14, 0xFE, 0xAA, 0x00, 0x2E, 0x48, 0x59, 0x7E, 0x84, 0x80, 0x2A, 0x08, 0x80, 0x40, 0x2D, 0x48,
+0x55, 0x7E, 0x84, 0x80, 0x00, 0x48, 0xAA, 0x00, 0x2E, 0x48, 0x59, 0x7E, 0x84, 0x80, 0x00, 0x48,
+0xAB, 0x40, 0x2A, 0x08, 0x2B, 0x42, 0x03, 0x18, 0x4F, 0x6E, 0x2E, 0x48, 0x5B, 0xBE, 0x84, 0x80,
+0x00, 0x8A, 0xAA, 0x00, 0x2E, 0x48, 0x5B, 0xBE, 0x84, 0x80, 0x2A, 0x08, 0x80, 0x40, 0x2D, 0x48,
+0xDC, 0xBE, 0x84, 0x80, 0x00, 0x48, 0xAA, 0x00, 0x2E, 0x48, 0x57, 0xBE, 0x84, 0x80, 0x2A, 0x08,
+0x80, 0x40, 0x2E, 0x48, 0x5B, 0xBE, 0x84, 0x80, 0x00, 0x48, 0xA1, 0xC0, 0x2E, 0x48, 0xA2, 0xC0,
+0x04, 0xF0, 0xF0, 0x27, 0x8A, 0x95, 0x2E, 0x48, 0x59, 0x7E, 0x84, 0x80, 0x00, 0x48, 0xA1, 0xC0,
+0x2E, 0x48, 0xA2, 0xC0, 0x05, 0x30, 0xF0, 0x27, 0x8A, 0x95, 0x2E, 0x48, 0x57, 0xBE, 0x84, 0x80,
+0x00, 0x48, 0xA1, 0xC0, 0x2E, 0x48, 0xA2, 0xC0, 0x06, 0x30, 0xF0, 0x27, 0x8A, 0x95, 0xA1, 0x01,
+0xA1, 0x4A, 0x2D, 0x48, 0xA2, 0xC0, 0x00, 0xB0, 0xF0, 0x27, 0x8A, 0x95, 0xA1, 0x01, 0xA1, 0x4A,
+0x2E, 0x48, 0xA2, 0xC0, 0x00, 0xB0, 0xF0, 0x27, 0x8A, 0x95, 0xE4, 0xB0, 0xAA, 0x00, 0x88, 0xAE,
+0x89, 0xEE, 0xAA, 0xCB, 0x87, 0x2E, 0x8C, 0xEE, 0x00, 0x00, 0x03, 0x30, 0x83, 0x52, 0x03, 0x53,
+0xA1, 0xC0, 0x2D, 0x48, 0xA2, 0xC0, 0x00, 0xB0, 0xF0, 0x27, 0x8A, 0x95, 0x0D, 0x70, 0xA1, 0xC0,
+0x2E, 0x48, 0xA2, 0xC0, 0x00, 0xB0, 0xF0, 0x27, 0x8A, 0x95, 0xD0, 0x70, 0xAB, 0x40, 0xC9, 0xB0,
+0xAA, 0x00, 0xAA, 0xCB, 0xA1, 0xEE, 0xAB, 0x0B, 0xA1, 0xEE, 0xA6, 0x2E, 0x83, 0x52, 0x03, 0x53,
+0x2D, 0x48, 0x03, 0xAD, 0xA6, 0x00, 0xE2, 0x7E, 0x84, 0x80, 0x83, 0x93, 0x00, 0x48, 0xA1, 0xC0,
+0x26, 0x08, 0xA2, 0xC0, 0x01, 0xF0, 0xF0, 0x27, 0x8A, 0x95, 0x26, 0x08, 0x55, 0x7E, 0x84, 0x80,
+0x00, 0x48, 0xA1, 0xC0, 0x26, 0x08, 0xA2, 0xC0, 0x02, 0xF0, 0xF0, 0x27, 0x8A, 0x95, 0x26, 0x08,
+0xDC, 0xBE, 0x84, 0x80, 0x00, 0x48, 0xA1, 0xC0, 0x26, 0x08, 0xA2, 0xC0, 0x03, 0x30, 0xF0, 0x27,
+0x8A, 0x95, 0x26, 0x08, 0x5B, 0xBE, 0x84, 0x80, 0x00, 0x48, 0xA1, 0xC0, 0x26, 0x08, 0xA2, 0xC0,
+0x04, 0xF0, 0xF0, 0x27, 0x8A, 0x95, 0x26, 0x08, 0x59, 0x7E, 0x84, 0x80, 0x00, 0x48, 0xA1, 0xC0,
+0x26, 0x08, 0xA2, 0xC0, 0x05, 0x30, 0xF0, 0x27, 0x8A, 0x95, 0x26, 0x08, 0x57, 0xBE, 0x84, 0x80,
+0x00, 0x48, 0xA1, 0xC0, 0x26, 0x08, 0xA2, 0xC0, 0x06, 0x30, 0xF0, 0x27, 0x8A, 0x95, 0x6E, 0x0E,
+0xF0, 0x39, 0x6F, 0xC4, 0xA1, 0xC0, 0x26, 0x08, 0xA2, 0xC0, 0x08, 0xF0, 0xF0, 0x27, 0x8A, 0x95,
+0x62, 0x08, 0xA4, 0xC0, 0x04, 0xF0, 0x03, 0xD0, 0xA4, 0x8D, 0xFF, 0x7E, 0x03, 0xD0, 0x03, 0x9D,
+0xF4, 0x6E, 0x24, 0x4D, 0x60, 0xC4, 0xA1, 0xC0, 0x26, 0x08, 0xA2, 0xC0, 0x0A, 0x30, 0xF0, 0x27,
+0x8A, 0x95, 0x6D, 0x88, 0xA1, 0xC0, 0x26, 0x08, 0xA2, 0xC0, 0x0B, 0x70, 0xF0, 0x27, 0x8A, 0x95,
+0x6C, 0x48, 0xA4, 0xC0, 0x05, 0x30, 0x03, 0xD0, 0xA4, 0x8D, 0xFF, 0x7E, 0x03, 0xD0, 0x03, 0x9D,
+0x0C, 0xEF, 0x6B, 0x0D, 0x24, 0xC4, 0x68, 0x04, 0xA1, 0xC0, 0x26, 0x08, 0xA2, 0xC0, 0x0C, 0x30,
+0xF0, 0x27, 0x8A, 0x95, 0x69, 0x48, 0xA4, 0xC0, 0x05, 0x30, 0x03, 0xD0, 0xA4, 0x8D, 0xFF, 0x7E,
+0x03, 0x9D, 0x1D, 0x6F, 0x6A, 0x48, 0xA5, 0x00, 0x01, 0xF0, 0x03, 0xD0, 0xA5, 0xCD, 0xFF, 0x7E,
+0x03, 0xD0, 0x03, 0x9D, 0x26, 0x2F, 0x25, 0x8D, 0x24, 0xC4, 0x5E, 0x84, 0xA1, 0xC0, 0x26, 0x08,
+0xA2, 0xC0, 0x0D, 0x70, 0xF0, 0x27, 0x8A, 0x95, 0x03, 0xD0, 0x5F, 0x4D, 0x5D, 0x84, 0xA1, 0xC0,
+0x26, 0x08, 0xA2, 0xC0, 0x0E, 0x70, 0xF0, 0x27, 0x8A, 0x95, 0x83, 0x96, 0x6C, 0x48, 0x83, 0x52,
+0xA4, 0xC0, 0x03, 0xD0, 0xA4, 0x8D, 0x03, 0xD0, 0xA4, 0x8D, 0x03, 0xD0, 0xA4, 0x8D, 0x83, 0x96,
+0x6D, 0x88, 0x83, 0x52, 0xA5, 0x00, 0x03, 0xD0, 0xA5, 0xCD, 0x03, 0xD0, 0xA5, 0xCD, 0x83, 0x96,
+0x03, 0xD0, 0x6E, 0x0D, 0x83, 0x52, 0x25, 0x04, 0x24, 0xC4, 0x61, 0x04, 0xA1, 0xC0, 0x26, 0x08,
+0xA2, 0xC0, 0x10, 0xF0, 0xF0, 0x6F, 0xA4, 0x01, 0x24, 0xC8, 0xEA, 0xBE, 0x84, 0x80, 0x83, 0x93,
+0x00, 0x48, 0xA1, 0xC0, 0x24, 0xC8, 0xA2, 0xC0, 0x00, 0xB0, 0xF0, 0x27, 0x8A, 0x95, 0x24, 0xC8,
+0xE0, 0x3E, 0x84, 0x80, 0x00, 0x48, 0xA1, 0xC0, 0x24, 0xC8, 0xA2, 0xC0, 0x01, 0xF0, 0xF0, 0x27,
+0x8A, 0x95, 0x24, 0xC8, 0xDE, 0xFE, 0x84, 0x80, 0x00, 0x48, 0xA1, 0xC0, 0x24, 0xC8, 0xA2, 0xC0,
+0x02, 0xF0, 0xF0, 0x27, 0x8A, 0x95, 0x24, 0xC8, 0xDA, 0xBE, 0x84, 0x80, 0x00, 0x48, 0xA1, 0xC0,
+0x24, 0xC8, 0xA2, 0xC0, 0x03, 0x30, 0xF0, 0x27, 0x8A, 0x95, 0x24, 0xC8, 0xE8, 0x7E, 0x84, 0x80,
+0x00, 0x48, 0xA1, 0xC0, 0x24, 0xC8, 0xA2, 0xC0, 0x04, 0xF0, 0xF0, 0x27, 0x8A, 0x95, 0x24, 0xC8,
+0xE6, 0xBE, 0x84, 0x80, 0x00, 0x48, 0xA1, 0xC0, 0x24, 0xC8, 0xA2, 0xC0, 0x05, 0x30, 0xF0, 0x27,
+0x8A, 0x95, 0x24, 0xC8, 0xE4, 0x7E, 0x84, 0x80, 0x00, 0x48, 0xA1, 0xC0, 0x24, 0xC8, 0xA2, 0xC0,
+0x06, 0x30, 0xF0, 0x27, 0x8A, 0x95, 0x24, 0xC8, 0xAC, 0x7E, 0x84, 0x80, 0x83, 0xD7, 0x00, 0x48,
+0xA1, 0xC0, 0x24, 0xC8, 0xA2, 0xC0, 0x08, 0xF0, 0xF0, 0x27, 0x8A, 0x95, 0x24, 0xC8, 0xA8, 0x3E,
+0x84, 0x80, 0x00, 0x48, 0xA1, 0xC0, 0x24, 0xC8, 0xA2, 0xC0, 0x0A, 0x30, 0xF0, 0x27, 0x8A, 0x95,
+0x24, 0xC8, 0xAA, 0x7E, 0x84, 0x80, 0x00, 0x48, 0xA1, 0xC0, 0x24, 0xC8, 0xA2, 0xC0, 0x0B, 0x70,
+0xF0, 0x27, 0x8A, 0x95, 0x24, 0xC8, 0xA2, 0x3E, 0x84, 0x80, 0x00, 0x48, 0xA1, 0xC0, 0x24, 0xC8,
+0xA2, 0xC0, 0x0C, 0x30, 0xF0, 0x27, 0x8A, 0x95, 0x24, 0xC8, 0xA4, 0x3E, 0x84, 0x80, 0x00, 0x48,
+0xA1, 0xC0, 0x24, 0xC8, 0xA2, 0xC0, 0x0D, 0x70, 0xF0, 0x27, 0x8A, 0x95, 0x24, 0xC8, 0xA6, 0x7E,
+0x84, 0x80, 0x00, 0x48, 0xA1, 0xC0, 0x24, 0xC8, 0xA2, 0xC0, 0x0E, 0x70, 0xF0, 0x27, 0x8A, 0x95,
+0x24, 0xC8, 0xA0, 0xFE, 0x84, 0x80, 0x00, 0x48, 0xA1, 0xC0, 0x24, 0xC8, 0xA2, 0xC0, 0x10, 0xF0,
+0xF0, 0x27, 0x8A, 0x95, 0x02, 0xF0, 0xA4, 0x4A, 0x24, 0xC2, 0x03, 0x18, 0x08, 0x40, 0x5C, 0x6F,
+0xA3, 0x00, 0x22, 0xC8, 0x03, 0x59, 0xFA, 0xEF, 0x21, 0xC8, 0x88, 0x80, 0x23, 0x08, 0x80, 0x38,
+0x86, 0xC0, 0x08, 0x40, 0x21, 0xC8, 0x88, 0x80, 0x23, 0x08, 0x80, 0x38, 0x85, 0xC0, 0x08, 0x40
+};
diff --git a/libloragw/src/loragw_aux.c b/libloragw/src/loragw_aux.c
new file mode 100644
index 0000000..c921296
--- /dev/null
+++ b/libloragw/src/loragw_aux.c
@@ -0,0 +1,61 @@
+/*
+ / _____) _ | |
+( (____ _____ ____ _| |_ _____ ____| |__
+ \____ \| ___ | (_ _) ___ |/ ___) _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+ (C)2013 Semtech-Cycleo
+
+Description:
+ LoRa concentrator HAL auxiliary functions
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+Maintainer: Sylvain Miermont
+*/
+
+
+/* -------------------------------------------------------------------------- */
+/* --- DEPENDANCIES --------------------------------------------------------- */
+
+/* fix an issue between POSIX and C99 */
+#if __STDC_VERSION__ >= 199901L
+ #define _XOPEN_SOURCE 600
+#else
+ #define _XOPEN_SOURCE 500
+#endif
+
+#include <stdio.h> /* printf fprintf */
+#include <time.h> /* clock_nanosleep */
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE MACROS ------------------------------------------------------- */
+
+#if DEBUG_AUX == 1
+ #define DEBUG_MSG(str) fprintf(stderr, str)
+ #define DEBUG_PRINTF(fmt, args...) fprintf(stderr,"%s:%d: "fmt, __FUNCTION__, __LINE__, args)
+#else
+ #define DEBUG_MSG(str)
+ #define DEBUG_PRINTF(fmt, args...)
+#endif
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC FUNCTIONS DEFINITION ------------------------------------------ */
+
+/* This implementation is POSIX-pecific and require a fix to be compatible with C99 */
+void wait_ms(unsigned long a) {
+ struct timespec dly;
+ struct timespec rem;
+
+ dly.tv_sec = a / 1000;
+ dly.tv_nsec = ((long)a % 1000) * 1000000;
+
+ DEBUG_PRINTF("NOTE dly: %ld sec %ld ns\n", dly.tv_sec, dly.tv_nsec);
+
+ if((dly.tv_sec > 0) || ((dly.tv_sec == 0) && (dly.tv_nsec > 100000))) {
+ clock_nanosleep(CLOCK_MONOTONIC, 0, &dly, &rem);
+ DEBUG_PRINTF("NOTE remain: %ld sec %ld ns\n", rem.tv_sec, rem.tv_nsec);
+ }
+ return;
+}
+
+/* --- EOF ------------------------------------------------------------------ */
diff --git a/libloragw/src/loragw_fpga.c b/libloragw/src/loragw_fpga.c
new file mode 100644
index 0000000..465f43e
--- /dev/null
+++ b/libloragw/src/loragw_fpga.c
@@ -0,0 +1,352 @@
+/*
+ / _____) _ | |
+( (____ _____ ____ _| |_ _____ ____| |__
+ \____ \| ___ | (_ _) ___ |/ ___) _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+ (C)2013 Semtech-Cycleo
+
+Description:
+ Functions used to handle FPGA register access for LoRa concentrator.
+ Registers are addressed by name.
+ Multi-bytes registers are handled automatically.
+ Read-modify-write is handled automatically.
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+Maintainer: Michael Coracin
+*/
+
+/* -------------------------------------------------------------------------- */
+/* --- DEPENDANCIES --------------------------------------------------------- */
+
+#include <stdint.h> /* C99 types */
+#include <stdbool.h> /* bool type */
+#include <stdio.h> /* printf fprintf */
+
+#include "loragw_spi.h"
+#include "loragw_aux.h"
+#include "loragw_hal.h"
+#include "loragw_reg.h"
+#include "loragw_fpga.h"
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE MACROS ------------------------------------------------------- */
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+#if DEBUG_REG == 1
+ #define DEBUG_MSG(str) fprintf(stderr, str)
+ #define DEBUG_PRINTF(fmt, args...) fprintf(stderr,"%s:%d: "fmt, __FUNCTION__, __LINE__, args)
+ #define CHECK_NULL(a) if(a==NULL){fprintf(stderr,"%s:%d: ERROR: NULL POINTER AS ARGUMENT\n", __FUNCTION__, __LINE__);return LGW_REG_ERROR;}
+#else
+ #define DEBUG_MSG(str)
+ #define DEBUG_PRINTF(fmt, args...)
+ #define CHECK_NULL(a) if(a==NULL){return LGW_REG_ERROR;}
+#endif
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE CONSTANTS ---------------------------------------------------- */
+
+/*
+auto generated register mapping for C code : 11-Jul-2013 13:20:40
+this file contains autogenerated C struct used to access the LoRa register from the Primer firmware
+this file is autogenerated from registers description
+293 registers are defined
+*/
+const struct lgw_reg_s fpga_regs[LGW_FPGA_TOTALREGS] = {
+ {-1,0,0,0,1,0,0}, /* SOFT_RESET */
+ {-1,0,1,0,4,1,0}, /* FPGA_FEATURE */
+ {-1,0,5,0,3,1,0}, /* LBT_INITIAL_FREQ */
+ {-1,1,0,0,8,1,0}, /* VERSION */
+ {-1,2,0,0,8,1,0}, /* FPGA_STATUS */
+ {-1,3,0,0,1,0,0}, /* FPGA_CTRL_FEATURE_START */
+ {-1,3,1,0,1,0,0}, /* FPGA_CTRL_RADIO_RESET */
+ {-1,3,2,0,1,0,0}, /* FPGA_CTRL_INPUT_SYNC_I */
+ {-1,3,3,0,1,0,0}, /* FPGA_CTRL_INPUT_SYNC_Q */
+ {-1,3,4,0,1,0,0}, /* FPGA_CTRL_OUTPUT_SYNC */
+ {-1,3,5,0,1,0,0}, /* FPGA_CTRL_INVERT_IQ */
+ {-1,3,6,0,1,0,0}, /* FPGA_CTRL_ACCESS_HISTO_MEM */
+ {-1,3,7,0,1,0,0}, /* FPGA_CTRL_CLEAR_HISTO_MEM */
+ {-1,4,0,0,8,0,0}, /* HISTO_RAM_ADDR */
+ {-1,5,0,0,8,1,0}, /* HISTO_RAM_DATA */
+ {-1,8,0,0,16,0,1000}, /* HISTO_NB_READ */
+ {-1,14,0,0,16,1,0}, /* LBT_TIMESTAMP_CH */
+ {-1,17,0,0,4,0,0}, /* LBT_TIMESTAMP_SELECT_CH */
+ {-1,18,0,0,8,0,0}, /* LBT_CH0_FREQ_OFFSET */
+ {-1,19,0,0,8,0,0}, /* LBT_CH1_FREQ_OFFSET */
+ {-1,20,0,0,8,0,0}, /* LBT_CH2_FREQ_OFFSET */
+ {-1,21,0,0,8,0,0}, /* LBT_CH3_FREQ_OFFSET */
+ {-1,22,0,0,8,0,0}, /* LBT_CH4_FREQ_OFFSET */
+ {-1,23,0,0,8,0,0}, /* LBT_CH5_FREQ_OFFSET */
+ {-1,24,0,0,8,0,0}, /* LBT_CH6_FREQ_OFFSET */
+ {-1,25,0,0,8,0,0}, /* LBT_CH7_FREQ_OFFSET */
+ {-1,26,0,0,8,0,0}, /* SCAN_FREQ_OFFSET */
+ {-1,28,0,0,1,0,0}, /* LBT_SCAN_TIME_CH0 */
+ {-1,28,1,0,1,0,0}, /* LBT_SCAN_TIME_CH1 */
+ {-1,28,2,0,1,0,0}, /* LBT_SCAN_TIME_CH2 */
+ {-1,28,3,0,1,0,0}, /* LBT_SCAN_TIME_CH3 */
+ {-1,28,4,0,1,0,0}, /* LBT_SCAN_TIME_CH4 */
+ {-1,28,5,0,1,0,0}, /* LBT_SCAN_TIME_CH5 */
+ {-1,28,6,0,1,0,0}, /* LBT_SCAN_TIME_CH6 */
+ {-1,28,7,0,1,0,0}, /* LBT_SCAN_TIME_CH7 */
+ {-1,30,0,0,8,0,160}, /* RSSI_TARGET */
+ {-1,31,0,0,24,0,0}, /* HISTO_SCAN_FREQ */
+ {-1,34,0,0,6,0,0} /* NOTCH_FREQ_OFFSET */
+};
+
+/* -------------------------------------------------------------------------- */
+/* --- INTERNAL SHARED VARIABLES -------------------------------------------- */
+
+extern void *lgw_spi_target; /*! generic pointer to the SPI device */
+extern uint8_t lgw_spi_mux_mode; /*! current SPI mux mode used */
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE VARIABLES ---------------------------------------------------- */
+static bool tx_notch_support = false;
+static uint8_t tx_notch_offset;
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE FUNCTIONS ---------------------------------------------------- */
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE FUNCTIONS DEFINITION ----------------------------------------- */
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC FUNCTIONS DEFINITION ------------------------------------------ */
+
+float lgw_fpga_get_tx_notch_delay(void) {
+ float tx_notch_delay;
+
+ if (tx_notch_support == false) {
+ return 0;
+ }
+
+ /* Notch filtering performed by FPGA adds a constant delay (group delay) that we need to compensate */
+ tx_notch_delay = (31.25 * ((64 + tx_notch_offset) / 2)) / 1E3; /* 32MHz => 31.25ns */
+
+ return tx_notch_delay;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int lgw_fpga_configure(uint32_t tx_notch_freq) {
+ int x;
+ int32_t val;
+ bool spectral_scan_support, lbt_support;
+
+ /* Check input parameters */
+ if ((tx_notch_freq < LGW_MIN_NOTCH_FREQ) || (tx_notch_freq > LGW_MAX_NOTCH_FREQ)) {
+ DEBUG_PRINTF("WARNING: FPGA TX notch frequency is out of range (%u - [%u..%u]), setting it to default (%u)\n", tx_notch_freq, LGW_MIN_NOTCH_FREQ, LGW_MAX_NOTCH_FREQ, LGW_DEFAULT_NOTCH_FREQ);
+ tx_notch_freq = LGW_DEFAULT_NOTCH_FREQ;
+ }
+
+ /* Get supported FPGA features */
+ printf("INFO: FPGA supported features:");
+ lgw_fpga_reg_r(LGW_FPGA_FEATURE, &val);
+ tx_notch_support = TAKE_N_BITS_FROM((uint8_t)val, 0, 1);
+ if (tx_notch_support == true) {
+ printf(" [TX filter] ");
+ }
+ spectral_scan_support = TAKE_N_BITS_FROM((uint8_t)val, 1, 1);
+ if (spectral_scan_support == true) {
+ printf(" [Spectral Scan] ");
+ }
+ lbt_support = TAKE_N_BITS_FROM((uint8_t)val, 2, 1);
+ if (lbt_support == true) {
+ printf(" [LBT] ");
+ }
+ printf("\n");
+
+ x = lgw_fpga_reg_w(LGW_FPGA_CTRL_INPUT_SYNC_I, 1);
+ x |= lgw_fpga_reg_w(LGW_FPGA_CTRL_INPUT_SYNC_Q, 1);
+ x |= lgw_fpga_reg_w(LGW_FPGA_CTRL_OUTPUT_SYNC, 0);
+ if (x != LGW_REG_SUCCESS) {
+ DEBUG_MSG("ERROR: Failed to configure FPGA TX synchro\n");
+ return LGW_REG_ERROR;
+ }
+
+ /* Required for Semtech AP2 reference design */
+ x = lgw_fpga_reg_w(LGW_FPGA_CTRL_INVERT_IQ, 1);
+ if (x != LGW_REG_SUCCESS) {
+ DEBUG_MSG("ERROR: Failed to configure FPGA polarity\n");
+ return LGW_REG_ERROR;
+ }
+
+ /* Configure TX notch filter */
+ if (tx_notch_support == true) {
+ tx_notch_offset = (32E6 / (2*tx_notch_freq)) - 64;
+ x = lgw_fpga_reg_w(LGW_FPGA_NOTCH_FREQ_OFFSET, (int32_t)tx_notch_offset);
+ if (x != LGW_REG_SUCCESS) {
+ DEBUG_MSG("ERROR: Failed to configure FPGA TX notch filter\n");
+ return LGW_REG_ERROR;
+ }
+
+ /* Readback to check that notch frequency is programmable */
+ x = lgw_fpga_reg_r(LGW_FPGA_NOTCH_FREQ_OFFSET, &val);
+ if (x != LGW_REG_SUCCESS) {
+ DEBUG_MSG("ERROR: Failed to read FPGA TX notch frequency\n");
+ return LGW_REG_ERROR;
+ }
+ if (val != tx_notch_offset) {
+ DEBUG_MSG("WARNING: TX notch filter frequency is not programmable (check your FPGA image)\n");
+ } else {
+ DEBUG_PRINTF("INFO: TX notch filter frequency set to %u (%i)\n", tx_notch_freq, tx_notch_offset);
+ }
+ }
+
+ return LGW_REG_SUCCESS;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+/* Write to a register addressed by name */
+int lgw_fpga_reg_w(uint16_t register_id, int32_t reg_value) {
+ int spi_stat = LGW_SPI_SUCCESS;
+ struct lgw_reg_s r;
+
+ /* check input parameters */
+ if (register_id >= LGW_FPGA_TOTALREGS) {
+ DEBUG_MSG("ERROR: REGISTER NUMBER OUT OF DEFINED RANGE\n");
+ return LGW_REG_ERROR;
+ }
+
+ /* check if SPI is initialised */
+ if (lgw_spi_target == NULL) {
+ DEBUG_MSG("ERROR: CONCENTRATOR UNCONNECTED\n");
+ return LGW_REG_ERROR;
+ }
+
+ /* get register struct from the struct array */
+ r = fpga_regs[register_id];
+
+ /* reject write to read-only registers */
+ if (r.rdon == 1){
+ DEBUG_MSG("ERROR: TRYING TO WRITE A READ-ONLY REGISTER\n");
+ return LGW_REG_ERROR;
+ }
+
+ spi_stat += reg_w_align32(lgw_spi_target, LGW_SPI_MUX_MODE1, LGW_SPI_MUX_TARGET_FPGA, r, reg_value);
+
+ if (spi_stat != LGW_SPI_SUCCESS) {
+ DEBUG_MSG("ERROR: SPI ERROR DURING REGISTER WRITE\n");
+ return LGW_REG_ERROR;
+ } else {
+ return LGW_REG_SUCCESS;
+ }
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+/* Read to a register addressed by name */
+int lgw_fpga_reg_r(uint16_t register_id, int32_t *reg_value) {
+ int spi_stat = LGW_SPI_SUCCESS;
+ struct lgw_reg_s r;
+
+ /* check input parameters */
+ CHECK_NULL(reg_value);
+ if (register_id >= LGW_FPGA_TOTALREGS) {
+ DEBUG_MSG("ERROR: REGISTER NUMBER OUT OF DEFINED RANGE\n");
+ return LGW_REG_ERROR;
+ }
+
+ /* check if SPI is initialised */
+ if (lgw_spi_target == NULL) {
+ DEBUG_MSG("ERROR: CONCENTRATOR UNCONNECTED\n");
+ return LGW_REG_ERROR;
+ }
+
+ /* get register struct from the struct array */
+ r = fpga_regs[register_id];
+
+ spi_stat += reg_r_align32(lgw_spi_target, LGW_SPI_MUX_MODE1, LGW_SPI_MUX_TARGET_FPGA, r, reg_value);
+
+ if (spi_stat != LGW_SPI_SUCCESS) {
+ DEBUG_MSG("ERROR: SPI ERROR DURING REGISTER WRITE\n");
+ return LGW_REG_ERROR;
+ } else {
+ return LGW_REG_SUCCESS;
+ }
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+/* Point to a register by name and do a burst write */
+int lgw_fpga_reg_wb(uint16_t register_id, uint8_t *data, uint16_t size) {
+ int spi_stat = LGW_SPI_SUCCESS;
+ struct lgw_reg_s r;
+
+ /* check input parameters */
+ CHECK_NULL(data);
+ if (size == 0) {
+ DEBUG_MSG("ERROR: BURST OF NULL LENGTH\n");
+ return LGW_REG_ERROR;
+ }
+ if (register_id >= LGW_FPGA_TOTALREGS) {
+ DEBUG_MSG("ERROR: REGISTER NUMBER OUT OF DEFINED RANGE\n");
+ return LGW_REG_ERROR;
+ }
+
+ /* check if SPI is initialised */
+ if (lgw_spi_target == NULL) {
+ DEBUG_MSG("ERROR: CONCENTRATOR UNCONNECTED\n");
+ return LGW_REG_ERROR;
+ }
+
+ /* get register struct from the struct array */
+ r = fpga_regs[register_id];
+
+ /* reject write to read-only registers */
+ if (r.rdon == 1){
+ DEBUG_MSG("ERROR: TRYING TO BURST WRITE A READ-ONLY REGISTER\n");
+ return LGW_REG_ERROR;
+ }
+
+ /* do the burst write */
+ spi_stat += lgw_spi_wb(lgw_spi_target, LGW_SPI_MUX_MODE1, LGW_SPI_MUX_TARGET_FPGA, r.addr, data, size);
+
+ if (spi_stat != LGW_SPI_SUCCESS) {
+ DEBUG_MSG("ERROR: SPI ERROR DURING REGISTER BURST WRITE\n");
+ return LGW_REG_ERROR;
+ } else {
+ return LGW_REG_SUCCESS;
+ }
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+/* Point to a register by name and do a burst read */
+int lgw_fpga_reg_rb(uint16_t register_id, uint8_t *data, uint16_t size) {
+ int spi_stat = LGW_SPI_SUCCESS;
+ struct lgw_reg_s r;
+
+ /* check input parameters */
+ CHECK_NULL(data);
+ if (size == 0) {
+ DEBUG_MSG("ERROR: BURST OF NULL LENGTH\n");
+ return LGW_REG_ERROR;
+ }
+ if (register_id >= LGW_FPGA_TOTALREGS) {
+ DEBUG_MSG("ERROR: REGISTER NUMBER OUT OF DEFINED RANGE\n");
+ return LGW_REG_ERROR;
+ }
+
+ /* check if SPI is initialised */
+ if (lgw_spi_target == NULL) {
+ DEBUG_MSG("ERROR: CONCENTRATOR UNCONNECTED\n");
+ return LGW_REG_ERROR;
+ }
+
+ /* get register struct from the struct array */
+ r = fpga_regs[register_id];
+
+ /* do the burst read */
+ spi_stat += lgw_spi_rb(lgw_spi_target, LGW_SPI_MUX_MODE1, LGW_SPI_MUX_TARGET_FPGA, r.addr, data, size);
+
+ if (spi_stat != LGW_SPI_SUCCESS) {
+ DEBUG_MSG("ERROR: SPI ERROR DURING REGISTER BURST READ\n");
+ return LGW_REG_ERROR;
+ } else {
+ return LGW_REG_SUCCESS;
+ }
+}
+
+/* --- EOF ------------------------------------------------------------------ */
diff --git a/libloragw/src/loragw_gps.c b/libloragw/src/loragw_gps.c
new file mode 100644
index 0000000..c0e0ded
--- /dev/null
+++ b/libloragw/src/loragw_gps.c
@@ -0,0 +1,835 @@
+/*
+ / _____) _ | |
+( (____ _____ ____ _| |_ _____ ____| |__
+ \____ \| ___ | (_ _) ___ |/ ___) _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+ (C)2013 Semtech-Cycleo
+
+Description:
+ Library of functions to manage a GNSS module (typically GPS) for accurate
+ timestamping of packets and synchronisation of gateways.
+ A limited set of module brands/models are supported.
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+Maintainer: Michael Coracin
+*/
+
+
+/* -------------------------------------------------------------------------- */
+/* --- DEPENDANCIES --------------------------------------------------------- */
+
+#define _GNU_SOURCE /* needed for qsort_r to be defined */
+#include <stdint.h> /* C99 types */
+#include <stdbool.h> /* bool type */
+#include <stdio.h> /* printf fprintf */
+#include <string.h> /* memcpy */
+
+#include <time.h> /* struct timespec */
+#include <fcntl.h> /* open */
+#include <termios.h> /* tcflush */
+#include <math.h> /* modf */
+
+#include <stdlib.h>
+
+#include "loragw_gps.h"
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE MACROS ------------------------------------------------------- */
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+#if DEBUG_GPS == 1
+ #define DEBUG_MSG(args...) fprintf(stderr, args)
+ #define DEBUG_ARRAY(a,b,c) for(a=0;a<b;++a) fprintf(stderr,"%x.",c[a]);fprintf(stderr,"end\n")
+ #define CHECK_NULL(a) if(a==NULL){fprintf(stderr,"%s:%d: ERROR: NULL POINTER AS ARGUMENT\n", __FUNCTION__, __LINE__);return LGW_GPS_ERROR;}
+#else
+ #define DEBUG_MSG(args...)
+ #define DEBUG_ARRAY(a,b,c) for(a=0;a!=0;){}
+ #define CHECK_NULL(a) if(a==NULL){return LGW_GPS_ERROR;}
+#endif
+#define TRACE() fprintf(stderr, "@ %s %d\n", __FUNCTION__, __LINE__);
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE CONSTANTS ---------------------------------------------------- */
+
+#define TS_CPS 1E6 /* count-per-second of the timestamp counter */
+#define PLUS_10PPM 1.00001
+#define MINUS_10PPM 0.99999
+#define DEFAULT_BAUDRATE B9600
+
+#define UBX_MSG_NAVTIMEGPS_LEN 16
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE VARIABLES ---------------------------------------------------- */
+
+
+/* result of the NMEA parsing */
+static short gps_yea = 0; /* year (2 or 4 digits) */
+static short gps_mon = 0; /* month (1-12) */
+static short gps_day = 0; /* day of the month (1-31) */
+static short gps_hou = 0; /* hours (0-23) */
+static short gps_min = 0; /* minutes (0-59) */
+static short gps_sec = 0; /* seconds (0-60)(60 is for leap second) */
+static float gps_fra = 0.0; /* fractions of seconds (<1) */
+static bool gps_time_ok = false;
+static int16_t gps_week = 0; /* GPS week number of the navigation epoch */
+static uint32_t gps_iTOW = 0; /* GPS time of week in milliseconds */
+static int32_t gps_fTOW = 0; /* Fractional part of iTOW (+/-500000) in nanosec */
+
+static short gps_dla = 0; /* degrees of latitude */
+static double gps_mla = 0.0; /* minutes of latitude */
+static char gps_ola = 0; /* orientation (N-S) of latitude */
+static short gps_dlo = 0; /* degrees of longitude */
+static double gps_mlo = 0.0; /* minutes of longitude */
+static char gps_olo = 0; /* orientation (E-W) of longitude */
+static short gps_alt = 0; /* altitude */
+static bool gps_pos_ok = false;
+
+static char gps_mod = 'N'; /* GPS mode (N no fix, A autonomous, D differential) */
+static short gps_sat = 0; /* number of satellites used for fix */
+
+static struct termios ttyopt_restore;
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE FUNCTIONS DECLARATION ---------------------------------------- */
+
+static int nmea_checksum(const char *nmea_string, int buff_size, char *checksum);
+
+static char nibble_to_hexchar(uint8_t a);
+
+static bool validate_nmea_checksum(const char *serial_buff, int buff_size);
+
+static bool match_label(const char *s, char *label, int size, char wildcard);
+
+static int str_chop(char *s, int buff_size, char separator, int *idx_ary, int max_idx);
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE FUNCTIONS DEFINITION ----------------------------------------- */
+
+/*
+Calculate the checksum for a NMEA string
+Skip the first '$' if necessary and calculate checksum until '*' character is
+reached (or buff_size exceeded).
+Checksum must point to a 2-byte (or more) char array.
+Return position of the checksum in the string
+*/
+static int nmea_checksum(const char *nmea_string, int buff_size, char *checksum) {
+ int i = 0;
+ uint8_t check_num = 0;
+
+ /* check input parameters */
+ if ((nmea_string == NULL) || (checksum == NULL) || (buff_size <= 1)) {
+ DEBUG_MSG("Invalid parameters for nmea_checksum\n");
+ return -1;
+ }
+
+ /* skip the first '$' if necessary */
+ if (nmea_string[i] == '$') {
+ i += 1;
+ }
+
+ /* xor until '*' or max length is reached */
+ while (nmea_string[i] != '*') {
+ check_num ^= nmea_string[i];
+ i += 1;
+ if (i >= buff_size) {
+ DEBUG_MSG("Maximum length reached for nmea_checksum\n");
+ return -1;
+ }
+ }
+
+ /* Convert checksum value to 2 hexadecimal characters */
+ checksum[0] = nibble_to_hexchar(check_num / 16); /* upper nibble */
+ checksum[1] = nibble_to_hexchar(check_num % 16); /* lower nibble */
+
+ return i + 1;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+static char nibble_to_hexchar(uint8_t a) {
+ if (a < 10) {
+ return '0' + a;
+ } else if (a < 16) {
+ return 'A' + (a-10);
+ } else {
+ return '?';
+ }
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+/*
+Calculate the checksum of a NMEA frame and compare it to the checksum that is
+present at the end of it.
+Return true if it matches
+*/
+static bool validate_nmea_checksum(const char *serial_buff, int buff_size) {
+ int checksum_index;
+ char checksum[2]; /* 2 characters to calculate NMEA checksum */
+
+ checksum_index = nmea_checksum(serial_buff, buff_size, checksum);
+
+ /* could we calculate a verification checksum ? */
+ if (checksum_index < 0) {
+ DEBUG_MSG("ERROR: IMPOSSIBLE TO PARSE NMEA SENTENCE\n");
+ return false;
+ }
+
+ /* check if there are enough char in the serial buffer to read checksum */
+ if (checksum_index >= (buff_size - 2)) {
+ DEBUG_MSG("ERROR: IMPOSSIBLE TO READ NMEA SENTENCE CHECKSUM\n");
+ return false;
+ }
+
+ /* check the checksum per se */
+ if ((serial_buff[checksum_index] == checksum[0]) && (serial_buff[checksum_index+1] == checksum[1])) {
+ return true;
+ } else {
+ DEBUG_MSG("ERROR: NMEA CHECKSUM %c%c DOESN'T MATCH VERIFICATION CHECKSUM %c%c\n", serial_buff[checksum_index], serial_buff[checksum_index+1], checksum[0], checksum[1]);
+ return false;
+ }
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+/*
+Return true if the "label" string (can contain wildcard characters) matches
+the begining of the "s" string
+*/
+static bool match_label(const char *s, char *label, int size, char wildcard) {
+ int i;
+
+ for (i=0; i < size; i++) {
+ if (label[i] == wildcard) continue;
+ if (label[i] != s[i]) return false;
+ }
+ return true;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+/*
+Chop a string into smaller strings
+Replace every separator in the input character buffer by a null character so
+that all s[index] are valid strings.
+Populate an array of integer 'idx_ary' representing indexes of token in the
+string.
+buff_size and max_idx are there to prevent segfaults.
+Return the number of token found (number of idx_ary filled).
+*/
+int str_chop(char *s, int buff_size, char separator, int *idx_ary, int max_idx) {
+ int i = 0; /* index in the string */
+ int j = 0; /* index in the result array */
+
+ if ((s == NULL) || (buff_size < 0) || (separator == 0) || (idx_ary == NULL) || (max_idx < 0)) {
+ /* unsafe to do anything */
+ return -1;
+ }
+ if ((buff_size == 0) || (max_idx == 0)) {
+ /* nothing to do */
+ return 0;
+ }
+ s[buff_size - 1] = 0; /* add string terminator at the end of the buffer, just to be sure */
+ idx_ary[j] = 0;
+ j += 1;
+ /* loop until string terminator is reached */
+ while (s[i] != 0) {
+ if (s[i] == separator) {
+ s[i] = 0; /* replace separator by string terminator */
+ if (j >= max_idx) { /* no more room in the index array */
+ return j;
+ }
+ idx_ary[j] = i+1; /* next token start after replaced separator */
+ ++j;
+ }
+ ++i;
+ }
+ return j;
+}
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC FUNCTIONS DEFINITION ------------------------------------------ */
+
+int lgw_gps_enable(char *tty_path, char *gps_family, speed_t target_brate, int *fd_ptr) {
+ int i;
+ struct termios ttyopt; /* serial port options */
+ int gps_tty_dev; /* file descriptor to the serial port of the GNSS module */
+ uint8_t ubx_cmd_timegps[UBX_MSG_NAVTIMEGPS_LEN] = {
+ 0xB5, 0x62, /* UBX Sync Chars */
+ 0x06, 0x01, /* CFG-MSG Class/ID */
+ 0x08, 0x00, /* Payload length */
+ 0x01, 0x20, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, /* Enable NAV-TIMEGPS output on serial */
+ 0x32, 0x94 }; /* Checksum */
+ ssize_t num_written;
+
+ /* check input parameters */
+ CHECK_NULL(tty_path);
+ CHECK_NULL(fd_ptr);
+
+ /* open TTY device */
+ gps_tty_dev = open(tty_path, O_RDWR | O_NOCTTY);
+ if (gps_tty_dev <= 0) {
+ DEBUG_MSG("ERROR: TTY PORT FAIL TO OPEN, CHECK PATH AND ACCESS RIGHTS\n");
+ return LGW_GPS_ERROR;
+ }
+ *fd_ptr = gps_tty_dev;
+
+ /* manage the different GPS modules families */
+ if (gps_family == NULL) {
+ DEBUG_MSG("WARNING: this version of GPS module may not be supported\n");
+ } else if (strncmp(gps_family, "ubx7", 4) != 0) {
+ /* The current implementation relies on proprietary messages from U-Blox */
+ /* GPS modules (UBX, NAV-TIMEGPS...) and has only be tested with a u-blox 7. */
+ /* Those messages allow to get NATIVE GPS time (no leap seconds) required */
+ /* for class-B handling and GPS synchronization */
+ /* see lgw_parse_ubx() function for details */
+ DEBUG_MSG("WARNING: this version of GPS module may not be supported\n");
+ }
+
+ /* manage the target bitrate */
+ if (target_brate != 0) {
+ DEBUG_MSG("WARNING: target_brate parameter ignored for now\n"); // TODO
+ }
+
+ /* get actual serial port configuration */
+ i = tcgetattr(gps_tty_dev, &ttyopt);
+ if (i != 0) {
+ DEBUG_MSG("ERROR: IMPOSSIBLE TO GET TTY PORT CONFIGURATION\n");
+ return LGW_GPS_ERROR;
+ }
+
+ /* Save current serial port configuration for restoring later */
+ memcpy(&ttyopt_restore, &ttyopt, sizeof ttyopt);
+
+ /* update baudrates */
+ cfsetispeed(&ttyopt, DEFAULT_BAUDRATE);
+ cfsetospeed(&ttyopt, DEFAULT_BAUDRATE);
+
+ /* update terminal parameters */
+ /* The following configuration should allow to:
+ - Get ASCII NMEA messages
+ - Get UBX binary messages
+ - Send UBX binary commands
+ Note: as binary data have to be read/written, we need to disable
+ various character processing to avoid loosing data */
+ /* Control Modes */
+ ttyopt.c_cflag |= CLOCAL; /* local connection, no modem control */
+ ttyopt.c_cflag |= CREAD; /* enable receiving characters */
+ ttyopt.c_cflag |= CS8; /* 8 bit frames */
+ ttyopt.c_cflag &= ~PARENB; /* no parity */
+ ttyopt.c_cflag &= ~CSTOPB; /* one stop bit */
+ /* Input Modes */
+ ttyopt.c_iflag |= IGNPAR; /* ignore bytes with parity errors */
+ ttyopt.c_iflag &= ~ICRNL; /* do not map CR to NL on input*/
+ ttyopt.c_iflag &= ~IGNCR; /* do not ignore carriage return on input */
+ ttyopt.c_iflag &= ~IXON; /* disable Start/Stop output control */
+ ttyopt.c_iflag &= ~IXOFF; /* do not send Start/Stop characters */
+ /* Output Modes */
+ ttyopt.c_oflag = 0; /* disable everything on output as we only write binary */
+ /* Local Modes */
+ ttyopt.c_lflag &= ~ICANON; /* disable canonical input - cannot use with binary input */
+ ttyopt.c_lflag &= ~ISIG; /* disable check for INTR, QUIT, SUSP special characters */
+ ttyopt.c_lflag &= ~IEXTEN; /* disable any special control character */
+ ttyopt.c_lflag &= ~ECHO; /* do not echo back every character typed */
+ ttyopt.c_lflag &= ~ECHOE; /* does not erase the last character in current line */
+ ttyopt.c_lflag &= ~ECHOK; /* do not echo NL after KILL character */
+
+ /* settings for non-canonical mode
+ read will block for until the lesser of VMIN or requested chars have been received */
+ ttyopt.c_cc[VMIN] = LGW_GPS_MIN_MSG_SIZE;
+ ttyopt.c_cc[VTIME] = 0;
+
+ /* set new serial ports parameters */
+ i = tcsetattr(gps_tty_dev, TCSANOW, &ttyopt);
+ if (i != 0){
+ DEBUG_MSG("ERROR: IMPOSSIBLE TO UPDATE TTY PORT CONFIGURATION\n");
+ return LGW_GPS_ERROR;
+ }
+ tcflush(gps_tty_dev, TCIOFLUSH);
+
+ /* Send UBX CFG NAV-TIMEGPS message to tell GPS module to output native GPS time */
+ /* This is a binary message, serial port has to be properly configured to handle this */
+ num_written = write (gps_tty_dev, ubx_cmd_timegps, UBX_MSG_NAVTIMEGPS_LEN);
+ if (num_written != UBX_MSG_NAVTIMEGPS_LEN) {
+ DEBUG_MSG("ERROR: Failed to write on serial port (written=%d)\n", (int) num_written);
+ }
+
+ /* get timezone info */
+ tzset();
+
+ /* initialize global variables */
+ gps_time_ok = false;
+ gps_pos_ok = false;
+ gps_mod = 'N';
+
+ return LGW_GPS_SUCCESS;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int lgw_gps_disable(int fd) {
+ int i;
+
+ /* restore serial ports parameters */
+ i = tcsetattr(fd, TCSANOW, &ttyopt_restore);
+ if (i != 0){
+ DEBUG_MSG("ERROR: IMPOSSIBLE TO RESTORE TTY PORT CONFIGURATION\n");
+ return LGW_GPS_ERROR;
+ }
+ tcflush(fd, TCIOFLUSH);
+
+ i = close(fd);
+ if (i <= 0) {
+ DEBUG_MSG("ERROR: TTY PORT FAIL TO CLOSE\n");
+ return LGW_GPS_ERROR;
+ }
+
+ return LGW_GPS_SUCCESS;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+enum gps_msg lgw_parse_ubx(const char *serial_buff, size_t buff_size, size_t *msg_size) {
+ bool valid = 0; /* iTOW, fTOW and week validity */
+ unsigned int payload_length;
+ uint8_t ck_a, ck_b;
+ uint8_t ck_a_rcv, ck_b_rcv;
+ unsigned int i;
+
+ *msg_size = 0; /* ensure msg_size alway receives a value */
+
+ /* check input parameters */
+ if (serial_buff == NULL) {
+ return IGNORED;
+ }
+ if (buff_size < 8) {
+ DEBUG_MSG("ERROR: TOO SHORT TO BE A VALID UBX MESSAGE\n");
+ return IGNORED;
+ }
+
+ /* display received serial data and checksum */
+ DEBUG_MSG("Note: parsing UBX frame> ");
+ for (i=0; i<buff_size; i++) {
+ DEBUG_MSG("%02x ", serial_buff[i]);
+ }
+ DEBUG_MSG("\n");
+
+ /* Check for UBX sync chars 0xB5 0x62 */
+ if ((serial_buff[0] == (char)0xB5) && (serial_buff[1] == (char)0x62)) {
+
+ /* Get payload length to compute message size */
+ payload_length = (uint8_t)serial_buff[4];
+ payload_length |= (uint8_t)serial_buff[5] << 8;
+ *msg_size = 6 + payload_length + 2; /* header + payload + checksum */
+
+ /* check for complete message in buffer */
+ if(*msg_size <= buff_size) {
+ /* Validate checksum of message */
+ ck_a_rcv = serial_buff[*msg_size-2]; /* received checksum */
+ ck_b_rcv = serial_buff[*msg_size-1]; /* received checksum */
+ /* Use 8-bit Fletcher Algorithm to compute checksum of actual payload */
+ ck_a = 0; ck_b = 0;
+ for (i=0; i<(4 + payload_length); i++) {
+ ck_a = ck_a + serial_buff[i+2];
+ ck_b = ck_b + ck_a;
+ }
+
+ /* Compare checksums and parse if OK */
+ if ((ck_a == ck_a_rcv) && (ck_b == ck_b_rcv)) {
+ /* Check for Class 0x01 (NAV) and ID 0x20 (NAV-TIMEGPS) */
+ if ((serial_buff[2] == 0x01) && (serial_buff[3] == 0x20)) {
+ /* Check validity of information */
+ valid = serial_buff[17] & 0x3; /* towValid, weekValid */
+ if (valid) {
+ /* Parse buffer to extract GPS time */
+ /* Warning: payload byte ordering is Little Endian */
+ gps_iTOW = (uint8_t)serial_buff[6];
+ gps_iTOW |= (uint8_t)serial_buff[7] << 8;
+ gps_iTOW |= (uint8_t)serial_buff[8] << 16;
+ gps_iTOW |= (uint8_t)serial_buff[9] << 24; /* GPS time of week, in ms */
+
+ gps_fTOW = (uint8_t)serial_buff[10];
+ gps_fTOW |= (uint8_t)serial_buff[11] << 8;
+ gps_fTOW |= (uint8_t)serial_buff[12] << 16;
+ gps_fTOW |= (uint8_t)serial_buff[13] << 24; /* Fractional part of iTOW, in ns */
+
+ gps_week = (uint8_t)serial_buff[14];
+ gps_week |= (uint8_t)serial_buff[15] << 8; /* GPS week number */
+
+ gps_time_ok = true;
+#if 0
+ /* For debug */
+ {
+ short ubx_gps_hou = 0; /* hours (0-23) */
+ short ubx_gps_min = 0; /* minutes (0-59) */
+ short ubx_gps_sec = 0; /* seconds (0-59) */
+
+ /* Format GPS time in hh:mm:ss based on iTOW */
+ ubx_gps_sec = (gps_iTOW / 1000) % 60;
+ ubx_gps_min = (gps_iTOW / 1000 / 60) % 60;
+ ubx_gps_hou = (gps_iTOW / 1000 / 60 / 60) % 24;
+ printf(" GPS time = %02d:%02d:%02d\n", ubx_gps_hou, ubx_gps_min, ubx_gps_sec);
+ }
+#endif
+ } else { /* valid */
+ gps_time_ok = false;
+ }
+
+ return UBX_NAV_TIMEGPS;
+ } else if ((serial_buff[2] == 0x05) && (serial_buff[3] == 0x00)) {
+ DEBUG_MSG("NOTE: UBX ACK-NAK received\n");
+ return IGNORED;
+ } else if ((serial_buff[2] == 0x05) && (serial_buff[3] == 0x01)) {
+ DEBUG_MSG("NOTE: UBX ACK-ACK received\n");
+ return IGNORED;
+ } else { /* not a supported message */
+ DEBUG_MSG("ERROR: UBX message is not supported (%02x %02x)\n", serial_buff[2], serial_buff[3]);
+ return IGNORED;
+ }
+ } else { /* checksum failed */
+ DEBUG_MSG("ERROR: UBX message is corrupted, checksum failed\n");
+ return INVALID;
+ }
+ } else { /* message contains less bytes than indicated by header */
+ DEBUG_MSG("ERROR: UBX message incomplete\n");
+ return INCOMPLETE;
+ }
+ } else { /* Not a UBX message */
+ /* Ignore messages which are not UBX ones for now */
+ return IGNORED;
+ }
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+enum gps_msg lgw_parse_nmea(const char *serial_buff, int buff_size) {
+ int i, j, k;
+ int str_index[30]; /* string index from the string chopping */
+ int nb_fields; /* number of strings detected by string chopping */
+ char parser_buf[256]; /* parsing modifies buffer so need a local copy */
+
+ /* check input parameters */
+ if (serial_buff == NULL) {
+ return UNKNOWN;
+ }
+
+ if(buff_size > (int)(sizeof(parser_buf) - 1)) {
+ DEBUG_MSG("Note: input string to big for parsing\n");
+ return INVALID;
+ }
+
+ /* look for some NMEA sentences in particular */
+ if (buff_size < 8) {
+ DEBUG_MSG("ERROR: TOO SHORT TO BE A VALID NMEA SENTENCE\n");
+ return UNKNOWN;
+ } else if (!validate_nmea_checksum(serial_buff, buff_size)) {
+ DEBUG_MSG("Warning: invalid NMEA sentence (bad checksum)\n");
+ return INVALID;
+ } else if (match_label(serial_buff, "$G?RMC", 6, '?')) {
+ /*
+ NMEA sentence format: $xxRMC,time,status,lat,NS,long,EW,spd,cog,date,mv,mvEW,posMode*cs<CR><LF>
+ Valid fix: $GPRMC,083559.34,A,4717.11437,N,00833.91522,E,0.004,77.52,091202,,,A*00
+ No fix: $GPRMC,,V,,,,,,,,,,N*00
+ */
+ memcpy(parser_buf, serial_buff, buff_size);
+ parser_buf[buff_size] = '\0';
+ nb_fields = str_chop(parser_buf, buff_size, ',', str_index, ARRAY_SIZE(str_index));
+ if (nb_fields != 13) {
+ DEBUG_MSG("Warning: invalid RMC sentence (number of fields)\n");
+ return IGNORED;
+ }
+ /* parse GPS status */
+ gps_mod = *(parser_buf + str_index[12]); /* get first character, no need to bother with sscanf */
+ if ((gps_mod != 'N') && (gps_mod != 'A') && (gps_mod != 'D')) {
+ gps_mod = 'N';
+ }
+ /* parse complete time */
+ i = sscanf(parser_buf + str_index[1], "%2hd%2hd%2hd%4f", &gps_hou, &gps_min, &gps_sec, &gps_fra);
+ j = sscanf(parser_buf + str_index[9], "%2hd%2hd%2hd", &gps_day, &gps_mon, &gps_yea);
+ if ((i == 4) && (j == 3)) {
+ if ((gps_mod == 'A') || (gps_mod == 'D')) {
+ gps_time_ok = true;
+ DEBUG_MSG("Note: Valid RMC sentence, GPS locked, date: 20%02d-%02d-%02dT%02d:%02d:%06.3fZ\n", gps_yea, gps_mon, gps_day, gps_hou, gps_min, gps_fra + (float)gps_sec);
+ } else {
+ gps_time_ok = false;
+ DEBUG_MSG("Note: Valid RMC sentence, no satellite fix, estimated date: 20%02d-%02d-%02dT%02d:%02d:%06.3fZ\n", gps_yea, gps_mon, gps_day, gps_hou, gps_min, gps_fra + (float)gps_sec);
+ }
+ } else {
+ /* could not get a valid hour AND date */
+ gps_time_ok = false;
+ DEBUG_MSG("Note: Valid RMC sentence, mode %c, no date\n", gps_mod);
+ }
+ return NMEA_RMC;
+ } else if (match_label(serial_buff, "$G?GGA", 6, '?')) {
+ /*
+ NMEA sentence format: $xxGGA,time,lat,NS,long,EW,quality,numSV,HDOP,alt,M,sep,M,diffAge,diffStation*cs<CR><LF>
+ Valid fix: $GPGGA,092725.00,4717.11399,N,00833.91590,E,1,08,1.01,499.6,M,48.0,M,,*5B
+ */
+ memcpy(parser_buf, serial_buff, buff_size);
+ parser_buf[buff_size] = '\0';
+ nb_fields = str_chop(parser_buf, buff_size, ',', str_index, ARRAY_SIZE(str_index));
+ if (nb_fields != 15) {
+ DEBUG_MSG("Warning: invalid GGA sentence (number of fields)\n");
+ return IGNORED;
+ }
+ /* parse number of satellites used for fix */
+ sscanf(parser_buf + str_index[7], "%hd", &gps_sat);
+ /* parse 3D coordinates */
+ i = sscanf(parser_buf + str_index[2], "%2hd%10lf", &gps_dla, &gps_mla);
+ gps_ola = *(parser_buf + str_index[3]);
+ j = sscanf(parser_buf + str_index[4], "%3hd%10lf", &gps_dlo, &gps_mlo);
+ gps_olo = *(parser_buf + str_index[5]);
+ k = sscanf(parser_buf + str_index[9], "%hd", &gps_alt);
+ if ((i == 2) && (j == 2) && (k == 1) && ((gps_ola=='N')||(gps_ola=='S')) && ((gps_olo=='E')||(gps_olo=='W'))) {
+ gps_pos_ok = true;
+ DEBUG_MSG("Note: Valid GGA sentence, %d sat, lat %02ddeg %06.3fmin %c, lon %03ddeg%06.3fmin %c, alt %d\n", gps_sat, gps_dla, gps_mla, gps_ola, gps_dlo, gps_mlo, gps_olo, gps_alt);
+ } else {
+ /* could not get a valid latitude, longitude AND altitude */
+ gps_pos_ok = false;
+ DEBUG_MSG("Note: Valid GGA sentence, %d sat, no coordinates\n", gps_sat);
+ }
+ return NMEA_GGA;
+ } else {
+ DEBUG_MSG("Note: ignored NMEA sentence\n"); /* quite verbose */
+ return IGNORED;
+ }
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int lgw_gps_get(struct timespec *utc, struct timespec *gps_time, struct coord_s *loc, struct coord_s *err) {
+ struct tm x;
+ time_t y;
+ double intpart, fractpart;
+
+ if (utc != NULL) {
+ if (!gps_time_ok) {
+ DEBUG_MSG("ERROR: NO VALID TIME TO RETURN\n");
+ return LGW_GPS_ERROR;
+ }
+ memset(&x, 0, sizeof(x));
+ if (gps_yea < 100) { /* 2-digits year, 20xx */
+ x.tm_year = gps_yea + 100; /* 100 years offset to 1900 */
+ } else { /* 4-digits year, Gregorian calendar */
+ x.tm_year = gps_yea - 1900;
+ }
+ x.tm_mon = gps_mon - 1; /* tm_mon is [0,11], gps_mon is [1,12] */
+ x.tm_mday = gps_day;
+ x.tm_hour = gps_hou;
+ x.tm_min = gps_min;
+ x.tm_sec = gps_sec;
+ y = mktime(&x) - timezone; /* need to substract timezone bc mktime assumes time vector is local time */
+ if (y == (time_t)(-1)) {
+ DEBUG_MSG("ERROR: FAILED TO CONVERT BROKEN-DOWN TIME\n");
+ return LGW_GPS_ERROR;
+ }
+ utc->tv_sec = y;
+ utc->tv_nsec = (int32_t)(gps_fra * 1e9);
+ }
+ if (gps_time != NULL) {
+ if (!gps_time_ok) {
+ DEBUG_MSG("ERROR: NO VALID TIME TO RETURN\n");
+ return LGW_GPS_ERROR;
+ }
+ fractpart = modf(((double)gps_iTOW / 1E3) + ((double)gps_fTOW / 1E9), &intpart);
+ /* Number of seconds since beginning on current GPS week */
+ gps_time->tv_sec = (time_t)intpart;
+ /* Number of seconds since GPS epoch 06.Jan.1980 */
+ gps_time->tv_sec += (time_t)gps_week * 604800; /* day*hours*minutes*secondes: 7*24*60*60; */
+ /* Fractional part in nanoseconds */
+ gps_time->tv_nsec = (long)(fractpart * 1E9);
+ }
+ if (loc != NULL) {
+ if (!gps_pos_ok) {
+ DEBUG_MSG("ERROR: NO VALID POSITION TO RETURN\n");
+ return LGW_GPS_ERROR;
+ }
+ loc->lat = ((double)gps_dla + (gps_mla/60.0)) * ((gps_ola == 'N')?1.0:-1.0);
+ loc->lon = ((double)gps_dlo + (gps_mlo/60.0)) * ((gps_olo == 'E')?1.0:-1.0);
+ loc->alt = gps_alt;
+ }
+ if (err != NULL) {
+ DEBUG_MSG("Warning: localization error processing not implemented yet\n");
+ err->lat = 0.0;
+ err->lon = 0.0;
+ err->alt = 0;
+ }
+
+ return LGW_GPS_SUCCESS;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int lgw_gps_sync(struct tref *ref, uint32_t count_us, struct timespec utc, struct timespec gps_time) {
+ double cnt_diff; /* internal concentrator time difference (in seconds) */
+ double utc_diff; /* UTC time difference (in seconds) */
+ double slope; /* time slope between new reference and old reference (for sanity check) */
+
+ bool aber_n0; /* is the update value for synchronization aberrant or not ? */
+ static bool aber_min1 = false; /* keep track of whether value at sync N-1 was aberrant or not */
+ static bool aber_min2 = false; /* keep track of whether value at sync N-2 was aberrant or not */
+
+ CHECK_NULL(ref);
+
+ /* calculate the slope */
+
+ cnt_diff = (double)(count_us - ref->count_us) / (double)(TS_CPS); /* uncorrected by xtal_err */
+ utc_diff = (double)(utc.tv_sec - (ref->utc).tv_sec) + (1E-9 * (double)(utc.tv_nsec - (ref->utc).tv_nsec));
+
+ /* detect aberrant points by measuring if slope limits are exceeded */
+ if (utc_diff != 0) { // prevent divide by zero
+ slope = cnt_diff/utc_diff;
+ if ((slope > PLUS_10PPM) || (slope < MINUS_10PPM)) {
+ DEBUG_MSG("Warning: correction range exceeded\n");
+ aber_n0 = true;
+ } else {
+ aber_n0 = false;
+ }
+ } else {
+ DEBUG_MSG("Warning: aberrant UTC value for synchronization\n");
+ aber_n0 = true;
+ }
+
+ /* watch if the 3 latest sync point were aberrant or not */
+ if (aber_n0 == false) {
+ /* value no aberrant -> sync with smoothed slope */
+ ref->systime = time(NULL);
+ ref->count_us = count_us;
+ ref->utc.tv_sec = utc.tv_sec;
+ ref->utc.tv_nsec = utc.tv_nsec;
+ ref->gps.tv_sec = gps_time.tv_sec;
+ ref->gps.tv_nsec = gps_time.tv_nsec;
+ ref->xtal_err = slope;
+ aber_min2 = aber_min1;
+ aber_min1 = aber_n0;
+ return LGW_GPS_SUCCESS;
+ } else if (aber_n0 && aber_min1 && aber_min2) {
+ /* 3 successive aberrant values -> sync reset (keep xtal_err) */
+ ref->systime = time(NULL);
+ ref->count_us = count_us;
+ ref->utc.tv_sec = utc.tv_sec;
+ ref->utc.tv_nsec = utc.tv_nsec;
+ ref->gps.tv_sec = gps_time.tv_sec;
+ ref->gps.tv_nsec = gps_time.tv_nsec;
+ /* reset xtal_err only if the present value is out of range */
+ if ((ref->xtal_err > PLUS_10PPM) || (ref->xtal_err < MINUS_10PPM)) {
+ ref->xtal_err = 1.0;
+ }
+ DEBUG_MSG("Warning: 3 successive aberrant sync attempts, sync reset\n");
+ aber_min2 = aber_min1;
+ aber_min1 = aber_n0;
+ return LGW_GPS_SUCCESS;
+ } else {
+ /* only 1 or 2 successive aberrant values -> ignore and return an error */
+ aber_min2 = aber_min1;
+ aber_min1 = aber_n0;
+ return LGW_GPS_ERROR;
+ }
+
+ return LGW_GPS_SUCCESS;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int lgw_cnt2utc(struct tref ref, uint32_t count_us, struct timespec *utc) {
+ double delta_sec;
+ double intpart, fractpart;
+ long tmp;
+
+ CHECK_NULL(utc);
+ if ((ref.systime == 0) || (ref.xtal_err > PLUS_10PPM) || (ref.xtal_err < MINUS_10PPM)) {
+ DEBUG_MSG("ERROR: INVALID REFERENCE FOR CNT -> UTC CONVERSION\n");
+ return LGW_GPS_ERROR;
+ }
+
+ /* calculate delta in seconds between reference count_us and target count_us */
+ delta_sec = (double)(count_us - ref.count_us) / (TS_CPS * ref.xtal_err);
+
+ /* now add that delta to reference UTC time */
+ fractpart = modf (delta_sec , &intpart);
+ tmp = ref.utc.tv_nsec + (long)(fractpart * 1E9);
+ if (tmp < (long)1E9) { /* the nanosecond part doesn't overflow */
+ utc->tv_sec = ref.utc.tv_sec + (time_t)intpart;
+ utc->tv_nsec = tmp;
+ } else { /* must carry one second */
+ utc->tv_sec = ref.utc.tv_sec + (time_t)intpart + 1;
+ utc->tv_nsec = tmp - (long)1E9;
+ }
+
+ return LGW_GPS_SUCCESS;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int lgw_utc2cnt(struct tref ref, struct timespec utc, uint32_t *count_us) {
+ double delta_sec;
+
+ CHECK_NULL(count_us);
+ if ((ref.systime == 0) || (ref.xtal_err > PLUS_10PPM) || (ref.xtal_err < MINUS_10PPM)) {
+ DEBUG_MSG("ERROR: INVALID REFERENCE FOR UTC -> CNT CONVERSION\n");
+ return LGW_GPS_ERROR;
+ }
+
+ /* calculate delta in seconds between reference utc and target utc */
+ delta_sec = (double)(utc.tv_sec - ref.utc.tv_sec);
+ delta_sec += 1E-9 * (double)(utc.tv_nsec - ref.utc.tv_nsec);
+
+ /* now convert that to internal counter tics and add that to reference counter value */
+ *count_us = ref.count_us + (uint32_t)(delta_sec * TS_CPS * ref.xtal_err);
+
+ return LGW_GPS_SUCCESS;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int lgw_cnt2gps(struct tref ref, uint32_t count_us, struct timespec *gps_time) {
+ double delta_sec;
+ double intpart, fractpart;
+ long tmp;
+
+ CHECK_NULL(gps_time);
+ if ((ref.systime == 0) || (ref.xtal_err > PLUS_10PPM) || (ref.xtal_err < MINUS_10PPM)) {
+ DEBUG_MSG("ERROR: INVALID REFERENCE FOR CNT -> GPS CONVERSION\n");
+ return LGW_GPS_ERROR;
+ }
+
+ /* calculate delta in milliseconds between reference count_us and target count_us */
+ delta_sec = (double)(count_us - ref.count_us) / (TS_CPS * ref.xtal_err);
+
+ /* now add that delta to reference GPS time */
+ fractpart = modf (delta_sec , &intpart);
+ tmp = ref.gps.tv_nsec + (long)(fractpart * 1E9);
+ if (tmp < (long)1E9) { /* the nanosecond part doesn't overflow */
+ gps_time->tv_sec = ref.gps.tv_sec + (time_t)intpart;
+ gps_time->tv_nsec = tmp;
+ } else { /* must carry one second */
+ gps_time->tv_sec = ref.gps.tv_sec + (time_t)intpart + 1;
+ gps_time->tv_nsec = tmp - (long)1E9;
+ }
+
+ return LGW_GPS_SUCCESS;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int lgw_gps2cnt(struct tref ref, struct timespec gps_time, uint32_t *count_us) {
+ double delta_sec;
+
+ CHECK_NULL(count_us);
+ if ((ref.systime == 0) || (ref.xtal_err > PLUS_10PPM) || (ref.xtal_err < MINUS_10PPM)) {
+ DEBUG_MSG("ERROR: INVALID REFERENCE FOR GPS -> CNT CONVERSION\n");
+ return LGW_GPS_ERROR;
+ }
+
+ /* calculate delta in seconds between reference gps time and target gps time */
+ delta_sec = (double)(gps_time.tv_sec - ref.gps.tv_sec);
+ delta_sec += 1E-9 * (double)(gps_time.tv_nsec - ref.gps.tv_nsec);
+
+ /* now convert that to internal counter tics and add that to reference counter value */
+ *count_us = ref.count_us + (uint32_t)(delta_sec * TS_CPS * ref.xtal_err);
+
+ return LGW_GPS_SUCCESS;
+}
+
+/* --- EOF ------------------------------------------------------------------ */
diff --git a/libloragw/src/loragw_hal.c b/libloragw/src/loragw_hal.c
new file mode 100644
index 0000000..8103751
--- /dev/null
+++ b/libloragw/src/loragw_hal.c
@@ -0,0 +1,1767 @@
+/*
+ / _____) _ | |
+( (____ _____ ____ _| |_ _____ ____| |__
+ \____ \| ___ | (_ _) ___ |/ ___) _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+ (C)2013 Semtech-Cycleo
+
+Description:
+ LoRa concentrator Hardware Abstraction Layer
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+Maintainer: Sylvain Miermont
+*/
+
+
+/* -------------------------------------------------------------------------- */
+/* --- DEPENDANCIES --------------------------------------------------------- */
+
+#include <stdint.h> /* C99 types */
+#include <stdbool.h> /* bool type */
+#include <stdio.h> /* printf fprintf */
+#include <string.h> /* memcpy */
+#include <math.h> /* pow, cell */
+
+#include "loragw_reg.h"
+#include "loragw_hal.h"
+#include "loragw_aux.h"
+#include "loragw_spi.h"
+#include "loragw_radio.h"
+#include "loragw_fpga.h"
+#include "loragw_lbt.h"
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE MACROS ------------------------------------------------------- */
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+#if DEBUG_HAL == 1
+ #define DEBUG_MSG(str) fprintf(stderr, str)
+ #define DEBUG_PRINTF(fmt, args...) fprintf(stderr,"%s:%d: "fmt, __FUNCTION__, __LINE__, args)
+ #define DEBUG_ARRAY(a,b,c) for(a=0;a<b;++a) fprintf(stderr,"%x.",c[a]);fprintf(stderr,"end\n")
+ #define CHECK_NULL(a) if(a==NULL){fprintf(stderr,"%s:%d: ERROR: NULL POINTER AS ARGUMENT\n", __FUNCTION__, __LINE__);return LGW_HAL_ERROR;}
+#else
+ #define DEBUG_MSG(str)
+ #define DEBUG_PRINTF(fmt, args...)
+ #define DEBUG_ARRAY(a,b,c) for(a=0;a!=0;){}
+ #define CHECK_NULL(a) if(a==NULL){return LGW_HAL_ERROR;}
+#endif
+
+#define IF_HZ_TO_REG(f) (f << 5)/15625
+#define SET_PPM_ON(bw,dr) (((bw == BW_125KHZ) && ((dr == DR_LORA_SF11) || (dr == DR_LORA_SF12))) || ((bw == BW_250KHZ) && (dr == DR_LORA_SF12)))
+#define TRACE() fprintf(stderr, "@ %s %d\n", __FUNCTION__, __LINE__);
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE CONSTANTS & TYPES -------------------------------------------- */
+
+#define MCU_ARB 0
+#define MCU_AGC 1
+#define MCU_ARB_FW_BYTE 8192 /* size of the firmware IN BYTES (= twice the number of 14b words) */
+#define MCU_AGC_FW_BYTE 8192 /* size of the firmware IN BYTES (= twice the number of 14b words) */
+#define FW_VERSION_ADDR 0x20 /* Address of firmware version in data memory */
+#define FW_VERSION_CAL 2 /* Expected version of calibration firmware */
+#define FW_VERSION_AGC 4 /* Expected version of AGC firmware */
+#define FW_VERSION_ARB 1 /* Expected version of arbiter firmware */
+
+#define TX_METADATA_NB 16
+#define RX_METADATA_NB 16
+
+#define AGC_CMD_WAIT 16
+#define AGC_CMD_ABORT 17
+
+#define MIN_LORA_PREAMBLE 6
+#define STD_LORA_PREAMBLE 8
+#define MIN_FSK_PREAMBLE 3
+#define STD_FSK_PREAMBLE 5
+
+#define RSSI_MULTI_BIAS -35 /* difference between "multi" modem RSSI offset and "stand-alone" modem RSSI offset */
+#define RSSI_FSK_POLY_0 60 /* polynomiam coefficients to linearize FSK RSSI */
+#define RSSI_FSK_POLY_1 1.5351
+#define RSSI_FSK_POLY_2 0.003
+
+/* Useful bandwidth of SX125x radios to consider depending on channel bandwidth */
+/* Note: the below values come from lab measurements. For any question, please contact Semtech support */
+#define LGW_RF_RX_BANDWIDTH_125KHZ 925000 /* for 125KHz channels */
+#define LGW_RF_RX_BANDWIDTH_250KHZ 1000000 /* for 250KHz channels */
+#define LGW_RF_RX_BANDWIDTH_500KHZ 1100000 /* for 500KHz channels */
+
+#define TX_START_DELAY_DEFAULT 1497 /* Calibrated value for 500KHz BW and notch filter disabled */
+
+/* constant arrays defining hardware capability */
+const uint8_t ifmod_config[LGW_IF_CHAIN_NB] = LGW_IFMODEM_CONFIG;
+
+/* Version string, used to identify the library version/options once compiled */
+const char lgw_version_string[] = "Version: " LIBLORAGW_VERSION ";";
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE VARIABLES ---------------------------------------------------- */
+
+#include "arb_fw.var" /* external definition of the variable */
+#include "agc_fw.var" /* external definition of the variable */
+#include "cal_fw.var" /* external definition of the variable */
+
+/*
+The following static variables are the configuration set that the user can
+modify using rxrf_setconf, rxif_setconf and txgain_setconf functions.
+The functions _start and _send then use that set to configure the hardware.
+
+Parameters validity and coherency is verified by the _setconf functions and
+the _start and _send functions assume they are valid.
+*/
+
+static bool lgw_is_started;
+
+static bool rf_enable[LGW_RF_CHAIN_NB];
+static uint32_t rf_rx_freq[LGW_RF_CHAIN_NB]; /* absolute, in Hz */
+static float rf_rssi_offset[LGW_RF_CHAIN_NB];
+static bool rf_tx_enable[LGW_RF_CHAIN_NB];
+static uint32_t rf_tx_notch_freq[LGW_RF_CHAIN_NB];
+static enum lgw_radio_type_e rf_radio_type[LGW_RF_CHAIN_NB];
+
+static bool if_enable[LGW_IF_CHAIN_NB];
+static bool if_rf_chain[LGW_IF_CHAIN_NB]; /* for each IF, 0 -> radio A, 1 -> radio B */
+static int32_t if_freq[LGW_IF_CHAIN_NB]; /* relative to radio frequency, +/- in Hz */
+
+static uint8_t lora_multi_sfmask[LGW_MULTI_NB]; /* enables SF for LoRa 'multi' modems */
+
+static uint8_t lora_rx_bw; /* bandwidth setting for LoRa standalone modem */
+static uint8_t lora_rx_sf; /* spreading factor setting for LoRa standalone modem */
+static bool lora_rx_ppm_offset;
+
+static uint8_t fsk_rx_bw; /* bandwidth setting of FSK modem */
+static uint32_t fsk_rx_dr; /* FSK modem datarate in bauds */
+static uint8_t fsk_sync_word_size = 3; /* default number of bytes for FSK sync word */
+static uint64_t fsk_sync_word= 0xC194C1; /* default FSK sync word (ALIGNED RIGHT, MSbit first) */
+
+static bool lorawan_public = false;
+static uint8_t rf_clkout = 0;
+
+static struct lgw_tx_gain_lut_s txgain_lut = {
+ .size = 2,
+ .lut[0] = {
+ .dig_gain = 0,
+ .pa_gain = 2,
+ .dac_gain = 3,
+ .mix_gain = 10,
+ .rf_power = 14
+ },
+ .lut[1] = {
+ .dig_gain = 0,
+ .pa_gain = 3,
+ .dac_gain = 3,
+ .mix_gain = 14,
+ .rf_power = 27
+ }};
+
+/* TX I/Q imbalance coefficients for mixer gain = 8 to 15 */
+static int8_t cal_offset_a_i[8]; /* TX I offset for radio A */
+static int8_t cal_offset_a_q[8]; /* TX Q offset for radio A */
+static int8_t cal_offset_b_i[8]; /* TX I offset for radio B */
+static int8_t cal_offset_b_q[8]; /* TX Q offset for radio B */
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE FUNCTIONS DECLARATION ---------------------------------------- */
+
+int load_firmware(uint8_t target, uint8_t *firmware, uint16_t size);
+
+void lgw_constant_adjust(void);
+
+int32_t lgw_sf_getval(int x);
+int32_t lgw_bw_getval(int x);
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE FUNCTIONS DEFINITION ----------------------------------------- */
+
+/* size is the firmware size in bytes (not 14b words) */
+int load_firmware(uint8_t target, uint8_t *firmware, uint16_t size) {
+ int reg_rst;
+ int reg_sel;
+ uint8_t fw_check[8192];
+ int32_t dummy;
+
+ /* check parameters */
+ CHECK_NULL(firmware);
+ if (target == MCU_ARB) {
+ if (size != MCU_ARB_FW_BYTE) {
+ DEBUG_MSG("ERROR: NOT A VALID SIZE FOR MCU ARG FIRMWARE\n");
+ return -1;
+ }
+ reg_rst = LGW_MCU_RST_0;
+ reg_sel = LGW_MCU_SELECT_MUX_0;
+ }else if (target == MCU_AGC) {
+ if (size != MCU_AGC_FW_BYTE) {
+ DEBUG_MSG("ERROR: NOT A VALID SIZE FOR MCU AGC FIRMWARE\n");
+ return -1;
+ }
+ reg_rst = LGW_MCU_RST_1;
+ reg_sel = LGW_MCU_SELECT_MUX_1;
+ } else {
+ DEBUG_MSG("ERROR: NOT A VALID TARGET FOR LOADING FIRMWARE\n");
+ return -1;
+ }
+
+ /* reset the targeted MCU */
+ lgw_reg_w(reg_rst, 1);
+
+ /* set mux to access MCU program RAM and set address to 0 */
+ lgw_reg_w(reg_sel, 0);
+ lgw_reg_w(LGW_MCU_PROM_ADDR, 0);
+
+ /* write the program in one burst */
+ lgw_reg_wb(LGW_MCU_PROM_DATA, firmware, size);
+
+ /* Read back firmware code for check */
+ lgw_reg_r( LGW_MCU_PROM_DATA, &dummy ); /* bug workaround */
+ lgw_reg_rb( LGW_MCU_PROM_DATA, fw_check, size );
+ if (memcmp(firmware, fw_check, size) != 0) {
+ printf ("ERROR: Failed to load fw %d\n", (int)target);
+ return -1;
+ }
+
+ /* give back control of the MCU program ram to the MCU */
+ lgw_reg_w(reg_sel, 1);
+
+ return 0;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+void lgw_constant_adjust(void) {
+
+ /* I/Q path setup */
+ // lgw_reg_w(LGW_RX_INVERT_IQ,0); /* default 0 */
+ // lgw_reg_w(LGW_MODEM_INVERT_IQ,1); /* default 1 */
+ // lgw_reg_w(LGW_CHIRP_INVERT_RX,1); /* default 1 */
+ // lgw_reg_w(LGW_RX_EDGE_SELECT,0); /* default 0 */
+ // lgw_reg_w(LGW_MBWSSF_MODEM_INVERT_IQ,0); /* default 0 */
+ // lgw_reg_w(LGW_DC_NOTCH_EN,1); /* default 1 */
+ lgw_reg_w(LGW_RSSI_BB_FILTER_ALPHA,6); /* default 7 */
+ lgw_reg_w(LGW_RSSI_DEC_FILTER_ALPHA,7); /* default 5 */
+ lgw_reg_w(LGW_RSSI_CHANN_FILTER_ALPHA,7); /* default 8 */
+ lgw_reg_w(LGW_RSSI_BB_DEFAULT_VALUE,23); /* default 32 */
+ lgw_reg_w(LGW_RSSI_CHANN_DEFAULT_VALUE,85); /* default 100 */
+ lgw_reg_w(LGW_RSSI_DEC_DEFAULT_VALUE,66); /* default 100 */
+ lgw_reg_w(LGW_DEC_GAIN_OFFSET,7); /* default 8 */
+ lgw_reg_w(LGW_CHAN_GAIN_OFFSET,6); /* default 7 */
+
+ /* Correlator setup */
+ // lgw_reg_w(LGW_CORR_DETECT_EN,126); /* default 126 */
+ // lgw_reg_w(LGW_CORR_NUM_SAME_PEAK,4); /* default 4 */
+ // lgw_reg_w(LGW_CORR_MAC_GAIN,5); /* default 5 */
+ // lgw_reg_w(LGW_CORR_SAME_PEAKS_OPTION_SF6,0); /* default 0 */
+ // lgw_reg_w(LGW_CORR_SAME_PEAKS_OPTION_SF7,1); /* default 1 */
+ // lgw_reg_w(LGW_CORR_SAME_PEAKS_OPTION_SF8,1); /* default 1 */
+ // lgw_reg_w(LGW_CORR_SAME_PEAKS_OPTION_SF9,1); /* default 1 */
+ // lgw_reg_w(LGW_CORR_SAME_PEAKS_OPTION_SF10,1); /* default 1 */
+ // lgw_reg_w(LGW_CORR_SAME_PEAKS_OPTION_SF11,1); /* default 1 */
+ // lgw_reg_w(LGW_CORR_SAME_PEAKS_OPTION_SF12,1); /* default 1 */
+ // lgw_reg_w(LGW_CORR_SIG_NOISE_RATIO_SF6,4); /* default 4 */
+ // lgw_reg_w(LGW_CORR_SIG_NOISE_RATIO_SF7,4); /* default 4 */
+ // lgw_reg_w(LGW_CORR_SIG_NOISE_RATIO_SF8,4); /* default 4 */
+ // lgw_reg_w(LGW_CORR_SIG_NOISE_RATIO_SF9,4); /* default 4 */
+ // lgw_reg_w(LGW_CORR_SIG_NOISE_RATIO_SF10,4); /* default 4 */
+ // lgw_reg_w(LGW_CORR_SIG_NOISE_RATIO_SF11,4); /* default 4 */
+ // lgw_reg_w(LGW_CORR_SIG_NOISE_RATIO_SF12,4); /* default 4 */
+
+ /* LoRa 'multi' demodulators setup */
+ // lgw_reg_w(LGW_PREAMBLE_SYMB1_NB,10); /* default 10 */
+ // lgw_reg_w(LGW_FREQ_TO_TIME_INVERT,29); /* default 29 */
+ // lgw_reg_w(LGW_FRAME_SYNCH_GAIN,1); /* default 1 */
+ // lgw_reg_w(LGW_SYNCH_DETECT_TH,1); /* default 1 */
+ // lgw_reg_w(LGW_ZERO_PAD,0); /* default 0 */
+ lgw_reg_w(LGW_SNR_AVG_CST,3); /* default 2 */
+ if (lorawan_public) { /* LoRa network */
+ lgw_reg_w(LGW_FRAME_SYNCH_PEAK1_POS,3); /* default 1 */
+ lgw_reg_w(LGW_FRAME_SYNCH_PEAK2_POS,4); /* default 2 */
+ } else { /* private network */
+ lgw_reg_w(LGW_FRAME_SYNCH_PEAK1_POS,1); /* default 1 */
+ lgw_reg_w(LGW_FRAME_SYNCH_PEAK2_POS,2); /* default 2 */
+ }
+
+ // lgw_reg_w(LGW_PREAMBLE_FINE_TIMING_GAIN,1); /* default 1 */
+ // lgw_reg_w(LGW_ONLY_CRC_EN,1); /* default 1 */
+ // lgw_reg_w(LGW_PAYLOAD_FINE_TIMING_GAIN,2); /* default 2 */
+ // lgw_reg_w(LGW_TRACKING_INTEGRAL,0); /* default 0 */
+ // lgw_reg_w(LGW_ADJUST_MODEM_START_OFFSET_RDX8,0); /* default 0 */
+ // lgw_reg_w(LGW_ADJUST_MODEM_START_OFFSET_SF12_RDX4,4092); /* default 4092 */
+ // lgw_reg_w(LGW_MAX_PAYLOAD_LEN,255); /* default 255 */
+
+ /* LoRa standalone 'MBWSSF' demodulator setup */
+ // lgw_reg_w(LGW_MBWSSF_PREAMBLE_SYMB1_NB,10); /* default 10 */
+ // lgw_reg_w(LGW_MBWSSF_FREQ_TO_TIME_INVERT,29); /* default 29 */
+ // lgw_reg_w(LGW_MBWSSF_FRAME_SYNCH_GAIN,1); /* default 1 */
+ // lgw_reg_w(LGW_MBWSSF_SYNCH_DETECT_TH,1); /* default 1 */
+ // lgw_reg_w(LGW_MBWSSF_ZERO_PAD,0); /* default 0 */
+ if (lorawan_public) { /* LoRa network */
+ lgw_reg_w(LGW_MBWSSF_FRAME_SYNCH_PEAK1_POS,3); /* default 1 */
+ lgw_reg_w(LGW_MBWSSF_FRAME_SYNCH_PEAK2_POS,4); /* default 2 */
+ } else {
+ lgw_reg_w(LGW_MBWSSF_FRAME_SYNCH_PEAK1_POS,1); /* default 1 */
+ lgw_reg_w(LGW_MBWSSF_FRAME_SYNCH_PEAK2_POS,2); /* default 2 */
+ }
+ // lgw_reg_w(LGW_MBWSSF_ONLY_CRC_EN,1); /* default 1 */
+ // lgw_reg_w(LGW_MBWSSF_PAYLOAD_FINE_TIMING_GAIN,2); /* default 2 */
+ // lgw_reg_w(LGW_MBWSSF_PREAMBLE_FINE_TIMING_GAIN,1); /* default 1 */
+ // lgw_reg_w(LGW_MBWSSF_TRACKING_INTEGRAL,0); /* default 0 */
+ // lgw_reg_w(LGW_MBWSSF_AGC_FREEZE_ON_DETECT,1); /* default 1 */
+
+ /* Improvement of reference clock frequency error tolerance */
+ lgw_reg_w(LGW_ADJUST_MODEM_START_OFFSET_RDX4, 1); /* default 0 */
+ lgw_reg_w(LGW_ADJUST_MODEM_START_OFFSET_SF12_RDX4, 4094); /* default 4092 */
+ lgw_reg_w(LGW_CORR_MAC_GAIN, 7); /* default 5 */
+
+ /* FSK datapath setup */
+ lgw_reg_w(LGW_FSK_RX_INVERT,1); /* default 0 */
+ lgw_reg_w(LGW_FSK_MODEM_INVERT_IQ,1); /* default 0 */
+
+ /* FSK demodulator setup */
+ lgw_reg_w(LGW_FSK_RSSI_LENGTH,4); /* default 0 */
+ lgw_reg_w(LGW_FSK_PKT_MODE,1); /* variable length, default 0 */
+ lgw_reg_w(LGW_FSK_CRC_EN,1); /* default 0 */
+ lgw_reg_w(LGW_FSK_DCFREE_ENC,2); /* default 0 */
+ // lgw_reg_w(LGW_FSK_CRC_IBM,0); /* default 0 */
+ lgw_reg_w(LGW_FSK_ERROR_OSR_TOL,10); /* default 0 */
+ lgw_reg_w(LGW_FSK_PKT_LENGTH,255); /* max packet length in variable length mode */
+ // lgw_reg_w(LGW_FSK_NODE_ADRS,0); /* default 0 */
+ // lgw_reg_w(LGW_FSK_BROADCAST,0); /* default 0 */
+ // lgw_reg_w(LGW_FSK_AUTO_AFC_ON,0); /* default 0 */
+ lgw_reg_w(LGW_FSK_PATTERN_TIMEOUT_CFG,128); /* sync timeout (allow 8 bytes preamble + 8 bytes sync word, default 0 */
+
+ /* TX general parameters */
+ lgw_reg_w(LGW_TX_START_DELAY, TX_START_DELAY_DEFAULT); /* default 0 */
+
+ /* TX LoRa */
+ // lgw_reg_w(LGW_TX_MODE,0); /* default 0 */
+ lgw_reg_w(LGW_TX_SWAP_IQ,1); /* "normal" polarity; default 0 */
+ if (lorawan_public) { /* LoRa network */
+ lgw_reg_w(LGW_TX_FRAME_SYNCH_PEAK1_POS,3); /* default 1 */
+ lgw_reg_w(LGW_TX_FRAME_SYNCH_PEAK2_POS,4); /* default 2 */
+ } else { /* Private network */
+ lgw_reg_w(LGW_TX_FRAME_SYNCH_PEAK1_POS,1); /* default 1 */
+ lgw_reg_w(LGW_TX_FRAME_SYNCH_PEAK2_POS,2); /* default 2 */
+ }
+
+ /* TX FSK */
+ // lgw_reg_w(LGW_FSK_TX_GAUSSIAN_EN,1); /* default 1 */
+ lgw_reg_w(LGW_FSK_TX_GAUSSIAN_SELECT_BT,2); /* Gaussian filter always on TX, default 0 */
+ // lgw_reg_w(LGW_FSK_TX_PATTERN_EN,1); /* default 1 */
+ // lgw_reg_w(LGW_FSK_TX_PREAMBLE_SEQ,0); /* default 0 */
+
+ return;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int32_t lgw_bw_getval(int x) {
+ switch (x) {
+ case BW_500KHZ: return 500000;
+ case BW_250KHZ: return 250000;
+ case BW_125KHZ: return 125000;
+ case BW_62K5HZ: return 62500;
+ case BW_31K2HZ: return 31200;
+ case BW_15K6HZ: return 15600;
+ case BW_7K8HZ : return 7800;
+ default: return -1;
+ }
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int32_t lgw_sf_getval(int x) {
+ switch (x) {
+ case DR_LORA_SF7: return 7;
+ case DR_LORA_SF8: return 8;
+ case DR_LORA_SF9: return 9;
+ case DR_LORA_SF10: return 10;
+ case DR_LORA_SF11: return 11;
+ case DR_LORA_SF12: return 12;
+ default: return -1;
+ }
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+uint16_t lgw_get_tx_start_delay(bool tx_notch_enable, uint8_t bw) {
+ float notch_delay_us = 0.0;
+ float bw_delay_us = 0.0;
+ float tx_start_delay;
+
+ /* Notch filtering performed by FPGA adds a constant delay (group delay) that we need to compensate */
+ if (tx_notch_enable) {
+ notch_delay_us = lgw_fpga_get_tx_notch_delay();
+ }
+
+ /* Calibrated delay brought by SX1301 depending on signal bandwidth */
+ switch (bw) {
+ case BW_125KHZ:
+ bw_delay_us = 1.5;
+ break;
+ case BW_500KHZ:
+ /* Intended fall-through: it is the calibrated reference */
+ default:
+ break;
+ }
+
+ tx_start_delay = (float)TX_START_DELAY_DEFAULT - bw_delay_us - notch_delay_us;
+
+ printf("INFO: tx_start_delay=%u (%f) - (%u, bw_delay=%f, notch_delay=%f)\n", (uint16_t)tx_start_delay, tx_start_delay, TX_START_DELAY_DEFAULT, bw_delay_us, notch_delay_us);
+
+ return (uint16_t)tx_start_delay; /* keep truncating instead of rounding: better behaviour measured */
+}
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC FUNCTIONS DEFINITION ------------------------------------------ */
+
+int lgw_board_setconf(struct lgw_conf_board_s conf) {
+
+ /* check if the concentrator is running */
+ if (lgw_is_started == true) {
+ DEBUG_MSG("ERROR: CONCENTRATOR IS RUNNING, STOP IT BEFORE TOUCHING CONFIGURATION\n");
+ return LGW_HAL_ERROR;
+ }
+
+ /* set internal config according to parameters */
+ lorawan_public = conf.lorawan_public;
+ rf_clkout = conf.clksrc;
+
+ DEBUG_PRINTF("Note: board configuration; lorawan_public:%d, clksrc:%d\n", lorawan_public, rf_clkout);
+
+ return LGW_HAL_SUCCESS;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int lgw_lbt_setconf(struct lgw_conf_lbt_s conf) {
+ int x;
+
+ /* check if the concentrator is running */
+ if (lgw_is_started == true) {
+ DEBUG_MSG("ERROR: CONCENTRATOR IS RUNNING, STOP IT BEFORE TOUCHING CONFIGURATION\n");
+ return LGW_HAL_ERROR;
+ }
+
+ x = lbt_setconf(&conf);
+ if (x != LGW_LBT_SUCCESS) {
+ DEBUG_MSG("ERROR: Failed to configure concentrator for LBT\n");
+ return LGW_HAL_ERROR;
+ }
+
+ return LGW_HAL_SUCCESS;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int lgw_rxrf_setconf(uint8_t rf_chain, struct lgw_conf_rxrf_s conf) {
+
+ /* check if the concentrator is running */
+ if (lgw_is_started == true) {
+ DEBUG_MSG("ERROR: CONCENTRATOR IS RUNNING, STOP IT BEFORE TOUCHING CONFIGURATION\n");
+ return LGW_HAL_ERROR;
+ }
+
+ /* check input range (segfault prevention) */
+ if (rf_chain >= LGW_RF_CHAIN_NB) {
+ DEBUG_MSG("ERROR: NOT A VALID RF_CHAIN NUMBER\n");
+ return LGW_HAL_ERROR;
+ }
+
+ /* check if radio type is supported */
+ if ((conf.type != LGW_RADIO_TYPE_SX1255) && (conf.type != LGW_RADIO_TYPE_SX1257)) {
+ DEBUG_MSG("ERROR: NOT A VALID RADIO TYPE\n");
+ return LGW_HAL_ERROR;
+ }
+
+ /* check if TX notch filter frequency is supported */
+ if ((conf.tx_enable == true) && ((conf.tx_notch_freq < LGW_MIN_NOTCH_FREQ) || (conf.tx_notch_freq > LGW_MAX_NOTCH_FREQ))) {
+ DEBUG_PRINTF("WARNING: NOT A VALID TX NOTCH FILTER FREQUENCY [%u..%u]Hz\n", LGW_MIN_NOTCH_FREQ, LGW_MAX_NOTCH_FREQ);
+ conf.tx_notch_freq = 0;
+ }
+
+ /* set internal config according to parameters */
+ rf_enable[rf_chain] = conf.enable;
+ rf_rx_freq[rf_chain] = conf.freq_hz;
+ rf_rssi_offset[rf_chain] = conf.rssi_offset;
+ rf_radio_type[rf_chain] = conf.type;
+ rf_tx_enable[rf_chain] = conf.tx_enable;
+ rf_tx_notch_freq[rf_chain] = conf.tx_notch_freq;
+
+ DEBUG_PRINTF("Note: rf_chain %d configuration; en:%d freq:%d rssi_offset:%f radio_type:%d tx_enable:%d tx_notch_freq:%u\n", rf_chain, rf_enable[rf_chain], rf_rx_freq[rf_chain], rf_rssi_offset[rf_chain], rf_radio_type[rf_chain], rf_tx_enable[rf_chain], rf_tx_notch_freq[rf_chain]);
+
+ return LGW_HAL_SUCCESS;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int lgw_rxif_setconf(uint8_t if_chain, struct lgw_conf_rxif_s conf) {
+ int32_t bw_hz;
+ uint32_t rf_rx_bandwidth;
+
+ /* check if the concentrator is running */
+ if (lgw_is_started == true) {
+ DEBUG_MSG("ERROR: CONCENTRATOR IS RUNNING, STOP IT BEFORE TOUCHING CONFIGURATION\n");
+ return LGW_HAL_ERROR;
+ }
+
+ /* check input range (segfault prevention) */
+ if (if_chain >= LGW_IF_CHAIN_NB) {
+ DEBUG_PRINTF("ERROR: %d NOT A VALID IF_CHAIN NUMBER\n", if_chain);
+ return LGW_HAL_ERROR;
+ }
+
+ /* if chain is disabled, don't care about most parameters */
+ if (conf.enable == false) {
+ if_enable[if_chain] = false;
+ if_freq[if_chain] = 0;
+ DEBUG_PRINTF("Note: if_chain %d disabled\n", if_chain);
+ return LGW_HAL_SUCCESS;
+ }
+
+ /* check 'general' parameters */
+ if (ifmod_config[if_chain] == IF_UNDEFINED) {
+ DEBUG_PRINTF("ERROR: IF CHAIN %d NOT CONFIGURABLE\n", if_chain);
+ }
+ if (conf.rf_chain >= LGW_RF_CHAIN_NB) {
+ DEBUG_MSG("ERROR: INVALID RF_CHAIN TO ASSOCIATE WITH A LORA_STD IF CHAIN\n");
+ return LGW_HAL_ERROR;
+ }
+ /* check if IF frequency is optimal based on channel and radio bandwidths */
+ switch (conf.bandwidth) {
+ case BW_250KHZ:
+ rf_rx_bandwidth = LGW_RF_RX_BANDWIDTH_250KHZ; /* radio bandwidth */
+ break;
+ case BW_500KHZ:
+ rf_rx_bandwidth = LGW_RF_RX_BANDWIDTH_500KHZ; /* radio bandwidth */
+ break;
+ default:
+ /* For 125KHz and below */
+ rf_rx_bandwidth = LGW_RF_RX_BANDWIDTH_125KHZ; /* radio bandwidth */
+ break;
+ }
+ bw_hz = lgw_bw_getval(conf.bandwidth); /* channel bandwidth */
+ if ((conf.freq_hz + ((bw_hz==-1)?LGW_REF_BW:bw_hz)/2) > ((int32_t)rf_rx_bandwidth/2)) {
+ DEBUG_PRINTF("ERROR: IF FREQUENCY %d TOO HIGH\n", conf.freq_hz);
+ return LGW_HAL_ERROR;
+ } else if ((conf.freq_hz - ((bw_hz==-1)?LGW_REF_BW:bw_hz)/2) < -((int32_t)rf_rx_bandwidth/2)) {
+ DEBUG_PRINTF("ERROR: IF FREQUENCY %d TOO LOW\n", conf.freq_hz);
+ return LGW_HAL_ERROR;
+ }
+
+ /* check parameters according to the type of IF chain + modem,
+ fill default if necessary, and commit configuration if everything is OK */
+ switch (ifmod_config[if_chain]) {
+ case IF_LORA_STD:
+ /* fill default parameters if needed */
+ if (conf.bandwidth == BW_UNDEFINED) {
+ conf.bandwidth = BW_250KHZ;
+ }
+ if (conf.datarate == DR_UNDEFINED) {
+ conf.datarate = DR_LORA_SF9;
+ }
+ /* check BW & DR */
+ if (!IS_LORA_BW(conf.bandwidth)) {
+ DEBUG_MSG("ERROR: BANDWIDTH NOT SUPPORTED BY LORA_STD IF CHAIN\n");
+ return LGW_HAL_ERROR;
+ }
+ if (!IS_LORA_STD_DR(conf.datarate)) {
+ DEBUG_MSG("ERROR: DATARATE NOT SUPPORTED BY LORA_STD IF CHAIN\n");
+ return LGW_HAL_ERROR;
+ }
+ /* set internal configuration */
+ if_enable[if_chain] = conf.enable;
+ if_rf_chain[if_chain] = conf.rf_chain;
+ if_freq[if_chain] = conf.freq_hz;
+ lora_rx_bw = conf.bandwidth;
+ lora_rx_sf = (uint8_t)(DR_LORA_MULTI & conf.datarate); /* filter SF out of the 7-12 range */
+ if (SET_PPM_ON(conf.bandwidth, conf.datarate)) {
+ lora_rx_ppm_offset = true;
+ } else {
+ lora_rx_ppm_offset = false;
+ }
+
+ DEBUG_PRINTF("Note: LoRa 'std' if_chain %d configuration; en:%d freq:%d bw:%d dr:%d\n", if_chain, if_enable[if_chain], if_freq[if_chain], lora_rx_bw, lora_rx_sf);
+ break;
+
+ case IF_LORA_MULTI:
+ /* fill default parameters if needed */
+ if (conf.bandwidth == BW_UNDEFINED) {
+ conf.bandwidth = BW_125KHZ;
+ }
+ if (conf.datarate == DR_UNDEFINED) {
+ conf.datarate = DR_LORA_MULTI;
+ }
+ /* check BW & DR */
+ if (conf.bandwidth != BW_125KHZ) {
+ DEBUG_MSG("ERROR: BANDWIDTH NOT SUPPORTED BY LORA_MULTI IF CHAIN\n");
+ return LGW_HAL_ERROR;
+ }
+ if (!IS_LORA_MULTI_DR(conf.datarate)) {
+ DEBUG_MSG("ERROR: DATARATE(S) NOT SUPPORTED BY LORA_MULTI IF CHAIN\n");
+ return LGW_HAL_ERROR;
+ }
+ /* set internal configuration */
+ if_enable[if_chain] = conf.enable;
+ if_rf_chain[if_chain] = conf.rf_chain;
+ if_freq[if_chain] = conf.freq_hz;
+ lora_multi_sfmask[if_chain] = (uint8_t)(DR_LORA_MULTI & conf.datarate); /* filter SF out of the 7-12 range */
+
+ DEBUG_PRINTF("Note: LoRa 'multi' if_chain %d configuration; en:%d freq:%d SF_mask:0x%02x\n", if_chain, if_enable[if_chain], if_freq[if_chain], lora_multi_sfmask[if_chain]);
+ break;
+
+ case IF_FSK_STD:
+ /* fill default parameters if needed */
+ if (conf.bandwidth == BW_UNDEFINED) {
+ conf.bandwidth = BW_250KHZ;
+ }
+ if (conf.datarate == DR_UNDEFINED) {
+ conf.datarate = 64000; /* default datarate */
+ }
+ /* check BW & DR */
+ if(!IS_FSK_BW(conf.bandwidth)) {
+ DEBUG_MSG("ERROR: BANDWIDTH NOT SUPPORTED BY FSK IF CHAIN\n");
+ return LGW_HAL_ERROR;
+ }
+ if(!IS_FSK_DR(conf.datarate)) {
+ DEBUG_MSG("ERROR: DATARATE NOT SUPPORTED BY FSK IF CHAIN\n");
+ return LGW_HAL_ERROR;
+ }
+ /* set internal configuration */
+ if_enable[if_chain] = conf.enable;
+ if_rf_chain[if_chain] = conf.rf_chain;
+ if_freq[if_chain] = conf.freq_hz;
+ fsk_rx_bw = conf.bandwidth;
+ fsk_rx_dr = conf.datarate;
+ if (conf.sync_word > 0) {
+ fsk_sync_word_size = conf.sync_word_size;
+ fsk_sync_word = conf.sync_word;
+ }
+ DEBUG_PRINTF("Note: FSK if_chain %d configuration; en:%d freq:%d bw:%d dr:%d (%d real dr) sync:0x%0*llX\n", if_chain, if_enable[if_chain], if_freq[if_chain], fsk_rx_bw, fsk_rx_dr, LGW_XTAL_FREQU/(LGW_XTAL_FREQU/fsk_rx_dr), 2*fsk_sync_word_size, fsk_sync_word);
+ break;
+
+ default:
+ DEBUG_PRINTF("ERROR: IF CHAIN %d TYPE NOT SUPPORTED\n", if_chain);
+ return LGW_HAL_ERROR;
+ }
+
+ return LGW_HAL_SUCCESS;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int lgw_txgain_setconf(struct lgw_tx_gain_lut_s *conf) {
+ int i;
+
+ /* Check LUT size */
+ if ((conf->size < 1) || (conf->size > TX_GAIN_LUT_SIZE_MAX)) {
+ DEBUG_PRINTF("ERROR: TX gain LUT must have at least one entry and maximum %d entries\n", TX_GAIN_LUT_SIZE_MAX);
+ return LGW_HAL_ERROR;
+ }
+
+ txgain_lut.size = conf->size;
+
+ for (i = 0; i < txgain_lut.size; i++) {
+ /* Check gain range */
+ if (conf->lut[i].dig_gain > 3) {
+ DEBUG_MSG("ERROR: TX gain LUT: SX1301 digital gain must be between 0 and 3\n");
+ return LGW_HAL_ERROR;
+ }
+ if (conf->lut[i].dac_gain != 3) {
+ DEBUG_MSG("ERROR: TX gain LUT: SX1257 DAC gains != 3 are not supported\n");
+ return LGW_HAL_ERROR;
+ }
+ if (conf->lut[i].mix_gain > 15) {
+ DEBUG_MSG("ERROR: TX gain LUT: SX1257 mixer gain must not exceed 15\n");
+ return LGW_HAL_ERROR;
+ } else if (conf->lut[i].mix_gain < 8) {
+ DEBUG_MSG("ERROR: TX gain LUT: SX1257 mixer gains < 8 are not supported\n");
+ return LGW_HAL_ERROR;
+ }
+ if (conf->lut[i].pa_gain > 3) {
+ DEBUG_MSG("ERROR: TX gain LUT: External PA gain must not exceed 3\n");
+ return LGW_HAL_ERROR;
+ }
+
+ /* Set internal LUT */
+ txgain_lut.lut[i].dig_gain = conf->lut[i].dig_gain;
+ txgain_lut.lut[i].dac_gain = conf->lut[i].dac_gain;
+ txgain_lut.lut[i].mix_gain = conf->lut[i].mix_gain;
+ txgain_lut.lut[i].pa_gain = conf->lut[i].pa_gain;
+ txgain_lut.lut[i].rf_power = conf->lut[i].rf_power;
+ }
+
+ return LGW_HAL_SUCCESS;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int lgw_start(void) {
+ int i, err;
+ int reg_stat;
+ unsigned x;
+ uint8_t radio_select;
+ int32_t read_val;
+ uint8_t load_val;
+ uint8_t fw_version;
+ uint8_t cal_cmd;
+ uint16_t cal_time;
+ uint8_t cal_status;
+
+ uint64_t fsk_sync_word_reg;
+
+ if (lgw_is_started == true) {
+ DEBUG_MSG("Note: LoRa concentrator already started, restarting it now\n");
+ }
+
+ reg_stat = lgw_connect(false, rf_tx_notch_freq[rf_tx_enable[1]?1:0]);
+ if (reg_stat == LGW_REG_ERROR) {
+ DEBUG_MSG("ERROR: FAIL TO CONNECT BOARD\n");
+ return LGW_HAL_ERROR;
+ }
+
+ /* reset the registers (also shuts the radios down) */
+ lgw_soft_reset();
+
+ /* gate clocks */
+ lgw_reg_w(LGW_GLOBAL_EN, 0);
+ lgw_reg_w(LGW_CLK32M_EN, 0);
+
+ /* switch on and reset the radios (also starts the 32 MHz XTAL) */
+ lgw_reg_w(LGW_RADIO_A_EN,1);
+ lgw_reg_w(LGW_RADIO_B_EN,1);
+ wait_ms(500); /* TODO: optimize */
+ lgw_reg_w(LGW_RADIO_RST,1);
+ wait_ms(5);
+ lgw_reg_w(LGW_RADIO_RST,0);
+
+ /* setup the radios */
+ err = lgw_setup_sx125x(0, rf_clkout, rf_enable[0], rf_radio_type[0], rf_rx_freq[0]);
+ if (err != 0) {
+ DEBUG_MSG("ERROR: Failed to setup sx125x radio for RF chain 0\n");
+ return LGW_HAL_ERROR;
+ }
+ err = lgw_setup_sx125x(1, rf_clkout, rf_enable[1], rf_radio_type[1], rf_rx_freq[1]);
+ if (err != 0) {
+ DEBUG_MSG("ERROR: Failed to setup sx125x radio for RF chain 0\n");
+ return LGW_HAL_ERROR;
+ }
+
+ /* gives AGC control of GPIOs to enable Tx external digital filter */
+ lgw_reg_w(LGW_GPIO_MODE,31); /* Set all GPIOs as output */
+ lgw_reg_w(LGW_GPIO_SELECT_OUTPUT,2);
+
+ /* Configure LBT */
+ if (lbt_is_enabled() == true) {
+ lgw_reg_w(LGW_CLK32M_EN, 1);
+ i = lbt_setup();
+ if (i != LGW_LBT_SUCCESS) {
+ DEBUG_MSG("ERROR: lbt_setup() did not return SUCCESS\n");
+ return LGW_HAL_ERROR;
+ }
+
+ /* Start SX1301 counter and LBT FSM at the same time to be in sync */
+ lgw_reg_w(LGW_CLK32M_EN, 0);
+ i = lbt_start();
+ if (i != LGW_LBT_SUCCESS) {
+ DEBUG_MSG("ERROR: lbt_start() did not return SUCCESS\n");
+ return LGW_HAL_ERROR;
+ }
+ }
+
+ /* Enable clocks */
+ lgw_reg_w(LGW_GLOBAL_EN, 1);
+ lgw_reg_w(LGW_CLK32M_EN, 1);
+
+ /* GPIOs table :
+ DGPIO0 -> N/A
+ DGPIO1 -> N/A
+ DGPIO2 -> N/A
+ DGPIO3 -> TX digital filter ON
+ DGPIO4 -> TX ON
+ */
+
+ /* select calibration command */
+ cal_cmd = 0;
+ cal_cmd |= rf_enable[0] ? 0x01 : 0x00; /* Bit 0: Calibrate Rx IQ mismatch compensation on radio A */
+ cal_cmd |= rf_enable[1] ? 0x02 : 0x00; /* Bit 1: Calibrate Rx IQ mismatch compensation on radio B */
+ cal_cmd |= (rf_enable[0] && rf_tx_enable[0]) ? 0x04 : 0x00; /* Bit 2: Calibrate Tx DC offset on radio A */
+ cal_cmd |= (rf_enable[1] && rf_tx_enable[1]) ? 0x08 : 0x00; /* Bit 3: Calibrate Tx DC offset on radio B */
+ cal_cmd |= 0x10; /* Bit 4: 0: calibrate with DAC gain=2, 1: with DAC gain=3 (use 3) */
+
+ switch (rf_radio_type[0]) { /* we assume that there is only one radio type on the board */
+ case LGW_RADIO_TYPE_SX1255:
+ cal_cmd |= 0x20; /* Bit 5: 0: SX1257, 1: SX1255 */
+ break;
+ case LGW_RADIO_TYPE_SX1257:
+ cal_cmd |= 0x00; /* Bit 5: 0: SX1257, 1: SX1255 */
+ break;
+ default:
+ DEBUG_PRINTF("ERROR: UNEXPECTED VALUE %d FOR RADIO TYPE\n", rf_radio_type[0]);
+ break;
+ }
+
+ cal_cmd |= 0x00; /* Bit 6-7: Board type 0: ref, 1: FPGA, 3: board X */
+ cal_time = 2300; /* measured between 2.1 and 2.2 sec, because 1 TX only */
+
+ /* Load the calibration firmware */
+ load_firmware(MCU_AGC, cal_firmware, MCU_AGC_FW_BYTE);
+ lgw_reg_w(LGW_FORCE_HOST_RADIO_CTRL, 0); /* gives to AGC MCU the control of the radios */
+ lgw_reg_w(LGW_RADIO_SELECT, cal_cmd); /* send calibration configuration word */
+ lgw_reg_w(LGW_MCU_RST_1, 0);
+
+ /* Check firmware version */
+ lgw_reg_w(LGW_DBG_AGC_MCU_RAM_ADDR, FW_VERSION_ADDR);
+ lgw_reg_r(LGW_DBG_AGC_MCU_RAM_DATA, &read_val);
+ fw_version = (uint8_t)read_val;
+ if (fw_version != FW_VERSION_CAL) {
+ printf("ERROR: Version of calibration firmware not expected, actual:%d expected:%d\n", fw_version, FW_VERSION_CAL);
+ return -1;
+ }
+
+ lgw_reg_w(LGW_PAGE_REG, 3); /* Calibration will start on this condition as soon as MCU can talk to concentrator registers */
+ lgw_reg_w(LGW_EMERGENCY_FORCE_HOST_CTRL, 0); /* Give control of concentrator registers to MCU */
+
+ /* Wait for calibration to end */
+ DEBUG_PRINTF("Note: calibration started (time: %u ms)\n", cal_time);
+ wait_ms(cal_time); /* Wait for end of calibration */
+ lgw_reg_w(LGW_EMERGENCY_FORCE_HOST_CTRL, 1); /* Take back control */
+
+ /* Get calibration status */
+ lgw_reg_r(LGW_MCU_AGC_STATUS, &read_val);
+ cal_status = (uint8_t)read_val;
+ /*
+ bit 7: calibration finished
+ bit 0: could access SX1301 registers
+ bit 1: could access radio A registers
+ bit 2: could access radio B registers
+ bit 3: radio A RX image rejection successful
+ bit 4: radio B RX image rejection successful
+ bit 5: radio A TX DC Offset correction successful
+ bit 6: radio B TX DC Offset correction successful
+ */
+ if ((cal_status & 0x81) != 0x81) {
+ DEBUG_PRINTF("ERROR: CALIBRATION FAILURE (STATUS = %u)\n", cal_status);
+ return LGW_HAL_ERROR;
+ } else {
+ DEBUG_PRINTF("Note: calibration finished (status = %u)\n", cal_status);
+ }
+ if (rf_enable[0] && ((cal_status & 0x02) == 0)) {
+ DEBUG_MSG("WARNING: calibration could not access radio A\n");
+ }
+ if (rf_enable[1] && ((cal_status & 0x04) == 0)) {
+ DEBUG_MSG("WARNING: calibration could not access radio B\n");
+ }
+ if (rf_enable[0] && ((cal_status & 0x08) == 0)) {
+ DEBUG_MSG("WARNING: problem in calibration of radio A for image rejection\n");
+ }
+ if (rf_enable[1] && ((cal_status & 0x10) == 0)) {
+ DEBUG_MSG("WARNING: problem in calibration of radio B for image rejection\n");
+ }
+ if (rf_enable[0] && rf_tx_enable[0] && ((cal_status & 0x20) == 0)) {
+ DEBUG_MSG("WARNING: problem in calibration of radio A for TX DC offset\n");
+ }
+ if (rf_enable[1] && rf_tx_enable[1] && ((cal_status & 0x40) == 0)) {
+ DEBUG_MSG("WARNING: problem in calibration of radio B for TX DC offset\n");
+ }
+
+ /* Get TX DC offset values */
+ for(i=0; i<=7; ++i) {
+ lgw_reg_w(LGW_DBG_AGC_MCU_RAM_ADDR, 0xA0+i);
+ lgw_reg_r(LGW_DBG_AGC_MCU_RAM_DATA, &read_val);
+ cal_offset_a_i[i] = (int8_t)read_val;
+ lgw_reg_w(LGW_DBG_AGC_MCU_RAM_ADDR, 0xA8+i);
+ lgw_reg_r(LGW_DBG_AGC_MCU_RAM_DATA, &read_val);
+ cal_offset_a_q[i] = (int8_t)read_val;
+ lgw_reg_w(LGW_DBG_AGC_MCU_RAM_ADDR, 0xB0+i);
+ lgw_reg_r(LGW_DBG_AGC_MCU_RAM_DATA, &read_val);
+ cal_offset_b_i[i] = (int8_t)read_val;
+ lgw_reg_w(LGW_DBG_AGC_MCU_RAM_ADDR, 0xB8+i);
+ lgw_reg_r(LGW_DBG_AGC_MCU_RAM_DATA, &read_val);
+ cal_offset_b_q[i] = (int8_t)read_val;
+ }
+
+ /* load adjusted parameters */
+ lgw_constant_adjust();
+
+ /* Sanity check for RX frequency */
+ if (rf_rx_freq[0] == 0) {
+ DEBUG_MSG("ERROR: wrong configuration, rf_rx_freq[0] is not set\n");
+ return LGW_HAL_ERROR;
+ }
+
+ /* Freq-to-time-drift calculation */
+ x = 4096000000 / (rf_rx_freq[0] >> 1); /* dividend: (4*2048*1000000) >> 1, rescaled to avoid 32b overflow */
+ x = ( x > 63 ) ? 63 : x; /* saturation */
+ lgw_reg_w(LGW_FREQ_TO_TIME_DRIFT, x); /* default 9 */
+
+ x = 4096000000 / (rf_rx_freq[0] >> 3); /* dividend: (16*2048*1000000) >> 3, rescaled to avoid 32b overflow */
+ x = ( x > 63 ) ? 63 : x; /* saturation */
+ lgw_reg_w(LGW_MBWSSF_FREQ_TO_TIME_DRIFT, x); /* default 36 */
+
+ /* configure LoRa 'multi' demodulators aka. LoRa 'sensor' channels (IF0-3) */
+ radio_select = 0; /* IF mapping to radio A/B (per bit, 0=A, 1=B) */
+ for(i=0; i<LGW_MULTI_NB; ++i) {
+ radio_select += (if_rf_chain[i] == 1 ? 1 << i : 0); /* transform bool array into binary word */
+ }
+ /*
+ lgw_reg_w(LGW_RADIO_SELECT, radio_select);
+
+ LGW_RADIO_SELECT is used for communication with the firmware, "radio_select"
+ will be loaded in LGW_RADIO_SELECT at the end of start procedure.
+ */
+
+ lgw_reg_w(LGW_IF_FREQ_0, IF_HZ_TO_REG(if_freq[0])); /* default -384 */
+ lgw_reg_w(LGW_IF_FREQ_1, IF_HZ_TO_REG(if_freq[1])); /* default -128 */
+ lgw_reg_w(LGW_IF_FREQ_2, IF_HZ_TO_REG(if_freq[2])); /* default 128 */
+ lgw_reg_w(LGW_IF_FREQ_3, IF_HZ_TO_REG(if_freq[3])); /* default 384 */
+ lgw_reg_w(LGW_IF_FREQ_4, IF_HZ_TO_REG(if_freq[4])); /* default -384 */
+ lgw_reg_w(LGW_IF_FREQ_5, IF_HZ_TO_REG(if_freq[5])); /* default -128 */
+ lgw_reg_w(LGW_IF_FREQ_6, IF_HZ_TO_REG(if_freq[6])); /* default 128 */
+ lgw_reg_w(LGW_IF_FREQ_7, IF_HZ_TO_REG(if_freq[7])); /* default 384 */
+
+ lgw_reg_w(LGW_CORR0_DETECT_EN, (if_enable[0] == true) ? lora_multi_sfmask[0] : 0); /* default 0 */
+ lgw_reg_w(LGW_CORR1_DETECT_EN, (if_enable[1] == true) ? lora_multi_sfmask[1] : 0); /* default 0 */
+ lgw_reg_w(LGW_CORR2_DETECT_EN, (if_enable[2] == true) ? lora_multi_sfmask[2] : 0); /* default 0 */
+ lgw_reg_w(LGW_CORR3_DETECT_EN, (if_enable[3] == true) ? lora_multi_sfmask[3] : 0); /* default 0 */
+ lgw_reg_w(LGW_CORR4_DETECT_EN, (if_enable[4] == true) ? lora_multi_sfmask[4] : 0); /* default 0 */
+ lgw_reg_w(LGW_CORR5_DETECT_EN, (if_enable[5] == true) ? lora_multi_sfmask[5] : 0); /* default 0 */
+ lgw_reg_w(LGW_CORR6_DETECT_EN, (if_enable[6] == true) ? lora_multi_sfmask[6] : 0); /* default 0 */
+ lgw_reg_w(LGW_CORR7_DETECT_EN, (if_enable[7] == true) ? lora_multi_sfmask[7] : 0); /* default 0 */
+
+ lgw_reg_w(LGW_PPM_OFFSET, 0x60); /* as the threshold is 16ms, use 0x60 to enable ppm_offset for SF12 and SF11 @125kHz*/
+
+ lgw_reg_w(LGW_CONCENTRATOR_MODEM_ENABLE, 1); /* default 0 */
+
+ /* configure LoRa 'stand-alone' modem (IF8) */
+ lgw_reg_w(LGW_IF_FREQ_8, IF_HZ_TO_REG(if_freq[8])); /* MBWSSF modem (default 0) */
+ if (if_enable[8] == true) {
+ lgw_reg_w(LGW_MBWSSF_RADIO_SELECT, if_rf_chain[8]);
+ switch(lora_rx_bw) {
+ case BW_125KHZ: lgw_reg_w(LGW_MBWSSF_MODEM_BW, 0); break;
+ case BW_250KHZ: lgw_reg_w(LGW_MBWSSF_MODEM_BW, 1); break;
+ case BW_500KHZ: lgw_reg_w(LGW_MBWSSF_MODEM_BW, 2); break;
+ default:
+ DEBUG_PRINTF("ERROR: UNEXPECTED VALUE %d IN SWITCH STATEMENT\n", lora_rx_bw);
+ return LGW_HAL_ERROR;
+ }
+ switch(lora_rx_sf) {
+ case DR_LORA_SF7: lgw_reg_w(LGW_MBWSSF_RATE_SF, 7); break;
+ case DR_LORA_SF8: lgw_reg_w(LGW_MBWSSF_RATE_SF, 8); break;
+ case DR_LORA_SF9: lgw_reg_w(LGW_MBWSSF_RATE_SF, 9); break;
+ case DR_LORA_SF10: lgw_reg_w(LGW_MBWSSF_RATE_SF, 10); break;
+ case DR_LORA_SF11: lgw_reg_w(LGW_MBWSSF_RATE_SF, 11); break;
+ case DR_LORA_SF12: lgw_reg_w(LGW_MBWSSF_RATE_SF, 12); break;
+ default:
+ DEBUG_PRINTF("ERROR: UNEXPECTED VALUE %d IN SWITCH STATEMENT\n", lora_rx_sf);
+ return LGW_HAL_ERROR;
+ }
+ lgw_reg_w(LGW_MBWSSF_PPM_OFFSET, lora_rx_ppm_offset); /* default 0 */
+ lgw_reg_w(LGW_MBWSSF_MODEM_ENABLE, 1); /* default 0 */
+ } else {
+ lgw_reg_w(LGW_MBWSSF_MODEM_ENABLE, 0);
+ }
+
+ /* configure FSK modem (IF9) */
+ lgw_reg_w(LGW_IF_FREQ_9, IF_HZ_TO_REG(if_freq[9])); /* FSK modem, default 0 */
+ lgw_reg_w(LGW_FSK_PSIZE, fsk_sync_word_size-1);
+ lgw_reg_w(LGW_FSK_TX_PSIZE, fsk_sync_word_size-1);
+ fsk_sync_word_reg = fsk_sync_word << (8 * (8 - fsk_sync_word_size));
+ lgw_reg_w(LGW_FSK_REF_PATTERN_LSB, (uint32_t)(0xFFFFFFFF & fsk_sync_word_reg));
+ lgw_reg_w(LGW_FSK_REF_PATTERN_MSB, (uint32_t)(0xFFFFFFFF & (fsk_sync_word_reg >> 32)));
+ if (if_enable[9] == true) {
+ lgw_reg_w(LGW_FSK_RADIO_SELECT, if_rf_chain[9]);
+ lgw_reg_w(LGW_FSK_BR_RATIO, LGW_XTAL_FREQU/fsk_rx_dr); /* setting the dividing ratio for datarate */
+ lgw_reg_w(LGW_FSK_CH_BW_EXPO, fsk_rx_bw);
+ lgw_reg_w(LGW_FSK_MODEM_ENABLE, 1); /* default 0 */
+ } else {
+ lgw_reg_w(LGW_FSK_MODEM_ENABLE, 0);
+ }
+
+ /* Load firmware */
+ load_firmware(MCU_ARB, arb_firmware, MCU_ARB_FW_BYTE);
+ load_firmware(MCU_AGC, agc_firmware, MCU_AGC_FW_BYTE);
+
+ /* gives the AGC MCU control over radio, RF front-end and filter gain */
+ lgw_reg_w(LGW_FORCE_HOST_RADIO_CTRL, 0);
+ lgw_reg_w(LGW_FORCE_HOST_FE_CTRL, 0);
+ lgw_reg_w(LGW_FORCE_DEC_FILTER_GAIN, 0);
+
+ /* Get MCUs out of reset */
+ lgw_reg_w(LGW_RADIO_SELECT, 0); /* MUST not be = to 1 or 2 at firmware init */
+ lgw_reg_w(LGW_MCU_RST_0, 0);
+ lgw_reg_w(LGW_MCU_RST_1, 0);
+
+ /* Check firmware version */
+ lgw_reg_w(LGW_DBG_AGC_MCU_RAM_ADDR, FW_VERSION_ADDR);
+ lgw_reg_r(LGW_DBG_AGC_MCU_RAM_DATA, &read_val);
+ fw_version = (uint8_t)read_val;
+ if (fw_version != FW_VERSION_AGC) {
+ DEBUG_PRINTF("ERROR: Version of AGC firmware not expected, actual:%d expected:%d\n", fw_version, FW_VERSION_AGC);
+ return LGW_HAL_ERROR;
+ }
+ lgw_reg_w(LGW_DBG_ARB_MCU_RAM_ADDR, FW_VERSION_ADDR);
+ lgw_reg_r(LGW_DBG_ARB_MCU_RAM_DATA, &read_val);
+ fw_version = (uint8_t)read_val;
+ if (fw_version != FW_VERSION_ARB) {
+ DEBUG_PRINTF("ERROR: Version of arbiter firmware not expected, actual:%d expected:%d\n", fw_version, FW_VERSION_ARB);
+ return LGW_HAL_ERROR;
+ }
+
+ DEBUG_MSG("Info: Initialising AGC firmware...\n");
+ wait_ms(1);
+
+ lgw_reg_r(LGW_MCU_AGC_STATUS, &read_val);
+ if (read_val != 0x10) {
+ DEBUG_PRINTF("ERROR: AGC FIRMWARE INITIALIZATION FAILURE, STATUS 0x%02X\n", (uint8_t)read_val);
+ return LGW_HAL_ERROR;
+ }
+
+ /* Update Tx gain LUT and start AGC */
+ for (i = 0; i < txgain_lut.size; ++i) {
+ lgw_reg_w(LGW_RADIO_SELECT, AGC_CMD_WAIT); /* start a transaction */
+ wait_ms(1);
+ load_val = txgain_lut.lut[i].mix_gain + (16 * txgain_lut.lut[i].dac_gain) + (64 * txgain_lut.lut[i].pa_gain);
+ lgw_reg_w(LGW_RADIO_SELECT, load_val);
+ wait_ms(1);
+ lgw_reg_r(LGW_MCU_AGC_STATUS, &read_val);
+ if (read_val != (0x30 + i)) {
+ DEBUG_PRINTF("ERROR: AGC FIRMWARE INITIALIZATION FAILURE, STATUS 0x%02X\n", (uint8_t)read_val);
+ return LGW_HAL_ERROR;
+ }
+ }
+ /* As the AGC fw is waiting for 16 entries, we need to abort the transaction if we get less entries */
+ if (txgain_lut.size < TX_GAIN_LUT_SIZE_MAX) {
+ lgw_reg_w(LGW_RADIO_SELECT, AGC_CMD_WAIT);
+ wait_ms(1);
+ load_val = AGC_CMD_ABORT;
+ lgw_reg_w(LGW_RADIO_SELECT, load_val);
+ wait_ms(1);
+ lgw_reg_r(LGW_MCU_AGC_STATUS, &read_val);
+ if (read_val != 0x30) {
+ DEBUG_PRINTF("ERROR: AGC FIRMWARE INITIALIZATION FAILURE, STATUS 0x%02X\n", (uint8_t)read_val);
+ return LGW_HAL_ERROR;
+ }
+ }
+
+ /* Load Tx freq MSBs (always 3 if f > 768 for SX1257 or f > 384 for SX1255 */
+ lgw_reg_w(LGW_RADIO_SELECT, AGC_CMD_WAIT);
+ wait_ms(1);
+ lgw_reg_w(LGW_RADIO_SELECT, 3);
+ wait_ms(1);
+ lgw_reg_r(LGW_MCU_AGC_STATUS, &read_val);
+ if (read_val != 0x33) {
+ DEBUG_PRINTF("ERROR: AGC FIRMWARE INITIALIZATION FAILURE, STATUS 0x%02X\n", (uint8_t)read_val);
+ return LGW_HAL_ERROR;
+ }
+
+ /* Load chan_select firmware option */
+ lgw_reg_w(LGW_RADIO_SELECT, AGC_CMD_WAIT);
+ wait_ms(1);
+ lgw_reg_w(LGW_RADIO_SELECT, 0);
+ wait_ms(1);
+ lgw_reg_r(LGW_MCU_AGC_STATUS, &read_val);
+ if (read_val != 0x30) {
+ DEBUG_PRINTF("ERROR: AGC FIRMWARE INITIALIZATION FAILURE, STATUS 0x%02X\n", (uint8_t)read_val);
+ return LGW_HAL_ERROR;
+ }
+
+ /* End AGC firmware init and check status */
+ lgw_reg_w(LGW_RADIO_SELECT, AGC_CMD_WAIT);
+ wait_ms(1);
+ lgw_reg_w(LGW_RADIO_SELECT, radio_select); /* Load intended value of RADIO_SELECT */
+ wait_ms(1);
+ DEBUG_MSG("Info: putting back original RADIO_SELECT value\n");
+ lgw_reg_r(LGW_MCU_AGC_STATUS, &read_val);
+ if (read_val != 0x40) {
+ DEBUG_PRINTF("ERROR: AGC FIRMWARE INITIALIZATION FAILURE, STATUS 0x%02X\n", (uint8_t)read_val);
+ return LGW_HAL_ERROR;
+ }
+
+ /* enable GPS event capture */
+ lgw_reg_w(LGW_GPS_EN, 1);
+
+ /* */
+ if (lbt_is_enabled() == true) {
+ printf("INFO: Configuring LBT, this may take few seconds, please wait...\n");
+ wait_ms(8400);
+ }
+
+ lgw_is_started = true;
+ return LGW_HAL_SUCCESS;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int lgw_stop(void) {
+ lgw_soft_reset();
+ lgw_disconnect();
+
+ lgw_is_started = false;
+ return LGW_HAL_SUCCESS;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int lgw_receive(uint8_t max_pkt, struct lgw_pkt_rx_s *pkt_data) {
+ int nb_pkt_fetch; /* loop variable and return value */
+ struct lgw_pkt_rx_s *p; /* pointer to the current structure in the struct array */
+ uint8_t buff[255+RX_METADATA_NB]; /* buffer to store the result of SPI read bursts */
+ unsigned sz; /* size of the payload, uses to address metadata */
+ int ifmod; /* type of if_chain/modem a packet was received by */
+ int stat_fifo; /* the packet status as indicated in the FIFO */
+ uint32_t raw_timestamp; /* timestamp when internal 'RX finished' was triggered */
+ uint32_t delay_x, delay_y, delay_z; /* temporary variable for timestamp offset calculation */
+ uint32_t timestamp_correction; /* correction to account for processing delay */
+ uint32_t sf, cr, bw_pow, crc_en, ppm; /* used to calculate timestamp correction */
+
+ /* check if the concentrator is running */
+ if (lgw_is_started == false) {
+ DEBUG_MSG("ERROR: CONCENTRATOR IS NOT RUNNING, START IT BEFORE RECEIVING\n");
+ return LGW_HAL_ERROR;
+ }
+
+ /* check input variables */
+ if ((max_pkt <= 0) || (max_pkt > LGW_PKT_FIFO_SIZE)) {
+ DEBUG_PRINTF("ERROR: %d = INVALID MAX NUMBER OF PACKETS TO FETCH\n", max_pkt);
+ return LGW_HAL_ERROR;
+ }
+ CHECK_NULL(pkt_data);
+
+ /* Initialize buffer */
+ memset (buff, 0, sizeof buff);
+
+ /* iterate max_pkt times at most */
+ for (nb_pkt_fetch = 0; nb_pkt_fetch < max_pkt; ++nb_pkt_fetch) {
+
+ /* point to the proper struct in the struct array */
+ p = &pkt_data[nb_pkt_fetch];
+
+ /* fetch all the RX FIFO data */
+ lgw_reg_rb(LGW_RX_PACKET_DATA_FIFO_NUM_STORED, buff, 5);
+ /* 0: number of packets available in RX data buffer */
+ /* 1,2: start address of the current packet in RX data buffer */
+ /* 3: CRC status of the current packet */
+ /* 4: size of the current packet payload in byte */
+
+ /* how many packets are in the RX buffer ? Break if zero */
+ if (buff[0] == 0) {
+ break; /* no more packets to fetch, exit out of FOR loop */
+ }
+
+ /* sanity check */
+ if (buff[0] > LGW_PKT_FIFO_SIZE) {
+ DEBUG_PRINTF("WARNING: %u = INVALID NUMBER OF PACKETS TO FETCH, ABORTING\n", buff[0]);
+ break;
+ }
+
+ DEBUG_PRINTF("FIFO content: %x %x %x %x %x\n", buff[0], buff[1], buff[2], buff[3], buff[4]);
+
+ p->size = buff[4];
+ sz = p->size;
+ stat_fifo = buff[3]; /* will be used later, need to save it before overwriting buff */
+
+ /* get payload + metadata */
+ lgw_reg_rb(LGW_RX_DATA_BUF_DATA, buff, sz+RX_METADATA_NB);
+
+ /* copy payload to result struct */
+ memcpy((void *)p->payload, (void *)buff, sz);
+
+ /* process metadata */
+ p->if_chain = buff[sz+0];
+ if (p->if_chain >= LGW_IF_CHAIN_NB) {
+ DEBUG_PRINTF("WARNING: %u NOT A VALID IF_CHAIN NUMBER, ABORTING\n", p->if_chain);
+ break;
+ }
+ ifmod = ifmod_config[p->if_chain];
+ DEBUG_PRINTF("[%d %d]\n", p->if_chain, ifmod);
+
+ p->rf_chain = (uint8_t)if_rf_chain[p->if_chain];
+ p->freq_hz = (uint32_t)((int32_t)rf_rx_freq[p->rf_chain] + if_freq[p->if_chain]);
+ p->rssi = (float)buff[sz+5] + rf_rssi_offset[p->rf_chain];
+
+ if ((ifmod == IF_LORA_MULTI) || (ifmod == IF_LORA_STD)) {
+ DEBUG_MSG("Note: LoRa packet\n");
+ switch(stat_fifo & 0x07) {
+ case 5:
+ p->status = STAT_CRC_OK;
+ crc_en = 1;
+ break;
+ case 7:
+ p->status = STAT_CRC_BAD;
+ crc_en = 1;
+ break;
+ case 1:
+ p->status = STAT_NO_CRC;
+ crc_en = 0;
+ break;
+ default:
+ p->status = STAT_UNDEFINED;
+ crc_en = 0;
+ }
+ p->modulation = MOD_LORA;
+ p->snr = ((float)((int8_t)buff[sz+2]))/4;
+ p->snr_min = ((float)((int8_t)buff[sz+3]))/4;
+ p->snr_max = ((float)((int8_t)buff[sz+4]))/4;
+ if (ifmod == IF_LORA_MULTI) {
+ p->bandwidth = BW_125KHZ; /* fixed in hardware */
+ } else {
+ p->bandwidth = lora_rx_bw; /* get the parameter from the config variable */
+ }
+ sf = (buff[sz+1] >> 4) & 0x0F;
+ switch (sf) {
+ case 7: p->datarate = DR_LORA_SF7; break;
+ case 8: p->datarate = DR_LORA_SF8; break;
+ case 9: p->datarate = DR_LORA_SF9; break;
+ case 10: p->datarate = DR_LORA_SF10; break;
+ case 11: p->datarate = DR_LORA_SF11; break;
+ case 12: p->datarate = DR_LORA_SF12; break;
+ default: p->datarate = DR_UNDEFINED;
+ }
+ cr = (buff[sz+1] >> 1) & 0x07;
+ switch (cr) {
+ case 1: p->coderate = CR_LORA_4_5; break;
+ case 2: p->coderate = CR_LORA_4_6; break;
+ case 3: p->coderate = CR_LORA_4_7; break;
+ case 4: p->coderate = CR_LORA_4_8; break;
+ default: p->coderate = CR_UNDEFINED;
+ }
+
+ /* determine if 'PPM mode' is on, needed for timestamp correction */
+ if (SET_PPM_ON(p->bandwidth,p->datarate)) {
+ ppm = 1;
+ } else {
+ ppm = 0;
+ }
+
+ /* timestamp correction code, base delay */
+ if (ifmod == IF_LORA_STD) { /* if packet was received on the stand-alone LoRa modem */
+ switch (lora_rx_bw) {
+ case BW_125KHZ:
+ delay_x = 64;
+ bw_pow = 1;
+ break;
+ case BW_250KHZ:
+ delay_x = 32;
+ bw_pow = 2;
+ break;
+ case BW_500KHZ:
+ delay_x = 16;
+ bw_pow = 4;
+ break;
+ default:
+ DEBUG_PRINTF("ERROR: UNEXPECTED VALUE %d IN SWITCH STATEMENT\n", p->bandwidth);
+ delay_x = 0;
+ bw_pow = 0;
+ }
+ } else { /* packet was received on one of the sensor channels = 125kHz */
+ delay_x = 114;
+ bw_pow = 1;
+ }
+
+ /* timestamp correction code, variable delay */
+ if ((sf >= 6) && (sf <= 12) && (bw_pow > 0)) {
+ if ((2*(sz + 2*crc_en) - (sf-7)) <= 0) { /* payload fits entirely in first 8 symbols */
+ delay_y = ( ((1<<(sf-1)) * (sf+1)) + (3 * (1<<(sf-4))) ) / bw_pow;
+ delay_z = 32 * (2*(sz+2*crc_en) + 5) / bw_pow;
+ } else {
+ delay_y = ( ((1<<(sf-1)) * (sf+1)) + ((4 - ppm) * (1<<(sf-4))) ) / bw_pow;
+ delay_z = (16 + 4*cr) * (((2*(sz+2*crc_en)-sf+6) % (sf - 2*ppm)) + 1) / bw_pow;
+ }
+ timestamp_correction = delay_x + delay_y + delay_z;
+ } else {
+ timestamp_correction = 0;
+ DEBUG_MSG("WARNING: invalid packet, no timestamp correction\n");
+ }
+
+ /* RSSI correction */
+ if (ifmod == IF_LORA_MULTI) {
+ p->rssi -= RSSI_MULTI_BIAS;
+ }
+
+ } else if (ifmod == IF_FSK_STD) {
+ DEBUG_MSG("Note: FSK packet\n");
+ switch(stat_fifo & 0x07) {
+ case 5:
+ p->status = STAT_CRC_OK;
+ break;
+ case 7:
+ p->status = STAT_CRC_BAD;
+ break;
+ case 1:
+ p->status = STAT_NO_CRC;
+ break;
+ default:
+ p->status = STAT_UNDEFINED;
+ break;
+ }
+ p->modulation = MOD_FSK;
+ p->snr = -128.0;
+ p->snr_min = -128.0;
+ p->snr_max = -128.0;
+ p->bandwidth = fsk_rx_bw;
+ p->datarate = fsk_rx_dr;
+ p->coderate = CR_UNDEFINED;
+ timestamp_correction = ((uint32_t)680000 / fsk_rx_dr) - 20;
+
+ /* RSSI correction */
+ p->rssi = RSSI_FSK_POLY_0 + RSSI_FSK_POLY_1 * p->rssi + RSSI_FSK_POLY_2 * pow(p->rssi, 2);
+ } else {
+ DEBUG_MSG("ERROR: UNEXPECTED PACKET ORIGIN\n");
+ p->status = STAT_UNDEFINED;
+ p->modulation = MOD_UNDEFINED;
+ p->rssi = -128.0;
+ p->snr = -128.0;
+ p->snr_min = -128.0;
+ p->snr_max = -128.0;
+ p->bandwidth = BW_UNDEFINED;
+ p->datarate = DR_UNDEFINED;
+ p->coderate = CR_UNDEFINED;
+ timestamp_correction = 0;
+ }
+
+ raw_timestamp = (uint32_t)buff[sz+6] + ((uint32_t)buff[sz+7] << 8) + ((uint32_t)buff[sz+8] << 16) + ((uint32_t)buff[sz+9] << 24);
+ p->count_us = raw_timestamp - timestamp_correction;
+ p->crc = (uint16_t)buff[sz+10] + ((uint16_t)buff[sz+11] << 8);
+
+ /* advance packet FIFO */
+ lgw_reg_w(LGW_RX_PACKET_DATA_FIFO_NUM_STORED, 0);
+ }
+
+ return nb_pkt_fetch;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int lgw_send(struct lgw_pkt_tx_s pkt_data) {
+ int i, x;
+ uint8_t buff[256+TX_METADATA_NB]; /* buffer to prepare the packet to send + metadata before SPI write burst */
+ uint32_t part_int = 0; /* integer part for PLL register value calculation */
+ uint32_t part_frac = 0; /* fractional part for PLL register value calculation */
+ uint16_t fsk_dr_div; /* divider to configure for target datarate */
+ int transfer_size = 0; /* data to transfer from host to TX databuffer */
+ int payload_offset = 0; /* start of the payload content in the databuffer */
+ uint8_t pow_index = 0; /* 4-bit value to set the firmware TX power */
+ uint8_t target_mix_gain = 0; /* used to select the proper I/Q offset correction */
+ uint32_t count_trig = 0; /* timestamp value in trigger mode corrected for TX start delay */
+ bool tx_allowed = false;
+ uint16_t tx_start_delay;
+ bool tx_notch_enable = false;
+
+ /* check if the concentrator is running */
+ if (lgw_is_started == false) {
+ DEBUG_MSG("ERROR: CONCENTRATOR IS NOT RUNNING, START IT BEFORE SENDING\n");
+ return LGW_HAL_ERROR;
+ }
+
+ /* check input range (segfault prevention) */
+ if (pkt_data.rf_chain >= LGW_RF_CHAIN_NB) {
+ DEBUG_MSG("ERROR: INVALID RF_CHAIN TO SEND PACKETS\n");
+ return LGW_HAL_ERROR;
+ }
+
+ /* check input variables */
+ if (rf_tx_enable[pkt_data.rf_chain] == false) {
+ DEBUG_MSG("ERROR: SELECTED RF_CHAIN IS DISABLED FOR TX ON SELECTED BOARD\n");
+ return LGW_HAL_ERROR;
+ }
+ if (rf_enable[pkt_data.rf_chain] == false) {
+ DEBUG_MSG("ERROR: SELECTED RF_CHAIN IS DISABLED\n");
+ return LGW_HAL_ERROR;
+ }
+ if (!IS_TX_MODE(pkt_data.tx_mode)) {
+ DEBUG_MSG("ERROR: TX_MODE NOT SUPPORTED\n");
+ return LGW_HAL_ERROR;
+ }
+ if (pkt_data.modulation == MOD_LORA) {
+ if (!IS_LORA_BW(pkt_data.bandwidth)) {
+ DEBUG_MSG("ERROR: BANDWIDTH NOT SUPPORTED BY LORA TX\n");
+ return LGW_HAL_ERROR;
+ }
+ if (!IS_LORA_STD_DR(pkt_data.datarate)) {
+ DEBUG_MSG("ERROR: DATARATE NOT SUPPORTED BY LORA TX\n");
+ return LGW_HAL_ERROR;
+ }
+ if (!IS_LORA_CR(pkt_data.coderate)) {
+ DEBUG_MSG("ERROR: CODERATE NOT SUPPORTED BY LORA TX\n");
+ return LGW_HAL_ERROR;
+ }
+ if (pkt_data.size > 255) {
+ DEBUG_MSG("ERROR: PAYLOAD LENGTH TOO BIG FOR LORA TX\n");
+ return LGW_HAL_ERROR;
+ }
+ } else if (pkt_data.modulation == MOD_FSK) {
+ if((pkt_data.f_dev < 1) || (pkt_data.f_dev > 200)) {
+ DEBUG_MSG("ERROR: TX FREQUENCY DEVIATION OUT OF ACCEPTABLE RANGE\n");
+ return LGW_HAL_ERROR;
+ }
+ if(!IS_FSK_DR(pkt_data.datarate)) {
+ DEBUG_MSG("ERROR: DATARATE NOT SUPPORTED BY FSK IF CHAIN\n");
+ return LGW_HAL_ERROR;
+ }
+ if (pkt_data.size > 255) {
+ DEBUG_MSG("ERROR: PAYLOAD LENGTH TOO BIG FOR FSK TX\n");
+ return LGW_HAL_ERROR;
+ }
+ } else {
+ DEBUG_MSG("ERROR: INVALID TX MODULATION\n");
+ return LGW_HAL_ERROR;
+ }
+
+ /* Enable notch filter for LoRa 125kHz */
+ if ((pkt_data.modulation == MOD_LORA) && (pkt_data.bandwidth == BW_125KHZ)) {
+ tx_notch_enable = true;
+ }
+
+ /* Get the TX start delay to be applied for this TX */
+ tx_start_delay = lgw_get_tx_start_delay(tx_notch_enable, pkt_data.bandwidth);
+
+ /* interpretation of TX power */
+ for (pow_index = txgain_lut.size-1; pow_index > 0; pow_index--) {
+ if (txgain_lut.lut[pow_index].rf_power <= pkt_data.rf_power) {
+ break;
+ }
+ }
+
+ /* loading TX imbalance correction */
+ target_mix_gain = txgain_lut.lut[pow_index].mix_gain;
+ if (pkt_data.rf_chain == 0) { /* use radio A calibration table */
+ lgw_reg_w(LGW_TX_OFFSET_I, cal_offset_a_i[target_mix_gain - 8]);
+ lgw_reg_w(LGW_TX_OFFSET_Q, cal_offset_a_q[target_mix_gain - 8]);
+ } else { /* use radio B calibration table */
+ lgw_reg_w(LGW_TX_OFFSET_I, cal_offset_b_i[target_mix_gain - 8]);
+ lgw_reg_w(LGW_TX_OFFSET_Q, cal_offset_b_q[target_mix_gain - 8]);
+ }
+
+ /* Set digital gain from LUT */
+ lgw_reg_w(LGW_TX_GAIN, txgain_lut.lut[pow_index].dig_gain);
+
+ /* fixed metadata, useful payload and misc metadata compositing */
+ transfer_size = TX_METADATA_NB + pkt_data.size; /* */
+ payload_offset = TX_METADATA_NB; /* start the payload just after the metadata */
+
+ /* metadata 0 to 2, TX PLL frequency */
+ switch (rf_radio_type[0]) { /* we assume that there is only one radio type on the board */
+ case LGW_RADIO_TYPE_SX1255:
+ part_int = pkt_data.freq_hz / (SX125x_32MHz_FRAC << 7); /* integer part, gives the MSB */
+ part_frac = ((pkt_data.freq_hz % (SX125x_32MHz_FRAC << 7)) << 9) / SX125x_32MHz_FRAC; /* fractional part, gives middle part and LSB */
+ break;
+ case LGW_RADIO_TYPE_SX1257:
+ part_int = pkt_data.freq_hz / (SX125x_32MHz_FRAC << 8); /* integer part, gives the MSB */
+ part_frac = ((pkt_data.freq_hz % (SX125x_32MHz_FRAC << 8)) << 8) / SX125x_32MHz_FRAC; /* fractional part, gives middle part and LSB */
+ break;
+ default:
+ DEBUG_PRINTF("ERROR: UNEXPECTED VALUE %d FOR RADIO TYPE\n", rf_radio_type[0]);
+ break;
+ }
+
+ buff[0] = 0xFF & part_int; /* Most Significant Byte */
+ buff[1] = 0xFF & (part_frac >> 8); /* middle byte */
+ buff[2] = 0xFF & part_frac; /* Least Significant Byte */
+
+ /* metadata 3 to 6, timestamp trigger value */
+ /* TX state machine must be triggered at (T0 - lgw_i_tx_start_delay_us) for packet to start being emitted at T0 */
+ if (pkt_data.tx_mode == TIMESTAMPED)
+ {
+ count_trig = pkt_data.count_us - (uint32_t)tx_start_delay;
+ buff[3] = 0xFF & (count_trig >> 24);
+ buff[4] = 0xFF & (count_trig >> 16);
+ buff[5] = 0xFF & (count_trig >> 8);
+ buff[6] = 0xFF & count_trig;
+ }
+
+ /* parameters depending on modulation */
+ if (pkt_data.modulation == MOD_LORA) {
+ /* metadata 7, modulation type, radio chain selection and TX power */
+ buff[7] = (0x20 & (pkt_data.rf_chain << 5)) | (0x0F & pow_index); /* bit 4 is 0 -> LoRa modulation */
+
+ buff[8] = 0; /* metadata 8, not used */
+
+ /* metadata 9, CRC, LoRa CR & SF */
+ switch (pkt_data.datarate) {
+ case DR_LORA_SF7: buff[9] = 7; break;
+ case DR_LORA_SF8: buff[9] = 8; break;
+ case DR_LORA_SF9: buff[9] = 9; break;
+ case DR_LORA_SF10: buff[9] = 10; break;
+ case DR_LORA_SF11: buff[9] = 11; break;
+ case DR_LORA_SF12: buff[9] = 12; break;
+ default: DEBUG_PRINTF("ERROR: UNEXPECTED VALUE %d IN SWITCH STATEMENT\n", pkt_data.datarate);
+ }
+ switch (pkt_data.coderate) {
+ case CR_LORA_4_5: buff[9] |= 1 << 4; break;
+ case CR_LORA_4_6: buff[9] |= 2 << 4; break;
+ case CR_LORA_4_7: buff[9] |= 3 << 4; break;
+ case CR_LORA_4_8: buff[9] |= 4 << 4; break;
+ default: DEBUG_PRINTF("ERROR: UNEXPECTED VALUE %d IN SWITCH STATEMENT\n", pkt_data.coderate);
+ }
+ if (pkt_data.no_crc == false) {
+ buff[9] |= 0x80; /* set 'CRC enable' bit */
+ } else {
+ DEBUG_MSG("Info: packet will be sent without CRC\n");
+ }
+
+ /* metadata 10, payload size */
+ buff[10] = pkt_data.size;
+
+ /* metadata 11, implicit header, modulation bandwidth, PPM offset & polarity */
+ switch (pkt_data.bandwidth) {
+ case BW_125KHZ: buff[11] = 0; break;
+ case BW_250KHZ: buff[11] = 1; break;
+ case BW_500KHZ: buff[11] = 2; break;
+ default: DEBUG_PRINTF("ERROR: UNEXPECTED VALUE %d IN SWITCH STATEMENT\n", pkt_data.bandwidth);
+ }
+ if (pkt_data.no_header == true) {
+ buff[11] |= 0x04; /* set 'implicit header' bit */
+ }
+ if (SET_PPM_ON(pkt_data.bandwidth,pkt_data.datarate)) {
+ buff[11] |= 0x08; /* set 'PPM offset' bit at 1 */
+ }
+ if (pkt_data.invert_pol == true) {
+ buff[11] |= 0x10; /* set 'TX polarity' bit at 1 */
+ }
+
+ /* metadata 12 & 13, LoRa preamble size */
+ if (pkt_data.preamble == 0) { /* if not explicit, use recommended LoRa preamble size */
+ pkt_data.preamble = STD_LORA_PREAMBLE;
+ } else if (pkt_data.preamble < MIN_LORA_PREAMBLE) { /* enforce minimum preamble size */
+ pkt_data.preamble = MIN_LORA_PREAMBLE;
+ DEBUG_MSG("Note: preamble length adjusted to respect minimum LoRa preamble size\n");
+ }
+ buff[12] = 0xFF & (pkt_data.preamble >> 8);
+ buff[13] = 0xFF & pkt_data.preamble;
+
+ /* metadata 14 & 15, not used */
+ buff[14] = 0;
+ buff[15] = 0;
+
+ /* MSB of RF frequency is now used in AGC firmware to implement large/narrow filtering in SX1257/55 */
+ buff[0] &= 0x3F; /* Unset 2 MSBs of frequency code */
+ if (pkt_data.bandwidth == BW_500KHZ) {
+ buff[0] |= 0x80; /* Set MSB bit to enlarge analog filter for 500kHz BW */
+ }
+
+ /* Set MSB-1 bit to enable digital filter if required */
+ if (tx_notch_enable == true) {
+ DEBUG_MSG("INFO: Enabling TX notch filter\n");
+ buff[0] |= 0x40;
+ }
+ } else if (pkt_data.modulation == MOD_FSK) {
+ /* metadata 7, modulation type, radio chain selection and TX power */
+ buff[7] = (0x20 & (pkt_data.rf_chain << 5)) | 0x10 | (0x0F & pow_index); /* bit 4 is 1 -> FSK modulation */
+
+ buff[8] = 0; /* metadata 8, not used */
+
+ /* metadata 9, frequency deviation */
+ buff[9] = pkt_data.f_dev;
+
+ /* metadata 10, payload size */
+ buff[10] = pkt_data.size;
+ /* TODO: how to handle 255 bytes packets ?!? */
+
+ /* metadata 11, packet mode, CRC, encoding */
+ buff[11] = 0x01 | (pkt_data.no_crc?0:0x02) | (0x02 << 2); /* always in variable length packet mode, whitening, and CCITT CRC if CRC is not disabled */
+
+ /* metadata 12 & 13, FSK preamble size */
+ if (pkt_data.preamble == 0) { /* if not explicit, use LoRa MAC preamble size */
+ pkt_data.preamble = STD_FSK_PREAMBLE;
+ } else if (pkt_data.preamble < MIN_FSK_PREAMBLE) { /* enforce minimum preamble size */
+ pkt_data.preamble = MIN_FSK_PREAMBLE;
+ DEBUG_MSG("Note: preamble length adjusted to respect minimum FSK preamble size\n");
+ }
+ buff[12] = 0xFF & (pkt_data.preamble >> 8);
+ buff[13] = 0xFF & pkt_data.preamble;
+
+ /* metadata 14 & 15, FSK baudrate */
+ fsk_dr_div = (uint16_t)((uint32_t)LGW_XTAL_FREQU / pkt_data.datarate); /* Ok for datarate between 500bps and 250kbps */
+ buff[14] = 0xFF & (fsk_dr_div >> 8);
+ buff[15] = 0xFF & fsk_dr_div;
+
+ /* insert payload size in the packet for variable mode */
+ buff[16] = pkt_data.size;
+ ++transfer_size; /* one more byte to transfer to the TX modem */
+ ++payload_offset; /* start the payload with one more byte of offset */
+
+ /* MSB of RF frequency is now used in AGC firmware to implement large/narrow filtering in SX1257/55 */
+ buff[0] &= 0x7F; /* Always use narrow band for FSK (force MSB to 0) */
+
+ } else {
+ DEBUG_MSG("ERROR: INVALID TX MODULATION..\n");
+ return LGW_HAL_ERROR;
+ }
+
+ /* Configure TX start delay based on TX notch filter */
+ lgw_reg_w(LGW_TX_START_DELAY, tx_start_delay);
+
+ /* copy payload from user struct to buffer containing metadata */
+ memcpy((void *)(buff + payload_offset), (void *)(pkt_data.payload), pkt_data.size);
+
+ /* reset TX command flags */
+ lgw_abort_tx();
+
+ /* put metadata + payload in the TX data buffer */
+ lgw_reg_w(LGW_TX_DATA_BUF_ADDR, 0);
+ lgw_reg_wb(LGW_TX_DATA_BUF_DATA, buff, transfer_size);
+ DEBUG_ARRAY(i, transfer_size, buff);
+
+ x = lbt_is_channel_free(&pkt_data, tx_start_delay, &tx_allowed);
+ if (x != LGW_LBT_SUCCESS) {
+ DEBUG_MSG("ERROR: Failed to check channel availability for TX\n");
+ return LGW_HAL_ERROR;
+ }
+ if (tx_allowed == true) {
+ switch(pkt_data.tx_mode) {
+ case IMMEDIATE:
+ lgw_reg_w(LGW_TX_TRIG_IMMEDIATE, 1);
+ break;
+
+ case TIMESTAMPED:
+ lgw_reg_w(LGW_TX_TRIG_DELAYED, 1);
+ break;
+
+ case ON_GPS:
+ lgw_reg_w(LGW_TX_TRIG_GPS, 1);
+ break;
+
+ default:
+ DEBUG_PRINTF("ERROR: UNEXPECTED VALUE %d IN SWITCH STATEMENT\n", pkt_data.tx_mode);
+ return LGW_HAL_ERROR;
+ }
+ } else {
+ DEBUG_MSG("ERROR: Cannot send packet, channel is busy (LBT)\n");
+ return LGW_LBT_ISSUE;
+ }
+
+ return LGW_HAL_SUCCESS;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int lgw_status(uint8_t select, uint8_t *code) {
+ int32_t read_value;
+
+ /* check input variables */
+ CHECK_NULL(code);
+
+ if (select == TX_STATUS) {
+ lgw_reg_r(LGW_TX_STATUS, &read_value);
+ if (lgw_is_started == false) {
+ *code = TX_OFF;
+ } else if ((read_value & 0x10) == 0) { /* bit 4 @1: TX programmed */
+ *code = TX_FREE;
+ } else if ((read_value & 0x60) != 0) { /* bit 5 or 6 @1: TX sequence */
+ *code = TX_EMITTING;
+ } else {
+ *code = TX_SCHEDULED;
+ }
+ return LGW_HAL_SUCCESS;
+
+ } else if (select == RX_STATUS) {
+ *code = RX_STATUS_UNKNOWN; /* todo */
+ return LGW_HAL_SUCCESS;
+
+ } else {
+ DEBUG_MSG("ERROR: SELECTION INVALID, NO STATUS TO RETURN\n");
+ return LGW_HAL_ERROR;
+ }
+
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int lgw_abort_tx(void) {
+ int i;
+
+ i = lgw_reg_w(LGW_TX_TRIG_ALL, 0);
+
+ if (i == LGW_REG_SUCCESS) return LGW_HAL_SUCCESS;
+ else return LGW_HAL_ERROR;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int lgw_get_trigcnt(uint32_t* trig_cnt_us) {
+ int i;
+ int32_t val;
+
+ i = lgw_reg_r(LGW_TIMESTAMP, &val);
+ if (i == LGW_REG_SUCCESS) {
+ *trig_cnt_us = (uint32_t)val;
+ return LGW_HAL_SUCCESS;
+ } else {
+ return LGW_HAL_ERROR;
+ }
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+const char* lgw_version_info() {
+ return lgw_version_string;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+uint32_t lgw_time_on_air(struct lgw_pkt_tx_s *packet) {
+ int32_t val;
+ uint8_t SF, H, DE;
+ uint16_t BW;
+ uint32_t payloadSymbNb, Tpacket;
+ double Tsym, Tpreamble, Tpayload, Tfsk;
+
+ if (packet == NULL) {
+ DEBUG_MSG("ERROR: Failed to compute time on air, wrong parameter\n");
+ return 0;
+ }
+
+ if (packet->modulation == MOD_LORA) {
+ /* Get bandwidth */
+ val = lgw_bw_getval(packet->bandwidth);
+ if (val != -1) {
+ BW = (uint16_t)(val / 1E3);
+ } else {
+ DEBUG_PRINTF("ERROR: Cannot compute time on air for this packet, unsupported bandwidth (0x%02X)\n", packet->bandwidth);
+ return 0;
+ }
+
+ /* Get datarate */
+ val = lgw_sf_getval(packet->datarate);
+ if (val != -1) {
+ SF = (uint8_t)val;
+ } else {
+ DEBUG_PRINTF("ERROR: Cannot compute time on air for this packet, unsupported datarate (0x%02X)\n", packet->datarate);
+ return 0;
+ }
+
+ /* Duration of 1 symbol */
+ Tsym = pow(2, SF) / BW;
+
+ /* Duration of preamble */
+ Tpreamble = ((double)(packet->preamble) + 4.25) * Tsym;
+
+ /* Duration of payload */
+ H = (packet->no_header==false) ? 0 : 1; /* header is always enabled, except for beacons */
+ DE = (SF >= 11) ? 1 : 0; /* Low datarate optimization enabled for SF11 and SF12 */
+
+ payloadSymbNb = 8 + (ceil((double)(8*packet->size - 4*SF + 28 + 16 - 20*H) / (double)(4*(SF - 2*DE))) * (packet->coderate + 4)); /* Explicitely cast to double to keep precision of the division */
+
+ Tpayload = payloadSymbNb * Tsym;
+
+ /* Duration of packet */
+ Tpacket = Tpreamble + Tpayload;
+ } else if (packet->modulation == MOD_FSK) {
+ /* PREAMBLE + SYNC_WORD + PKT_LEN + PKT_PAYLOAD + CRC
+ PREAMBLE: default 5 bytes
+ SYNC_WORD: default 3 bytes
+ PKT_LEN: 1 byte (variable length mode)
+ PKT_PAYLOAD: x bytes
+ CRC: 0 or 2 bytes
+ */
+ Tfsk = (8 * (double)(packet->preamble + fsk_sync_word_size + 1 + packet->size + ((packet->no_crc == true) ? 0 : 2)) / (double)packet->datarate) * 1E3;
+
+ /* Duration of packet */
+ Tpacket = (uint32_t)Tfsk + 1; /* add margin for rounding */
+ } else {
+ Tpacket = 0;
+ DEBUG_PRINTF("ERROR: Cannot compute time on air for this packet, unsupported modulation (0x%02X)\n", packet->modulation);
+ }
+
+ return Tpacket;
+}
+
+/* --- EOF ------------------------------------------------------------------ */
diff --git a/libloragw/src/loragw_lbt.c b/libloragw/src/loragw_lbt.c
new file mode 100644
index 0000000..9c43521
--- /dev/null
+++ b/libloragw/src/loragw_lbt.c
@@ -0,0 +1,391 @@
+/*
+ / _____) _ | |
+( (____ _____ ____ _| |_ _____ ____| |__
+ \____ \| ___ | (_ _) ___ |/ ___) _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+ (C)2013 Semtech-Cycleo
+
+Description:
+ Functions used to handle the Listen Before Talk feature
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+Maintainer: Michael Coracin
+*/
+
+/* -------------------------------------------------------------------------- */
+/* --- DEPENDANCIES --------------------------------------------------------- */
+
+#include <stdint.h> /* C99 types */
+#include <stdbool.h> /* bool type */
+#include <stdio.h> /* printf fprintf */
+#include <stdlib.h> /* abs, labs, llabs */
+#include <string.h> /* memset */
+
+#include "loragw_radio.h"
+#include "loragw_aux.h"
+#include "loragw_lbt.h"
+#include "loragw_fpga.h"
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE MACROS ------------------------------------------------------- */
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+#if DEBUG_LBT == 1
+ #define DEBUG_MSG(str) fprintf(stderr, str)
+ #define DEBUG_PRINTF(fmt, args...) fprintf(stderr,"%s:%d: "fmt, __FUNCTION__, __LINE__, args)
+ #define CHECK_NULL(a) if(a==NULL){fprintf(stderr,"%s:%d: ERROR: NULL POINTER AS ARGUMENT\n", __FUNCTION__, __LINE__);return LGW_REG_ERROR;}
+#else
+ #define DEBUG_MSG(str)
+ #define DEBUG_PRINTF(fmt, args...)
+ #define CHECK_NULL(a) if(a==NULL){return LGW_REG_ERROR;}
+#endif
+
+#define LBT_TIMESTAMP_MASK 0x007FF000 /* 11-bits timestamp */
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE TYPES -------------------------------------------------------- */
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE CONSTANTS ---------------------------------------------------- */
+
+/* -------------------------------------------------------------------------- */
+/* --- INTERNAL SHARED VARIABLES -------------------------------------------- */
+
+extern void *lgw_spi_target; /*! generic pointer to the SPI device */
+extern uint8_t lgw_spi_mux_mode; /*! current SPI mux mode used */
+extern uint16_t lgw_i_tx_start_delay_us;
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE VARIABLES ---------------------------------------------------- */
+
+static bool lbt_enable;
+static uint8_t lbt_nb_active_channel;
+static int8_t lbt_rssi_target_dBm;
+static int8_t lbt_rssi_offset_dB;
+static uint32_t lbt_start_freq;
+static struct lgw_conf_lbt_chan_s lbt_channel_cfg[LBT_CHANNEL_FREQ_NB];
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE FUNCTIONS ---------------------------------------------------- */
+
+bool is_equal_freq(uint32_t a, uint32_t b);
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC FUNCTIONS DEFINITION ------------------------------------------ */
+
+int lbt_setconf(struct lgw_conf_lbt_s * conf) {
+ int i;
+
+ /* Check input parameters */
+ if (conf == NULL) {
+ return LGW_LBT_ERROR;
+ }
+ if ((conf->nb_channel < 1) || (conf->nb_channel > LBT_CHANNEL_FREQ_NB)) {
+ DEBUG_PRINTF("ERROR: Number of defined LBT channels is out of range (%u)\n", conf->nb_channel);
+ return LGW_LBT_ERROR;
+ }
+
+ /* Initialize LBT channels configuration */
+ memset(lbt_channel_cfg, 0, sizeof lbt_channel_cfg);
+
+ /* Set internal LBT config according to parameters */
+ lbt_enable = conf->enable;
+ lbt_nb_active_channel = conf->nb_channel;
+ lbt_rssi_target_dBm = conf->rssi_target;
+ lbt_rssi_offset_dB = conf->rssi_offset;
+
+ for (i=0; i<lbt_nb_active_channel; i++) {
+ lbt_channel_cfg[i].freq_hz = conf->channels[i].freq_hz;
+ lbt_channel_cfg[i].scan_time_us = conf->channels[i].scan_time_us;
+ }
+
+ return LGW_LBT_SUCCESS;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int lbt_setup(void) {
+ int x, i;
+ int32_t val;
+ uint32_t freq_offset;
+
+ /* Check if LBT feature is supported by FPGA */
+ x = lgw_fpga_reg_r(LGW_FPGA_FEATURE, &val);
+ if (x != LGW_REG_SUCCESS) {
+ DEBUG_MSG("ERROR: Failed to read FPGA Features register\n");
+ return LGW_LBT_ERROR;
+ }
+ if (TAKE_N_BITS_FROM((uint8_t)val, 2, 1) != 1) {
+ DEBUG_MSG("ERROR: No support for LBT in FPGA\n");
+ return LGW_LBT_ERROR;
+ }
+
+ /* Get FPGA lowest frequency for LBT channels */
+ x = lgw_fpga_reg_r(LGW_FPGA_LBT_INITIAL_FREQ, &val);
+ if (x != LGW_REG_SUCCESS) {
+ DEBUG_MSG("ERROR: Failed to read LBT initial frequency from FPGA\n");
+ return LGW_LBT_ERROR;
+ }
+ switch(val) {
+ case 0:
+ lbt_start_freq = 915000000;
+ break;
+ case 1:
+ lbt_start_freq = 863000000;
+ break;
+ default:
+ DEBUG_PRINTF("ERROR: LBT start frequency %d is not supported\n", val);
+ return LGW_LBT_ERROR;
+ }
+
+ /* Configure SX127x for FSK */
+ x = lgw_setup_sx127x(lbt_start_freq, MOD_FSK, LGW_SX127X_RXBW_100K_HZ, lbt_rssi_offset_dB); /* 200KHz LBT channels */
+ if (x != LGW_REG_SUCCESS) {
+ DEBUG_MSG("ERROR: Failed to configure SX127x for LBT\n");
+ return LGW_LBT_ERROR;
+ }
+
+ /* Configure FPGA for LBT */
+ val = -2*lbt_rssi_target_dBm; /* Convert RSSI target in dBm to FPGA register format */
+ x = lgw_fpga_reg_w(LGW_FPGA_RSSI_TARGET, val);
+ if (x != LGW_REG_SUCCESS) {
+ DEBUG_MSG("ERROR: Failed to configure FPGA for LBT\n");
+ return LGW_LBT_ERROR;
+ }
+ /* Set default values for non-active LBT channels */
+ for (i=lbt_nb_active_channel; i<LBT_CHANNEL_FREQ_NB; i++) {
+ lbt_channel_cfg[i].freq_hz = lbt_start_freq;
+ lbt_channel_cfg[i].scan_time_us = 128; /* fastest scan for non-active channels */
+ }
+ /* Configure FPGA for both active and non-active LBT channels */
+ for (i=0; i<LBT_CHANNEL_FREQ_NB; i++) {
+ /* Check input parameters */
+ if (lbt_channel_cfg[i].freq_hz < lbt_start_freq) {
+ DEBUG_PRINTF("ERROR: LBT channel frequency is out of range (%u)\n", lbt_channel_cfg[i].freq_hz);
+ return LGW_LBT_ERROR;
+ }
+ if ((lbt_channel_cfg[i].scan_time_us != 128) && (lbt_channel_cfg[i].scan_time_us != 5000)) {
+ DEBUG_PRINTF("ERROR: LBT channel scan time is not supported (%u)\n", lbt_channel_cfg[i].scan_time_us);
+ return LGW_LBT_ERROR;
+ }
+ /* Configure */
+ freq_offset = (lbt_channel_cfg[i].freq_hz - lbt_start_freq) / 100E3; /* 100kHz unit */
+ x = lgw_fpga_reg_w(LGW_FPGA_LBT_CH0_FREQ_OFFSET+i, (int32_t)freq_offset);
+ if (x != LGW_REG_SUCCESS) {
+ DEBUG_PRINTF("ERROR: Failed to configure FPGA for LBT channel %d (freq offset)\n", i);
+ return LGW_LBT_ERROR;
+ }
+ if (lbt_channel_cfg[i].scan_time_us == 5000) { /* configured to 128 by default */
+ x = lgw_fpga_reg_w(LGW_FPGA_LBT_SCAN_TIME_CH0+i, 1);
+ if (x != LGW_REG_SUCCESS) {
+ DEBUG_PRINTF("ERROR: Failed to configure FPGA for LBT channel %d (freq offset)\n", i);
+ return LGW_LBT_ERROR;
+ }
+ }
+ }
+
+ DEBUG_MSG("Note: LBT configuration:\n");
+ DEBUG_PRINTF("\tlbt_enable: %d\n", lbt_enable );
+ DEBUG_PRINTF("\tlbt_nb_active_channel: %d\n", lbt_nb_active_channel );
+ DEBUG_PRINTF("\tlbt_start_freq: %d\n", lbt_start_freq);
+ DEBUG_PRINTF("\tlbt_rssi_target: %d\n", lbt_rssi_target_dBm );
+ for (i=0; i<LBT_CHANNEL_FREQ_NB; i++) {
+ DEBUG_PRINTF("\tlbt_channel_cfg[%d].freq_hz: %u\n", i, lbt_channel_cfg[i].freq_hz );
+ DEBUG_PRINTF("\tlbt_channel_cfg[%d].scan_time_us: %u\n", i, lbt_channel_cfg[i].scan_time_us );
+ }
+
+ return LGW_LBT_SUCCESS;
+
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int lbt_start(void) {
+ int x;
+
+ x = lgw_fpga_reg_w(LGW_FPGA_CTRL_FEATURE_START, 1);
+ if (x != LGW_REG_SUCCESS) {
+ DEBUG_MSG("ERROR: Failed to start LBT FSM\n");
+ return LGW_LBT_ERROR;
+ }
+
+ return LGW_LBT_SUCCESS;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int lbt_is_channel_free(struct lgw_pkt_tx_s * pkt_data, uint16_t tx_start_delay, bool * tx_allowed) {
+ int i;
+ int32_t val;
+ uint32_t tx_start_time = 0;
+ uint32_t tx_end_time = 0;
+ uint32_t delta_time = 0;
+ uint32_t sx1301_time = 0;
+ uint32_t lbt_time = 0;
+ uint32_t lbt_time1 = 0;
+ uint32_t lbt_time2 = 0;
+ uint32_t tx_max_time = 0;
+ int lbt_channel_decod_1 = -1;
+ int lbt_channel_decod_2 = -1;
+ uint32_t packet_duration = 0;
+
+ /* Check input parameters */
+ if ((pkt_data == NULL) || (tx_allowed == NULL)) {
+ return LGW_LBT_ERROR;
+ }
+
+ /* Check if TX is allowed */
+ if (lbt_enable == true) {
+ /* TX allowed for LoRa only */
+ if (pkt_data->modulation != MOD_LORA) {
+ *tx_allowed = false;
+ DEBUG_PRINTF("INFO: TX is not allowed for this modulation (%x)\n", pkt_data->modulation);
+ return LGW_LBT_SUCCESS;
+ }
+
+ /* Get SX1301 time at last PPS */
+ lgw_get_trigcnt(&sx1301_time);
+
+ DEBUG_MSG("################################\n");
+ switch(pkt_data->tx_mode) {
+ case TIMESTAMPED:
+ DEBUG_MSG("tx_mode = TIMESTAMPED\n");
+ tx_start_time = pkt_data->count_us & LBT_TIMESTAMP_MASK;
+ break;
+ case ON_GPS:
+ DEBUG_MSG("tx_mode = ON_GPS\n");
+ tx_start_time = (sx1301_time + (uint32_t)tx_start_delay + 1000000) & LBT_TIMESTAMP_MASK;
+ break;
+ case IMMEDIATE:
+ DEBUG_MSG("ERROR: tx_mode IMMEDIATE is not supported when LBT is enabled\n");
+ /* FALLTHROUGH */
+ default:
+ return LGW_LBT_ERROR;
+ }
+
+ /* Select LBT Channel corresponding to required TX frequency */
+ lbt_channel_decod_1 = -1;
+ lbt_channel_decod_2 = -1;
+ if (pkt_data->bandwidth == BW_125KHZ) {
+ for (i=0; i<lbt_nb_active_channel; i++) {
+ if (is_equal_freq(pkt_data->freq_hz, lbt_channel_cfg[i].freq_hz) == true) {
+ DEBUG_PRINTF("LBT: select channel %d (%u Hz)\n", i, lbt_channel_cfg[i].freq_hz);
+ lbt_channel_decod_1 = i;
+ lbt_channel_decod_2 = i;
+ if (lbt_channel_cfg[i].scan_time_us == 5000) {
+ tx_max_time = 4000000; /* 4 seconds */
+ } else { /* scan_time_us = 128 */
+ tx_max_time = 400000; /* 400 milliseconds */
+ }
+ break;
+ }
+ }
+ } else if (pkt_data->bandwidth == BW_250KHZ) {
+ /* In case of 250KHz, the TX freq has to be in between 2 consecutive channels of 200KHz BW.
+ The TX can only be over 2 channels, not more */
+ for (i=0; i<(lbt_nb_active_channel-1); i++) {
+ if ((is_equal_freq(pkt_data->freq_hz, (lbt_channel_cfg[i].freq_hz+lbt_channel_cfg[i+1].freq_hz)/2) == true) && ((lbt_channel_cfg[i+1].freq_hz-lbt_channel_cfg[i].freq_hz)==200E3)) {
+ DEBUG_PRINTF("LBT: select channels %d,%d (%u Hz)\n", i, i+1, (lbt_channel_cfg[i].freq_hz+lbt_channel_cfg[i+1].freq_hz)/2);
+ lbt_channel_decod_1 = i;
+ lbt_channel_decod_2 = i+1;
+ if (lbt_channel_cfg[i].scan_time_us == 5000) {
+ tx_max_time = 4000000; /* 4 seconds */
+ } else { /* scan_time_us = 128 */
+ tx_max_time = 200000; /* 200 milliseconds */
+ }
+ break;
+ }
+ }
+ } else {
+ /* Nothing to do for now */
+ }
+
+ /* Get last time when selected channel was free */
+ if ((lbt_channel_decod_1 >= 0) && (lbt_channel_decod_2 >= 0)) {
+ lgw_fpga_reg_w(LGW_FPGA_LBT_TIMESTAMP_SELECT_CH, (int32_t)lbt_channel_decod_1);
+ lgw_fpga_reg_r(LGW_FPGA_LBT_TIMESTAMP_CH, &val);
+ lbt_time = lbt_time1 = (uint32_t)(val & 0x0000FFFF) * 256; /* 16bits (1LSB = 256µs) */
+
+ if (lbt_channel_decod_1 != lbt_channel_decod_2 ) {
+ lgw_fpga_reg_w(LGW_FPGA_LBT_TIMESTAMP_SELECT_CH, (int32_t)lbt_channel_decod_2);
+ lgw_fpga_reg_r(LGW_FPGA_LBT_TIMESTAMP_CH, &val);
+ lbt_time2 = (uint32_t)(val & 0x0000FFFF) * 256; /* 16bits (1LSB = 256µs) */
+
+ if (lbt_time2 < lbt_time1) {
+ lbt_time = lbt_time2;
+ }
+ }
+ } else {
+ lbt_time = 0;
+ }
+
+ packet_duration = lgw_time_on_air(pkt_data) * 1000UL;
+ tx_end_time = (tx_start_time + packet_duration) & LBT_TIMESTAMP_MASK;
+ if (lbt_time < tx_end_time) {
+ delta_time = tx_end_time - lbt_time;
+ } else {
+ /* It means LBT counter has wrapped */
+ printf("LBT: lbt counter has wrapped\n");
+ delta_time = (LBT_TIMESTAMP_MASK - lbt_time) + tx_end_time;
+ }
+
+ DEBUG_PRINTF("sx1301_time = %u\n", sx1301_time & LBT_TIMESTAMP_MASK);
+ DEBUG_PRINTF("tx_freq = %u\n", pkt_data->freq_hz);
+ DEBUG_MSG("------------------------------------------------\n");
+ DEBUG_PRINTF("packet_duration = %u\n", packet_duration);
+ DEBUG_PRINTF("tx_start_time = %u\n", tx_start_time);
+ DEBUG_PRINTF("lbt_time1 = %u\n", lbt_time1);
+ DEBUG_PRINTF("lbt_time2 = %u\n", lbt_time2);
+ DEBUG_PRINTF("lbt_time = %u\n", lbt_time);
+ DEBUG_PRINTF("delta_time = %u\n", delta_time);
+ DEBUG_MSG("------------------------------------------------\n");
+
+ /* send data if allowed */
+ /* lbt_time: last time when channel was free */
+ /* tx_max_time: maximum time allowed to send packet since last free time */
+ /* 2048: some margin */
+ if ((delta_time < (tx_max_time - 2048)) && (lbt_time != 0)) {
+ *tx_allowed = true;
+ } else {
+ DEBUG_MSG("ERROR: TX request rejected (LBT)\n");
+ *tx_allowed = false;
+ }
+ } else {
+ /* Always allow if LBT is disabled */
+ *tx_allowed = true;
+ }
+
+ return LGW_LBT_SUCCESS;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+bool lbt_is_enabled(void) {
+ return lbt_enable;
+}
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE FUNCTIONS DEFINITION ----------------------------------------- */
+
+/* As given frequencies have been converted from float to integer, some aliasing
+issues can appear, so we can't simply check for equality, but have to take some
+margin */
+bool is_equal_freq(uint32_t a, uint32_t b) {
+ int64_t diff;
+ int64_t a64 = (int64_t)a;
+ int64_t b64 = (int64_t)b;
+
+ /* Calculate the difference */
+ diff = llabs(a64 - b64);
+
+ /* Check for acceptable diff range */
+ if( diff <= 10000 )
+ {
+ return true;
+ }
+
+ return false;
+}
+
+/* --- EOF ------------------------------------------------------------------ */
diff --git a/libloragw/src/loragw_radio.c b/libloragw/src/loragw_radio.c
new file mode 100644
index 0000000..b3046a9
--- /dev/null
+++ b/libloragw/src/loragw_radio.c
@@ -0,0 +1,562 @@
+/*
+ / _____) _ | |
+( (____ _____ ____ _| |_ _____ ____| |__
+ \____ \| ___ | (_ _) ___ |/ ___) _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+ (C)2013 Semtech-Cycleo
+
+Description:
+ Functions used to handle LoRa concentrator radios.
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+Maintainer: Michael Coracin
+*/
+
+/* -------------------------------------------------------------------------- */
+/* --- DEPENDANCIES --------------------------------------------------------- */
+
+#include <stdint.h> /* C99 types */
+#include <stdbool.h> /* bool type */
+#include <stdio.h> /* printf fprintf */
+
+#include "loragw_sx125x.h"
+#include "loragw_sx1272_fsk.h"
+#include "loragw_sx1272_lora.h"
+#include "loragw_sx1276_fsk.h"
+#include "loragw_sx1276_lora.h"
+#include "loragw_spi.h"
+#include "loragw_aux.h"
+#include "loragw_reg.h"
+#include "loragw_hal.h"
+#include "loragw_radio.h"
+#include "loragw_fpga.h"
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE MACROS ------------------------------------------------------- */
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+#if DEBUG_REG == 1
+ #define DEBUG_MSG(str) fprintf(stderr, str)
+ #define DEBUG_PRINTF(fmt, args...) fprintf(stderr,"%s:%d: "fmt, __FUNCTION__, __LINE__, args)
+ #define CHECK_NULL(a) if(a==NULL){fprintf(stderr,"%s:%d: ERROR: NULL POINTER AS ARGUMENT\n", __FUNCTION__, __LINE__);return LGW_REG_ERROR;}
+#else
+ #define DEBUG_MSG(str)
+ #define DEBUG_PRINTF(fmt, args...)
+ #define CHECK_NULL(a) if(a==NULL){return LGW_REG_ERROR;}
+#endif
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE TYPES -------------------------------------------------------- */
+
+/**
+@struct lgw_radio_FSK_bandwidth_s
+@brief Associate a bandwidth in kHz with its corresponding register values
+*/
+struct lgw_sx127x_FSK_bandwidth_s {
+ uint32_t RxBwKHz;
+ uint8_t RxBwMant;
+ uint8_t RxBwExp;
+};
+
+/**
+@struct lgw_radio_type_version_s
+@brief Associate a radio type with its corresponding expected version value
+ read in the radio version register.
+*/
+struct lgw_radio_type_version_s {
+ enum lgw_radio_type_e type;
+ uint8_t reg_version;
+};
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE CONSTANTS ---------------------------------------------------- */
+
+#define PLL_LOCK_MAX_ATTEMPTS 5
+
+const struct lgw_sx127x_FSK_bandwidth_s sx127x_FskBandwidths[] =
+{
+ { 2600 , 2, 7 }, /* LGW_SX127X_RXBW_2K6_HZ */
+ { 3100 , 1, 7 }, /* LGW_SX127X_RXBW_3K1_HZ */
+ { 3900 , 0, 7 }, /* ... */
+ { 5200 , 2, 6 },
+ { 6300 , 1, 6 },
+ { 7800 , 0, 6 },
+ { 10400 , 2, 5 },
+ { 12500 , 1, 5 },
+ { 15600 , 0, 5 },
+ { 20800 , 2, 4 },
+ { 25000 , 1, 4 }, /* ... */
+ { 31300 , 0, 4 },
+ { 41700 , 2, 3 },
+ { 50000 , 1, 3 },
+ { 62500 , 0, 3 },
+ { 83333 , 2, 2 },
+ { 100000, 1, 2 },
+ { 125000, 0, 2 },
+ { 166700, 2, 1 },
+ { 200000, 1, 1 }, /* ... */
+ { 250000, 0, 1 } /* LGW_SX127X_RXBW_250K_HZ */
+};
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE VARIABLES ---------------------------------------------------- */
+
+extern void *lgw_spi_target; /*! generic pointer to the SPI device */
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE FUNCTIONS ---------------------------------------------------- */
+
+void sx125x_write(uint8_t channel, uint8_t addr, uint8_t data);
+uint8_t sx125x_read(uint8_t channel, uint8_t addr);
+
+int setup_sx1272_FSK(uint32_t frequency, enum lgw_sx127x_rxbw_e rxbw_khz, int8_t rssi_offset);
+int setup_sx1276_FSK(uint32_t frequency, enum lgw_sx127x_rxbw_e rxbw_khz, int8_t rssi_offset);
+
+int reset_sx127x(enum lgw_radio_type_e radio_type);
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE FUNCTIONS DEFINITION ----------------------------------------- */
+
+void sx125x_write(uint8_t channel, uint8_t addr, uint8_t data) {
+ int reg_add, reg_dat, reg_cs;
+
+ /* checking input parameters */
+ if (channel >= LGW_RF_CHAIN_NB) {
+ DEBUG_MSG("ERROR: INVALID RF_CHAIN\n");
+ return;
+ }
+ if (addr >= 0x7F) {
+ DEBUG_MSG("ERROR: ADDRESS OUT OF RANGE\n");
+ return;
+ }
+
+ /* selecting the target radio */
+ switch (channel) {
+ case 0:
+ reg_add = LGW_SPI_RADIO_A__ADDR;
+ reg_dat = LGW_SPI_RADIO_A__DATA;
+ reg_cs = LGW_SPI_RADIO_A__CS;
+ break;
+
+ case 1:
+ reg_add = LGW_SPI_RADIO_B__ADDR;
+ reg_dat = LGW_SPI_RADIO_B__DATA;
+ reg_cs = LGW_SPI_RADIO_B__CS;
+ break;
+
+ default:
+ DEBUG_PRINTF("ERROR: UNEXPECTED VALUE %d IN SWITCH STATEMENT\n", channel);
+ return;
+ }
+
+ /* SPI master data write procedure */
+ lgw_reg_w(reg_cs, 0);
+ lgw_reg_w(reg_add, 0x80 | addr); /* MSB at 1 for write operation */
+ lgw_reg_w(reg_dat, data);
+ lgw_reg_w(reg_cs, 1);
+ lgw_reg_w(reg_cs, 0);
+
+ return;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+uint8_t sx125x_read(uint8_t channel, uint8_t addr) {
+ int reg_add, reg_dat, reg_cs, reg_rb;
+ int32_t read_value;
+
+ /* checking input parameters */
+ if (channel >= LGW_RF_CHAIN_NB) {
+ DEBUG_MSG("ERROR: INVALID RF_CHAIN\n");
+ return 0;
+ }
+ if (addr >= 0x7F) {
+ DEBUG_MSG("ERROR: ADDRESS OUT OF RANGE\n");
+ return 0;
+ }
+
+ /* selecting the target radio */
+ switch (channel) {
+ case 0:
+ reg_add = LGW_SPI_RADIO_A__ADDR;
+ reg_dat = LGW_SPI_RADIO_A__DATA;
+ reg_cs = LGW_SPI_RADIO_A__CS;
+ reg_rb = LGW_SPI_RADIO_A__DATA_READBACK;
+ break;
+
+ case 1:
+ reg_add = LGW_SPI_RADIO_B__ADDR;
+ reg_dat = LGW_SPI_RADIO_B__DATA;
+ reg_cs = LGW_SPI_RADIO_B__CS;
+ reg_rb = LGW_SPI_RADIO_B__DATA_READBACK;
+ break;
+
+ default:
+ DEBUG_PRINTF("ERROR: UNEXPECTED VALUE %d IN SWITCH STATEMENT\n", channel);
+ return 0;
+ }
+
+ /* SPI master data read procedure */
+ lgw_reg_w(reg_cs, 0);
+ lgw_reg_w(reg_add, addr); /* MSB at 0 for read operation */
+ lgw_reg_w(reg_dat, 0);
+ lgw_reg_w(reg_cs, 1);
+ lgw_reg_w(reg_cs, 0);
+ lgw_reg_r(reg_rb, &read_value);
+
+ return (uint8_t)read_value;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int setup_sx1272_FSK(uint32_t frequency, enum lgw_sx127x_rxbw_e rxbw_khz, int8_t rssi_offset) {
+ uint64_t freq_reg;
+ uint8_t ModulationShaping = 0;
+ uint8_t PllHop = 1;
+ uint8_t LnaGain = 1;
+ uint8_t LnaBoost = 3;
+ uint8_t AdcBwAuto = 0;
+ uint8_t AdcBw = 7;
+ uint8_t AdcLowPwr = 0;
+ uint8_t AdcTrim = 6;
+ uint8_t AdcTest = 0;
+ uint8_t RxBwExp = sx127x_FskBandwidths[rxbw_khz].RxBwExp;
+ uint8_t RxBwMant = sx127x_FskBandwidths[rxbw_khz].RxBwMant;
+ uint8_t RssiSmoothing = 5;
+ uint8_t RssiOffsetReg;
+ uint8_t reg_val;
+ int x;
+
+ /* Set in FSK mode */
+ x = lgw_sx127x_reg_w(SX1272_REG_OPMODE, 0);
+ wait_ms(100);
+ x |= lgw_sx127x_reg_w(SX1272_REG_OPMODE, 0 | (ModulationShaping << 3)); /* Sleep mode, no FSK shaping */
+ wait_ms(100);
+ x |= lgw_sx127x_reg_w(SX1272_REG_OPMODE, 1 | (ModulationShaping << 3)); /* Standby mode, no FSK shaping */
+ wait_ms(100);
+
+ /* Set RF carrier frequency */
+ x |= lgw_sx127x_reg_w(SX1272_REG_PLLHOP, PllHop << 7);
+ freq_reg = ((uint64_t)frequency << 19) / (uint64_t)32000000;
+ x |= lgw_sx127x_reg_w(SX1272_REG_FRFMSB, (freq_reg >> 16) & 0xFF);
+ x |= lgw_sx127x_reg_w(SX1272_REG_FRFMID, (freq_reg >> 8) & 0xFF);
+ x |= lgw_sx127x_reg_w(SX1272_REG_FRFLSB, (freq_reg >> 0) & 0xFF);
+
+ /* Config */
+ x |= lgw_sx127x_reg_w(SX1272_REG_LNA, LnaBoost | (LnaGain << 5)); /* Improved sensitivity, highest gain */
+ x |= lgw_sx127x_reg_w(0x68, AdcBw | (AdcBwAuto << 3));
+ x |= lgw_sx127x_reg_w(0x69, AdcTest | (AdcTrim << 4) | (AdcLowPwr << 7));
+
+ /* set BR and FDEV for 200 kHz bandwidth*/
+ x |= lgw_sx127x_reg_w(SX1272_REG_BITRATEMSB, 125);
+ x |= lgw_sx127x_reg_w(SX1272_REG_BITRATELSB, 0);
+ x |= lgw_sx127x_reg_w(SX1272_REG_FDEVMSB, 2);
+ x |= lgw_sx127x_reg_w(SX1272_REG_FDEVLSB, 225);
+
+ /* Config continues... */
+ x |= lgw_sx127x_reg_w(SX1272_REG_RXCONFIG, 0); /* Disable AGC */
+ RssiOffsetReg = (rssi_offset >= 0) ? (uint8_t)rssi_offset : (uint8_t)(~(-rssi_offset)+1); /* 2's complement */
+ x |= lgw_sx127x_reg_w(SX1272_REG_RSSICONFIG, RssiSmoothing | (RssiOffsetReg << 3)); /* Set RSSI smoothing to 64 samples, RSSI offset to given value */
+ x |= lgw_sx127x_reg_w(SX1272_REG_RXBW, RxBwExp | (RxBwMant << 3));
+ x |= lgw_sx127x_reg_w(SX1272_REG_RXDELAY, 2);
+ x |= lgw_sx127x_reg_w(SX1272_REG_PLL, 0x10); /* PLL BW set to 75 KHz */
+ x |= lgw_sx127x_reg_w(0x47, 1); /* optimize PLL start-up time */
+
+ if (x != LGW_REG_SUCCESS) {
+ DEBUG_MSG("ERROR: Failed to configure SX1272\n");
+ return x;
+ }
+
+ /* set Rx continuous mode */
+ x = lgw_sx127x_reg_w(SX1272_REG_OPMODE, 5 | (ModulationShaping << 3)); /* Receiver Mode, no FSK shaping */
+ wait_ms(500);
+ x |= lgw_sx127x_reg_r(SX1272_REG_IRQFLAGS1, &reg_val);
+ /* Check if RxReady and ModeReady */
+ if ((TAKE_N_BITS_FROM(reg_val, 6, 1) == 0) || (TAKE_N_BITS_FROM(reg_val, 7, 1) == 0) || (x != LGW_REG_SUCCESS)) {
+ DEBUG_MSG("ERROR: SX1272 failed to enter RX continuous mode\n");
+ return LGW_REG_ERROR;
+ }
+ wait_ms(500);
+
+ DEBUG_PRINTF("INFO: Successfully configured SX1272 for FSK modulation (rxbw=%d)\n", rxbw_khz);
+
+ return LGW_REG_SUCCESS;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int setup_sx1276_FSK(uint32_t frequency, enum lgw_sx127x_rxbw_e rxbw_khz, int8_t rssi_offset) {
+ uint64_t freq_reg;
+ uint8_t ModulationShaping = 0;
+ uint8_t PllHop = 1;
+ uint8_t LnaGain = 1;
+ uint8_t LnaBoost = 3;
+ uint8_t AdcBwAuto = 0;
+ uint8_t AdcBw = 7;
+ uint8_t AdcLowPwr = 0;
+ uint8_t AdcTrim = 6;
+ uint8_t AdcTest = 0;
+ uint8_t RxBwExp = sx127x_FskBandwidths[rxbw_khz].RxBwExp;
+ uint8_t RxBwMant = sx127x_FskBandwidths[rxbw_khz].RxBwMant;
+ uint8_t RssiSmoothing = 5;
+ uint8_t RssiOffsetReg;
+ uint8_t reg_val;
+ int x;
+
+ /* Set in FSK mode */
+ x = lgw_sx127x_reg_w(SX1276_REG_OPMODE, 0);
+ wait_ms(100);
+ x |= lgw_sx127x_reg_w(SX1276_REG_OPMODE, 0 | (ModulationShaping << 3)); /* Sleep mode, no FSK shaping */
+ wait_ms(100);
+ x |= lgw_sx127x_reg_w(SX1276_REG_OPMODE, 1 | (ModulationShaping << 3)); /* Standby mode, no FSK shaping */
+ wait_ms(100);
+
+ /* Set RF carrier frequency */
+ x |= lgw_sx127x_reg_w(SX1276_REG_PLLHOP, PllHop << 7);
+ freq_reg = ((uint64_t)frequency << 19) / (uint64_t)32000000;
+ x |= lgw_sx127x_reg_w(SX1276_REG_FRFMSB, (freq_reg >> 16) & 0xFF);
+ x |= lgw_sx127x_reg_w(SX1276_REG_FRFMID, (freq_reg >> 8) & 0xFF);
+ x |= lgw_sx127x_reg_w(SX1276_REG_FRFLSB, (freq_reg >> 0) & 0xFF);
+
+ /* Config */
+ x |= lgw_sx127x_reg_w(SX1276_REG_LNA, LnaBoost | (LnaGain << 5)); /* Improved sensitivity, highest gain */
+ x |= lgw_sx127x_reg_w(0x57, AdcBw | (AdcBwAuto << 3));
+ x |= lgw_sx127x_reg_w(0x58, AdcTest | (AdcTrim << 4) | (AdcLowPwr << 7));
+
+ /* set BR and FDEV for 200 kHz bandwidth*/
+ x |= lgw_sx127x_reg_w(SX1276_REG_BITRATEMSB, 125);
+ x |= lgw_sx127x_reg_w(SX1276_REG_BITRATELSB, 0);
+ x |= lgw_sx127x_reg_w(SX1276_REG_FDEVMSB, 2);
+ x |= lgw_sx127x_reg_w(SX1276_REG_FDEVLSB, 225);
+
+ /* Config continues... */
+ x |= lgw_sx127x_reg_w(SX1276_REG_RXCONFIG, 0); /* Disable AGC */
+ RssiOffsetReg = (rssi_offset >= 0) ? (uint8_t)rssi_offset : (uint8_t)(~(-rssi_offset)+1); /* 2's complement */
+ x |= lgw_sx127x_reg_w(SX1276_REG_RSSICONFIG, RssiSmoothing | (RssiOffsetReg << 3)); /* Set RSSI smoothing to 64 samples, RSSI offset 3dB */
+ x |= lgw_sx127x_reg_w(SX1276_REG_RXBW, RxBwExp | (RxBwMant << 3));
+ x |= lgw_sx127x_reg_w(SX1276_REG_RXDELAY, 2);
+ x |= lgw_sx127x_reg_w(SX1276_REG_PLL, 0x10); /* PLL BW set to 75 KHz */
+ x |= lgw_sx127x_reg_w(0x43, 1); /* optimize PLL start-up time */
+
+ if (x != LGW_REG_SUCCESS) {
+ DEBUG_MSG("ERROR: Failed to configure SX1276\n");
+ return x;
+ }
+
+ /* set Rx continuous mode */
+ x = lgw_sx127x_reg_w(SX1276_REG_OPMODE, 5 | (ModulationShaping << 3)); /* Receiver Mode, no FSK shaping */
+ wait_ms(500);
+ x |= lgw_sx127x_reg_r(SX1276_REG_IRQFLAGS1, &reg_val);
+ /* Check if RxReady and ModeReady */
+ if ((TAKE_N_BITS_FROM(reg_val, 6, 1) == 0) || (TAKE_N_BITS_FROM(reg_val, 7, 1) == 0) || (x != LGW_REG_SUCCESS)) {
+ DEBUG_MSG("ERROR: SX1276 failed to enter RX continuous mode\n");
+ return LGW_REG_ERROR;
+ }
+ wait_ms(500);
+
+ DEBUG_PRINTF("INFO: Successfully configured SX1276 for FSK modulation (rxbw=%d)\n", rxbw_khz);
+
+ return LGW_REG_SUCCESS;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int reset_sx127x(enum lgw_radio_type_e radio_type) {
+ int x;
+
+ switch(radio_type) {
+ case LGW_RADIO_TYPE_SX1276:
+ x = lgw_fpga_reg_w(LGW_FPGA_CTRL_RADIO_RESET, 0);
+ x |= lgw_fpga_reg_w(LGW_FPGA_CTRL_RADIO_RESET, 1);
+ if (x != LGW_SPI_SUCCESS) {
+ DEBUG_MSG("ERROR: Failed to reset sx127x\n");
+ return x;
+ }
+ break;
+ case LGW_RADIO_TYPE_SX1272:
+ x = lgw_fpga_reg_w(LGW_FPGA_CTRL_RADIO_RESET, 1);
+ x |= lgw_fpga_reg_w(LGW_FPGA_CTRL_RADIO_RESET, 0);
+ if (x != LGW_SPI_SUCCESS) {
+ DEBUG_MSG("ERROR: Failed to reset sx127x\n");
+ return x;
+ }
+ break;
+ default:
+ DEBUG_PRINTF("ERROR: Failed to reset sx127x, not supported (%d)\n", radio_type);
+ return LGW_REG_ERROR;
+ }
+
+ return LGW_REG_SUCCESS;
+}
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC FUNCTIONS DEFINITION ------------------------------------------ */
+
+int lgw_setup_sx125x(uint8_t rf_chain, uint8_t rf_clkout, bool rf_enable, uint8_t rf_radio_type, uint32_t freq_hz) {
+ uint32_t part_int = 0;
+ uint32_t part_frac = 0;
+ int cpt_attempts = 0;
+
+ if (rf_chain >= LGW_RF_CHAIN_NB) {
+ DEBUG_MSG("ERROR: INVALID RF_CHAIN\n");
+ return -1;
+ }
+
+ /* Get version to identify SX1255/57 silicon revision */
+ DEBUG_PRINTF("Note: SX125x #%d version register returned 0x%02x\n", rf_chain, sx125x_read(rf_chain, 0x07));
+
+ /* General radio setup */
+ if (rf_clkout == rf_chain) {
+ sx125x_write(rf_chain, 0x10, SX125x_TX_DAC_CLK_SEL + 2);
+ DEBUG_PRINTF("Note: SX125x #%d clock output enabled\n", rf_chain);
+ } else {
+ sx125x_write(rf_chain, 0x10, SX125x_TX_DAC_CLK_SEL);
+ DEBUG_PRINTF("Note: SX125x #%d clock output disabled\n", rf_chain);
+ }
+
+ switch (rf_radio_type) {
+ case LGW_RADIO_TYPE_SX1255:
+ sx125x_write(rf_chain, 0x28, SX125x_XOSC_GM_STARTUP + SX125x_XOSC_DISABLE*16);
+ break;
+ case LGW_RADIO_TYPE_SX1257:
+ sx125x_write(rf_chain, 0x26, SX125x_XOSC_GM_STARTUP + SX125x_XOSC_DISABLE*16);
+ break;
+ default:
+ DEBUG_PRINTF("ERROR: UNEXPECTED VALUE %d FOR RADIO TYPE\n", rf_radio_type);
+ break;
+ }
+
+ if (rf_enable == true) {
+ /* Tx gain and trim */
+ sx125x_write(rf_chain, 0x08, SX125x_TX_MIX_GAIN + SX125x_TX_DAC_GAIN*16);
+ sx125x_write(rf_chain, 0x0A, SX125x_TX_ANA_BW + SX125x_TX_PLL_BW*32);
+ sx125x_write(rf_chain, 0x0B, SX125x_TX_DAC_BW);
+
+ /* Rx gain and trim */
+ sx125x_write(rf_chain, 0x0C, SX125x_LNA_ZIN + SX125x_RX_BB_GAIN*2 + SX125x_RX_LNA_GAIN*32);
+ sx125x_write(rf_chain, 0x0D, SX125x_RX_BB_BW + SX125x_RX_ADC_TRIM*4 + SX125x_RX_ADC_BW*32);
+ sx125x_write(rf_chain, 0x0E, SX125x_ADC_TEMP + SX125x_RX_PLL_BW*2);
+
+ /* set RX PLL frequency */
+ switch (rf_radio_type) {
+ case LGW_RADIO_TYPE_SX1255:
+ part_int = freq_hz / (SX125x_32MHz_FRAC << 7); /* integer part, gives the MSB */
+ part_frac = ((freq_hz % (SX125x_32MHz_FRAC << 7)) << 9) / SX125x_32MHz_FRAC; /* fractional part, gives middle part and LSB */
+ break;
+ case LGW_RADIO_TYPE_SX1257:
+ part_int = freq_hz / (SX125x_32MHz_FRAC << 8); /* integer part, gives the MSB */
+ part_frac = ((freq_hz % (SX125x_32MHz_FRAC << 8)) << 8) / SX125x_32MHz_FRAC; /* fractional part, gives middle part and LSB */
+ break;
+ default:
+ DEBUG_PRINTF("ERROR: UNEXPECTED VALUE %d FOR RADIO TYPE\n", rf_radio_type);
+ break;
+ }
+
+ sx125x_write(rf_chain, 0x01,0xFF & part_int); /* Most Significant Byte */
+ sx125x_write(rf_chain, 0x02,0xFF & (part_frac >> 8)); /* middle byte */
+ sx125x_write(rf_chain, 0x03,0xFF & part_frac); /* Least Significant Byte */
+
+ /* start and PLL lock */
+ do {
+ if (cpt_attempts >= PLL_LOCK_MAX_ATTEMPTS) {
+ DEBUG_MSG("ERROR: FAIL TO LOCK PLL\n");
+ return -1;
+ }
+ sx125x_write(rf_chain, 0x00, 1); /* enable Xtal oscillator */
+ sx125x_write(rf_chain, 0x00, 3); /* Enable RX (PLL+FE) */
+ ++cpt_attempts;
+ DEBUG_PRINTF("Note: SX125x #%d PLL start (attempt %d)\n", rf_chain, cpt_attempts);
+ wait_ms(1);
+ } while((sx125x_read(rf_chain, 0x11) & 0x02) == 0);
+ } else {
+ DEBUG_PRINTF("Note: SX125x #%d kept in standby mode\n", rf_chain);
+ }
+
+ return 0;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int lgw_sx127x_reg_w(uint8_t address, uint8_t reg_value) {
+ return lgw_spi_w(lgw_spi_target, LGW_SPI_MUX_MODE1, LGW_SPI_MUX_TARGET_SX127X, address, reg_value);
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int lgw_sx127x_reg_r(uint8_t address, uint8_t *reg_value) {
+ return lgw_spi_r(lgw_spi_target, LGW_SPI_MUX_MODE1, LGW_SPI_MUX_TARGET_SX127X, address, reg_value);
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int lgw_setup_sx127x(uint32_t frequency, uint8_t modulation, enum lgw_sx127x_rxbw_e rxbw_khz, int8_t rssi_offset) {
+ int x, i;
+ uint8_t version;
+ enum lgw_radio_type_e radio_type = LGW_RADIO_TYPE_NONE;
+ struct lgw_radio_type_version_s supported_radio_type[2] = {
+ {LGW_RADIO_TYPE_SX1272, 0x22},
+ {LGW_RADIO_TYPE_SX1276, 0x12}
+ };
+
+ /* Check parameters */
+ if (modulation != MOD_FSK) {
+ DEBUG_PRINTF("ERROR: modulation not supported for SX127x (%u)\n", modulation);
+ return LGW_REG_ERROR;
+ }
+ if (rxbw_khz > LGW_SX127X_RXBW_250K_HZ) {
+ DEBUG_PRINTF("ERROR: RX bandwidth not supported for SX127x (%u)\n", rxbw_khz);
+ return LGW_REG_ERROR;
+ }
+
+ /* Probing radio type */
+ for (i = 0; i < (int)(sizeof supported_radio_type); i++) {
+ /* Reset the radio */
+ x = reset_sx127x(supported_radio_type[i].type);
+ if (x != LGW_SPI_SUCCESS) {
+ DEBUG_MSG("ERROR: Failed to reset sx127x\n");
+ return x;
+ }
+ /* Read version register */
+ x = lgw_sx127x_reg_r(0x42, &version);
+ if (x != LGW_SPI_SUCCESS) {
+ DEBUG_MSG("ERROR: Failed to read sx127x version register\n");
+ return x;
+ }
+ /* Check if we got the expected version */
+ if (version != supported_radio_type[i].reg_version) {
+ DEBUG_PRINTF("INFO: sx127x version register - read:0x%02x, expected:0x%02x\n", version, supported_radio_type[i].reg_version);
+ continue;
+ } else {
+ DEBUG_PRINTF("INFO: sx127x radio has been found (type:%d, version:0x%02x)\n", supported_radio_type[i].type, version);
+ radio_type = supported_radio_type[i].type;
+ break;
+ }
+ }
+ if (radio_type == LGW_RADIO_TYPE_NONE) {
+ DEBUG_MSG("ERROR: sx127x radio has not been found\n");
+ return LGW_REG_ERROR;
+ }
+
+ /* Setup the radio */
+ switch (modulation) {
+ case MOD_FSK:
+ if (radio_type == LGW_RADIO_TYPE_SX1272) {
+ x = setup_sx1272_FSK(frequency, rxbw_khz, rssi_offset);
+ } else {
+ x = setup_sx1276_FSK(frequency, rxbw_khz, rssi_offset);
+ }
+ break;
+ default:
+ /* Should not happen */
+ break;
+ }
+ if (x != LGW_REG_SUCCESS) {
+ DEBUG_MSG("ERROR: failed to setup SX127x\n");
+ return x;
+ }
+
+ return LGW_REG_SUCCESS;
+}
+
+/* --- EOF ------------------------------------------------------------------ */
diff --git a/libloragw/src/loragw_reg.c b/libloragw/src/loragw_reg.c
new file mode 100644
index 0000000..14e23cd
--- /dev/null
+++ b/libloragw/src/loragw_reg.c
@@ -0,0 +1,819 @@
+/*
+ / _____) _ | |
+( (____ _____ ____ _| |_ _____ ____| |__
+ \____ \| ___ | (_ _) ___ |/ ___) _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+ (C)2013 Semtech-Cycleo
+
+Description:
+ Functions used to handle a single LoRa concentrator.
+ Registers are addressed by name.
+ Multi-bytes registers are handled automatically.
+ Read-modify-write is handled automatically.
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+Maintainer: Sylvain Miermont
+*/
+
+
+/* -------------------------------------------------------------------------- */
+/* --- DEPENDANCIES --------------------------------------------------------- */
+
+#include <stdint.h> /* C99 types */
+#include <stdbool.h> /* bool type */
+#include <stdio.h> /* printf fprintf */
+
+#include "loragw_spi.h"
+#include "loragw_reg.h"
+#include "loragw_fpga.h"
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE MACROS ------------------------------------------------------- */
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+#if DEBUG_REG == 1
+ #define DEBUG_MSG(str) fprintf(stderr, str)
+ #define DEBUG_PRINTF(fmt, args...) fprintf(stderr,"%s:%d: "fmt, __FUNCTION__, __LINE__, args)
+ #define CHECK_NULL(a) if(a==NULL){fprintf(stderr,"%s:%d: ERROR: NULL POINTER AS ARGUMENT\n", __FUNCTION__, __LINE__);return LGW_REG_ERROR;}
+#else
+ #define DEBUG_MSG(str)
+ #define DEBUG_PRINTF(fmt, args...)
+ #define CHECK_NULL(a) if(a==NULL){return LGW_REG_ERROR;}
+#endif
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE CONSTANTS ---------------------------------------------------- */
+
+#define PAGE_ADDR 0x00
+#define PAGE_MASK 0x03
+
+const uint8_t FPGA_VERSION[] = { 31, 33 }; /* several versions could be supported */
+
+/*
+auto generated register mapping for C code : 11-Jul-2013 13:20:40
+this file contains autogenerated C struct used to access the LoRa register from the Primer firmware
+this file is autogenerated from registers description
+293 registers are defined
+*/
+const struct lgw_reg_s loregs[LGW_TOTALREGS] = {
+ {-1,0,0,0,2,0,0}, /* PAGE_REG */
+ {-1,0,7,0,1,0,0}, /* SOFT_RESET */
+ {-1,1,0,0,8,1,103}, /* VERSION */
+ {-1,2,0,0,16,0,0}, /* RX_DATA_BUF_ADDR */
+ {-1,4,0,0,8,0,0}, /* RX_DATA_BUF_DATA */
+ {-1,5,0,0,8,0,0}, /* TX_DATA_BUF_ADDR */
+ {-1,6,0,0,8,0,0}, /* TX_DATA_BUF_DATA */
+ {-1,7,0,0,8,0,0}, /* CAPTURE_RAM_ADDR */
+ {-1,8,0,0,8,1,0}, /* CAPTURE_RAM_DATA */
+ {-1,9,0,0,8,0,0}, /* MCU_PROM_ADDR */
+ {-1,10,0,0,8,0,0}, /* MCU_PROM_DATA */
+ {-1,11,0,0,8,0,0}, /* RX_PACKET_DATA_FIFO_NUM_STORED */
+ {-1,12,0,0,16,1,0}, /* RX_PACKET_DATA_FIFO_ADDR_POINTER */
+ {-1,14,0,0,8,1,0}, /* RX_PACKET_DATA_FIFO_STATUS */
+ {-1,15,0,0,8,1,0}, /* RX_PACKET_DATA_FIFO_PAYLOAD_SIZE */
+ {-1,16,0,0,1,0,0}, /* MBWSSF_MODEM_ENABLE */
+ {-1,16,1,0,1,0,0}, /* CONCENTRATOR_MODEM_ENABLE */
+ {-1,16,2,0,1,0,0}, /* FSK_MODEM_ENABLE */
+ {-1,16,3,0,1,0,0}, /* GLOBAL_EN */
+ {-1,17,0,0,1,0,1}, /* CLK32M_EN */
+ {-1,17,1,0,1,0,1}, /* CLKHS_EN */
+ {-1,18,0,0,1,0,0}, /* START_BIST0 */
+ {-1,18,1,0,1,0,0}, /* START_BIST1 */
+ {-1,18,2,0,1,0,0}, /* CLEAR_BIST0 */
+ {-1,18,3,0,1,0,0}, /* CLEAR_BIST1 */
+ {-1,19,0,0,1,1,0}, /* BIST0_FINISHED */
+ {-1,19,1,0,1,1,0}, /* BIST1_FINISHED */
+ {-1,20,0,0,1,1,0}, /* MCU_AGC_PROG_RAM_BIST_STATUS */
+ {-1,20,1,0,1,1,0}, /* MCU_ARB_PROG_RAM_BIST_STATUS */
+ {-1,20,2,0,1,1,0}, /* CAPTURE_RAM_BIST_STATUS */
+ {-1,20,3,0,1,1,0}, /* CHAN_FIR_RAM0_BIST_STATUS */
+ {-1,20,4,0,1,1,0}, /* CHAN_FIR_RAM1_BIST_STATUS */
+ {-1,21,0,0,1,1,0}, /* CORR0_RAM_BIST_STATUS */
+ {-1,21,1,0,1,1,0}, /* CORR1_RAM_BIST_STATUS */
+ {-1,21,2,0,1,1,0}, /* CORR2_RAM_BIST_STATUS */
+ {-1,21,3,0,1,1,0}, /* CORR3_RAM_BIST_STATUS */
+ {-1,21,4,0,1,1,0}, /* CORR4_RAM_BIST_STATUS */
+ {-1,21,5,0,1,1,0}, /* CORR5_RAM_BIST_STATUS */
+ {-1,21,6,0,1,1,0}, /* CORR6_RAM_BIST_STATUS */
+ {-1,21,7,0,1,1,0}, /* CORR7_RAM_BIST_STATUS */
+ {-1,22,0,0,1,1,0}, /* MODEM0_RAM0_BIST_STATUS */
+ {-1,22,1,0,1,1,0}, /* MODEM1_RAM0_BIST_STATUS */
+ {-1,22,2,0,1,1,0}, /* MODEM2_RAM0_BIST_STATUS */
+ {-1,22,3,0,1,1,0}, /* MODEM3_RAM0_BIST_STATUS */
+ {-1,22,4,0,1,1,0}, /* MODEM4_RAM0_BIST_STATUS */
+ {-1,22,5,0,1,1,0}, /* MODEM5_RAM0_BIST_STATUS */
+ {-1,22,6,0,1,1,0}, /* MODEM6_RAM0_BIST_STATUS */
+ {-1,22,7,0,1,1,0}, /* MODEM7_RAM0_BIST_STATUS */
+ {-1,23,0,0,1,1,0}, /* MODEM0_RAM1_BIST_STATUS */
+ {-1,23,1,0,1,1,0}, /* MODEM1_RAM1_BIST_STATUS */
+ {-1,23,2,0,1,1,0}, /* MODEM2_RAM1_BIST_STATUS */
+ {-1,23,3,0,1,1,0}, /* MODEM3_RAM1_BIST_STATUS */
+ {-1,23,4,0,1,1,0}, /* MODEM4_RAM1_BIST_STATUS */
+ {-1,23,5,0,1,1,0}, /* MODEM5_RAM1_BIST_STATUS */
+ {-1,23,6,0,1,1,0}, /* MODEM6_RAM1_BIST_STATUS */
+ {-1,23,7,0,1,1,0}, /* MODEM7_RAM1_BIST_STATUS */
+ {-1,24,0,0,1,1,0}, /* MODEM0_RAM2_BIST_STATUS */
+ {-1,24,1,0,1,1,0}, /* MODEM1_RAM2_BIST_STATUS */
+ {-1,24,2,0,1,1,0}, /* MODEM2_RAM2_BIST_STATUS */
+ {-1,24,3,0,1,1,0}, /* MODEM3_RAM2_BIST_STATUS */
+ {-1,24,4,0,1,1,0}, /* MODEM4_RAM2_BIST_STATUS */
+ {-1,24,5,0,1,1,0}, /* MODEM5_RAM2_BIST_STATUS */
+ {-1,24,6,0,1,1,0}, /* MODEM6_RAM2_BIST_STATUS */
+ {-1,24,7,0,1,1,0}, /* MODEM7_RAM2_BIST_STATUS */
+ {-1,25,0,0,1,1,0}, /* MODEM_MBWSSF_RAM0_BIST_STATUS */
+ {-1,25,1,0,1,1,0}, /* MODEM_MBWSSF_RAM1_BIST_STATUS */
+ {-1,25,2,0,1,1,0}, /* MODEM_MBWSSF_RAM2_BIST_STATUS */
+ {-1,26,0,0,1,1,0}, /* MCU_AGC_DATA_RAM_BIST0_STATUS */
+ {-1,26,1,0,1,1,0}, /* MCU_AGC_DATA_RAM_BIST1_STATUS */
+ {-1,26,2,0,1,1,0}, /* MCU_ARB_DATA_RAM_BIST0_STATUS */
+ {-1,26,3,0,1,1,0}, /* MCU_ARB_DATA_RAM_BIST1_STATUS */
+ {-1,26,4,0,1,1,0}, /* TX_TOP_RAM_BIST0_STATUS */
+ {-1,26,5,0,1,1,0}, /* TX_TOP_RAM_BIST1_STATUS */
+ {-1,26,6,0,1,1,0}, /* DATA_MNGT_RAM_BIST0_STATUS */
+ {-1,26,7,0,1,1,0}, /* DATA_MNGT_RAM_BIST1_STATUS */
+ {-1,27,0,0,4,0,0}, /* GPIO_SELECT_INPUT */
+ {-1,28,0,0,4,0,0}, /* GPIO_SELECT_OUTPUT */
+ {-1,29,0,0,5,0,0}, /* GPIO_MODE */
+ {-1,30,0,0,5,1,0}, /* GPIO_PIN_REG_IN */
+ {-1,31,0,0,5,0,0}, /* GPIO_PIN_REG_OUT */
+ {-1,32,0,0,8,1,0}, /* MCU_AGC_STATUS */
+ {-1,125,0,0,8,1,0}, /* MCU_ARB_STATUS */
+ {-1,126,0,0,8,1,1}, /* CHIP_ID */
+ {-1,127,0,0,1,0,1}, /* EMERGENCY_FORCE_HOST_CTRL */
+ {0,33,0,0,1,0,0}, /* RX_INVERT_IQ */
+ {0,33,1,0,1,0,1}, /* MODEM_INVERT_IQ */
+ {0,33,2,0,1,0,0}, /* MBWSSF_MODEM_INVERT_IQ */
+ {0,33,3,0,1,0,0}, /* RX_EDGE_SELECT */
+ {0,33,4,0,1,0,0}, /* MISC_RADIO_EN */
+ {0,33,5,0,1,0,0}, /* FSK_MODEM_INVERT_IQ */
+ {0,34,0,0,4,0,7}, /* FILTER_GAIN */
+ {0,35,0,0,8,0,240}, /* RADIO_SELECT */
+ {0,36,0,1,13,0,-384}, /* IF_FREQ_0 */
+ {0,38,0,1,13,0,-128}, /* IF_FREQ_1 */
+ {0,40,0,1,13,0,128}, /* IF_FREQ_2 */
+ {0,42,0,1,13,0,384}, /* IF_FREQ_3 */
+ {0,44,0,1,13,0,-384}, /* IF_FREQ_4 */
+ {0,46,0,1,13,0,-128}, /* IF_FREQ_5 */
+ {0,48,0,1,13,0,128}, /* IF_FREQ_6 */
+ {0,50,0,1,13,0,384}, /* IF_FREQ_7 */
+ {0,52,0,1,13,0,0}, /* IF_FREQ_8 */
+ {0,54,0,1,13,0,0}, /* IF_FREQ_9 */
+ {0,64,0,0,1,0,0}, /* CHANN_OVERRIDE_AGC_GAIN */
+ {0,64,1,0,4,0,7}, /* CHANN_AGC_GAIN */
+ {0,65,0,0,7,0,0}, /* CORR0_DETECT_EN */
+ {0,66,0,0,7,0,0}, /* CORR1_DETECT_EN */
+ {0,67,0,0,7,0,0}, /* CORR2_DETECT_EN */
+ {0,68,0,0,7,0,0}, /* CORR3_DETECT_EN */
+ {0,69,0,0,7,0,0}, /* CORR4_DETECT_EN */
+ {0,70,0,0,7,0,0}, /* CORR5_DETECT_EN */
+ {0,71,0,0,7,0,0}, /* CORR6_DETECT_EN */
+ {0,72,0,0,7,0,0}, /* CORR7_DETECT_EN */
+ {0,73,0,0,1,0,0}, /* CORR_SAME_PEAKS_OPTION_SF6 */
+ {0,73,1,0,1,0,1}, /* CORR_SAME_PEAKS_OPTION_SF7 */
+ {0,73,2,0,1,0,1}, /* CORR_SAME_PEAKS_OPTION_SF8 */
+ {0,73,3,0,1,0,1}, /* CORR_SAME_PEAKS_OPTION_SF9 */
+ {0,73,4,0,1,0,1}, /* CORR_SAME_PEAKS_OPTION_SF10 */
+ {0,73,5,0,1,0,1}, /* CORR_SAME_PEAKS_OPTION_SF11 */
+ {0,73,6,0,1,0,1}, /* CORR_SAME_PEAKS_OPTION_SF12 */
+ {0,74,0,0,4,0,4}, /* CORR_SIG_NOISE_RATIO_SF6 */
+ {0,74,4,0,4,0,4}, /* CORR_SIG_NOISE_RATIO_SF7 */
+ {0,75,0,0,4,0,4}, /* CORR_SIG_NOISE_RATIO_SF8 */
+ {0,75,4,0,4,0,4}, /* CORR_SIG_NOISE_RATIO_SF9 */
+ {0,76,0,0,4,0,4}, /* CORR_SIG_NOISE_RATIO_SF10 */
+ {0,76,4,0,4,0,4}, /* CORR_SIG_NOISE_RATIO_SF11 */
+ {0,77,0,0,4,0,4}, /* CORR_SIG_NOISE_RATIO_SF12 */
+ {0,78,0,0,4,0,4}, /* CORR_NUM_SAME_PEAK */
+ {0,78,4,0,3,0,5}, /* CORR_MAC_GAIN */
+ {0,81,0,0,12,0,0}, /* ADJUST_MODEM_START_OFFSET_RDX4 */
+ {0,83,0,0,12,0,4092}, /* ADJUST_MODEM_START_OFFSET_SF12_RDX4 */
+ {0,85,0,0,8,0,7}, /* DBG_CORR_SELECT_SF */
+ {0,86,0,0,8,0,0}, /* DBG_CORR_SELECT_CHANNEL */
+ {0,87,0,0,8,1,0}, /* DBG_DETECT_CPT */
+ {0,88,0,0,8,1,0}, /* DBG_SYMB_CPT */
+ {0,89,0,0,1,0,1}, /* CHIRP_INVERT_RX */
+ {0,89,1,0,1,0,1}, /* DC_NOTCH_EN */
+ {0,90,0,0,1,0,0}, /* IMPLICIT_CRC_EN */
+ {0,90,1,0,3,0,0}, /* IMPLICIT_CODING_RATE */
+ {0,91,0,0,8,0,0}, /* IMPLICIT_PAYLOAD_LENGHT */
+ {0,92,0,0,8,0,29}, /* FREQ_TO_TIME_INVERT */
+ {0,93,0,0,6,0,9}, /* FREQ_TO_TIME_DRIFT */
+ {0,94,0,0,2,0,2}, /* PAYLOAD_FINE_TIMING_GAIN */
+ {0,94,2,0,2,0,1}, /* PREAMBLE_FINE_TIMING_GAIN */
+ {0,94,4,0,2,0,0}, /* TRACKING_INTEGRAL */
+ {0,95,0,0,4,0,1}, /* FRAME_SYNCH_PEAK1_POS */
+ {0,95,4,0,4,0,2}, /* FRAME_SYNCH_PEAK2_POS */
+ {0,96,0,0,16,0,10}, /* PREAMBLE_SYMB1_NB */
+ {0,98,0,0,1,0,1}, /* FRAME_SYNCH_GAIN */
+ {0,98,1,0,1,0,1}, /* SYNCH_DETECT_TH */
+ {0,99,0,0,4,0,8}, /* LLR_SCALE */
+ {0,99,4,0,2,0,2}, /* SNR_AVG_CST */
+ {0,100,0,0,7,0,0}, /* PPM_OFFSET */
+ {0,101,0,0,8,0,255}, /* MAX_PAYLOAD_LEN */
+ {0,102,0,0,1,0,1}, /* ONLY_CRC_EN */
+ {0,103,0,0,8,0,0}, /* ZERO_PAD */
+ {0,104,0,0,4,0,8}, /* DEC_GAIN_OFFSET */
+ {0,104,4,0,4,0,7}, /* CHAN_GAIN_OFFSET */
+ {0,105,1,0,1,0,1}, /* FORCE_HOST_RADIO_CTRL */
+ {0,105,2,0,1,0,1}, /* FORCE_HOST_FE_CTRL */
+ {0,105,3,0,1,0,1}, /* FORCE_DEC_FILTER_GAIN */
+ {0,106,0,0,1,0,1}, /* MCU_RST_0 */
+ {0,106,1,0,1,0,1}, /* MCU_RST_1 */
+ {0,106,2,0,1,0,0}, /* MCU_SELECT_MUX_0 */
+ {0,106,3,0,1,0,0}, /* MCU_SELECT_MUX_1 */
+ {0,106,4,0,1,1,0}, /* MCU_CORRUPTION_DETECTED_0 */
+ {0,106,5,0,1,1,0}, /* MCU_CORRUPTION_DETECTED_1 */
+ {0,106,6,0,1,0,0}, /* MCU_SELECT_EDGE_0 */
+ {0,106,7,0,1,0,0}, /* MCU_SELECT_EDGE_1 */
+ {0,107,0,0,8,0,1}, /* CHANN_SELECT_RSSI */
+ {0,108,0,0,8,0,32}, /* RSSI_BB_DEFAULT_VALUE */
+ {0,109,0,0,8,0,100}, /* RSSI_DEC_DEFAULT_VALUE */
+ {0,110,0,0,8,0,100}, /* RSSI_CHANN_DEFAULT_VALUE */
+ {0,111,0,0,5,0,7}, /* RSSI_BB_FILTER_ALPHA */
+ {0,112,0,0,5,0,5}, /* RSSI_DEC_FILTER_ALPHA */
+ {0,113,0,0,5,0,8}, /* RSSI_CHANN_FILTER_ALPHA */
+ {0,114,0,0,6,0,0}, /* IQ_MISMATCH_A_AMP_COEFF */
+ {0,115,0,0,6,0,0}, /* IQ_MISMATCH_A_PHI_COEFF */
+ {0,116,0,0,6,0,0}, /* IQ_MISMATCH_B_AMP_COEFF */
+ {0,116,6,0,1,0,0}, /* IQ_MISMATCH_B_SEL_I */
+ {0,117,0,0,6,0,0}, /* IQ_MISMATCH_B_PHI_COEFF */
+ {1,33,0,0,1,0,0}, /* TX_TRIG_IMMEDIATE */
+ {1,33,1,0,1,0,0}, /* TX_TRIG_DELAYED */
+ {1,33,2,0,1,0,0}, /* TX_TRIG_GPS */
+ {1,34,0,0,16,0,0}, /* TX_START_DELAY */
+ {1,36,0,0,4,0,1}, /* TX_FRAME_SYNCH_PEAK1_POS */
+ {1,36,4,0,4,0,2}, /* TX_FRAME_SYNCH_PEAK2_POS */
+ {1,37,0,0,3,0,0}, /* TX_RAMP_DURATION */
+ {1,39,0,1,8,0,0}, /* TX_OFFSET_I */
+ {1,40,0,1,8,0,0}, /* TX_OFFSET_Q */
+ {1,41,0,0,1,0,0}, /* TX_MODE */
+ {1,41,1,0,4,0,0}, /* TX_ZERO_PAD */
+ {1,41,5,0,1,0,0}, /* TX_EDGE_SELECT */
+ {1,41,6,0,1,0,0}, /* TX_EDGE_SELECT_TOP */
+ {1,42,0,0,2,0,0}, /* TX_GAIN */
+ {1,42,2,0,3,0,5}, /* TX_CHIRP_LOW_PASS */
+ {1,42,5,0,2,0,0}, /* TX_FCC_WIDEBAND */
+ {1,42,7,0,1,0,1}, /* TX_SWAP_IQ */
+ {1,43,0,0,1,0,0}, /* MBWSSF_IMPLICIT_HEADER */
+ {1,43,1,0,1,0,0}, /* MBWSSF_IMPLICIT_CRC_EN */
+ {1,43,2,0,3,0,0}, /* MBWSSF_IMPLICIT_CODING_RATE */
+ {1,44,0,0,8,0,0}, /* MBWSSF_IMPLICIT_PAYLOAD_LENGHT */
+ {1,45,0,0,1,0,1}, /* MBWSSF_AGC_FREEZE_ON_DETECT */
+ {1,46,0,0,4,0,1}, /* MBWSSF_FRAME_SYNCH_PEAK1_POS */
+ {1,46,4,0,4,0,2}, /* MBWSSF_FRAME_SYNCH_PEAK2_POS */
+ {1,47,0,0,16,0,10}, /* MBWSSF_PREAMBLE_SYMB1_NB */
+ {1,49,0,0,1,0,1}, /* MBWSSF_FRAME_SYNCH_GAIN */
+ {1,49,1,0,1,0,1}, /* MBWSSF_SYNCH_DETECT_TH */
+ {1,50,0,0,8,0,10}, /* MBWSSF_DETECT_MIN_SINGLE_PEAK */
+ {1,51,0,0,3,0,3}, /* MBWSSF_DETECT_TRIG_SAME_PEAK_NB */
+ {1,52,0,0,8,0,29}, /* MBWSSF_FREQ_TO_TIME_INVERT */
+ {1,53,0,0,6,0,36}, /* MBWSSF_FREQ_TO_TIME_DRIFT */
+ {1,54,0,0,12,0,0}, /* MBWSSF_PPM_CORRECTION */
+ {1,56,0,0,2,0,2}, /* MBWSSF_PAYLOAD_FINE_TIMING_GAIN */
+ {1,56,2,0,2,0,1}, /* MBWSSF_PREAMBLE_FINE_TIMING_GAIN */
+ {1,56,4,0,2,0,0}, /* MBWSSF_TRACKING_INTEGRAL */
+ {1,57,0,0,8,0,0}, /* MBWSSF_ZERO_PAD */
+ {1,58,0,0,2,0,0}, /* MBWSSF_MODEM_BW */
+ {1,58,2,0,1,0,0}, /* MBWSSF_RADIO_SELECT */
+ {1,58,3,0,1,0,1}, /* MBWSSF_RX_CHIRP_INVERT */
+ {1,59,0,0,4,0,8}, /* MBWSSF_LLR_SCALE */
+ {1,59,4,0,2,0,3}, /* MBWSSF_SNR_AVG_CST */
+ {1,59,6,0,1,0,0}, /* MBWSSF_PPM_OFFSET */
+ {1,60,0,0,4,0,7}, /* MBWSSF_RATE_SF */
+ {1,60,4,0,1,0,1}, /* MBWSSF_ONLY_CRC_EN */
+ {1,61,0,0,8,0,255}, /* MBWSSF_MAX_PAYLOAD_LEN */
+ {1,62,0,0,8,1,128}, /* TX_STATUS */
+ {1,63,0,0,3,0,0}, /* FSK_CH_BW_EXPO */
+ {1,63,3,0,3,0,0}, /* FSK_RSSI_LENGTH */
+ {1,63,6,0,1,0,0}, /* FSK_RX_INVERT */
+ {1,63,7,0,1,0,0}, /* FSK_PKT_MODE */
+ {1,64,0,0,3,0,0}, /* FSK_PSIZE */
+ {1,64,3,0,1,0,0}, /* FSK_CRC_EN */
+ {1,64,4,0,2,0,0}, /* FSK_DCFREE_ENC */
+ {1,64,6,0,1,0,0}, /* FSK_CRC_IBM */
+ {1,65,0,0,5,0,0}, /* FSK_ERROR_OSR_TOL */
+ {1,65,7,0,1,0,0}, /* FSK_RADIO_SELECT */
+ {1,66,0,0,16,0,0}, /* FSK_BR_RATIO */
+ {1,68,0,0,32,0,0}, /* FSK_REF_PATTERN_LSB */
+ {1,72,0,0,32,0,0}, /* FSK_REF_PATTERN_MSB */
+ {1,76,0,0,8,0,0}, /* FSK_PKT_LENGTH */
+ {1,77,0,0,1,0,1}, /* FSK_TX_GAUSSIAN_EN */
+ {1,77,1,0,2,0,0}, /* FSK_TX_GAUSSIAN_SELECT_BT */
+ {1,77,3,0,1,0,1}, /* FSK_TX_PATTERN_EN */
+ {1,77,4,0,1,0,0}, /* FSK_TX_PREAMBLE_SEQ */
+ {1,77,5,0,3,0,0}, /* FSK_TX_PSIZE */
+ {1,80,0,0,8,0,0}, /* FSK_NODE_ADRS */
+ {1,81,0,0,8,0,0}, /* FSK_BROADCAST */
+ {1,82,0,0,1,0,1}, /* FSK_AUTO_AFC_ON */
+ {1,83,0,0,10,0,0}, /* FSK_PATTERN_TIMEOUT_CFG */
+ {2,33,0,0,8,0,0}, /* SPI_RADIO_A__DATA */
+ {2,34,0,0,8,1,0}, /* SPI_RADIO_A__DATA_READBACK */
+ {2,35,0,0,8,0,0}, /* SPI_RADIO_A__ADDR */
+ {2,37,0,0,1,0,0}, /* SPI_RADIO_A__CS */
+ {2,38,0,0,8,0,0}, /* SPI_RADIO_B__DATA */
+ {2,39,0,0,8,1,0}, /* SPI_RADIO_B__DATA_READBACK */
+ {2,40,0,0,8,0,0}, /* SPI_RADIO_B__ADDR */
+ {2,42,0,0,1,0,0}, /* SPI_RADIO_B__CS */
+ {2,43,0,0,1,0,0}, /* RADIO_A_EN */
+ {2,43,1,0,1,0,0}, /* RADIO_B_EN */
+ {2,43,2,0,1,0,1}, /* RADIO_RST */
+ {2,43,3,0,1,0,0}, /* LNA_A_EN */
+ {2,43,4,0,1,0,0}, /* PA_A_EN */
+ {2,43,5,0,1,0,0}, /* LNA_B_EN */
+ {2,43,6,0,1,0,0}, /* PA_B_EN */
+ {2,44,0,0,2,0,0}, /* PA_GAIN */
+ {2,45,0,0,4,0,2}, /* LNA_A_CTRL_LUT */
+ {2,45,4,0,4,0,4}, /* PA_A_CTRL_LUT */
+ {2,46,0,0,4,0,2}, /* LNA_B_CTRL_LUT */
+ {2,46,4,0,4,0,4}, /* PA_B_CTRL_LUT */
+ {2,47,0,0,5,0,0}, /* CAPTURE_SOURCE */
+ {2,47,5,0,1,0,0}, /* CAPTURE_START */
+ {2,47,6,0,1,0,0}, /* CAPTURE_FORCE_TRIGGER */
+ {2,47,7,0,1,0,0}, /* CAPTURE_WRAP */
+ {2,48,0,0,16,0,0}, /* CAPTURE_PERIOD */
+ {2,51,0,0,8,1,0}, /* MODEM_STATUS */
+ {2,52,0,0,8,1,0}, /* VALID_HEADER_COUNTER_0 */
+ {2,54,0,0,8,1,0}, /* VALID_PACKET_COUNTER_0 */
+ {2,56,0,0,8,1,0}, /* VALID_HEADER_COUNTER_MBWSSF */
+ {2,57,0,0,8,1,0}, /* VALID_HEADER_COUNTER_FSK */
+ {2,58,0,0,8,1,0}, /* VALID_PACKET_COUNTER_MBWSSF */
+ {2,59,0,0,8,1,0}, /* VALID_PACKET_COUNTER_FSK */
+ {2,60,0,0,8,1,0}, /* CHANN_RSSI */
+ {2,61,0,0,8,1,0}, /* BB_RSSI */
+ {2,62,0,0,8,1,0}, /* DEC_RSSI */
+ {2,63,0,0,8,1,0}, /* DBG_MCU_DATA */
+ {2,64,0,0,8,1,0}, /* DBG_ARB_MCU_RAM_DATA */
+ {2,65,0,0,8,1,0}, /* DBG_AGC_MCU_RAM_DATA */
+ {2,66,0,0,16,1,0}, /* NEXT_PACKET_CNT */
+ {2,68,0,0,16,1,0}, /* ADDR_CAPTURE_COUNT */
+ {2,70,0,0,32,1,0}, /* TIMESTAMP */
+ {2,74,0,0,4,1,0}, /* DBG_CHANN0_GAIN */
+ {2,74,4,0,4,1,0}, /* DBG_CHANN1_GAIN */
+ {2,75,0,0,4,1,0}, /* DBG_CHANN2_GAIN */
+ {2,75,4,0,4,1,0}, /* DBG_CHANN3_GAIN */
+ {2,76,0,0,4,1,0}, /* DBG_CHANN4_GAIN */
+ {2,76,4,0,4,1,0}, /* DBG_CHANN5_GAIN */
+ {2,77,0,0,4,1,0}, /* DBG_CHANN6_GAIN */
+ {2,77,4,0,4,1,0}, /* DBG_CHANN7_GAIN */
+ {2,78,0,0,4,1,0}, /* DBG_DEC_FILT_GAIN */
+ {2,79,0,0,3,1,0}, /* SPI_DATA_FIFO_PTR */
+ {2,79,3,0,3,1,0}, /* PACKET_DATA_FIFO_PTR */
+ {2,80,0,0,8,0,0}, /* DBG_ARB_MCU_RAM_ADDR */
+ {2,81,0,0,8,0,0}, /* DBG_AGC_MCU_RAM_ADDR */
+ {2,82,0,0,1,0,0}, /* SPI_MASTER_CHIP_SELECT_POLARITY */
+ {2,82,1,0,1,0,0}, /* SPI_MASTER_CPOL */
+ {2,82,2,0,1,0,0}, /* SPI_MASTER_CPHA */
+ {2,83,0,0,1,0,0}, /* SIG_GEN_ANALYSER_MUX_SEL */
+ {2,84,0,0,1,0,0}, /* SIG_GEN_EN */
+ {2,84,1,0,1,0,0}, /* SIG_ANALYSER_EN */
+ {2,84,2,0,2,0,0}, /* SIG_ANALYSER_AVG_LEN */
+ {2,84,4,0,3,0,0}, /* SIG_ANALYSER_PRECISION */
+ {2,84,7,0,1,1,0}, /* SIG_ANALYSER_VALID_OUT */
+ {2,85,0,0,8,0,0}, /* SIG_GEN_FREQ */
+ {2,86,0,0,8,0,0}, /* SIG_ANALYSER_FREQ */
+ {2,87,0,0,8,1,0}, /* SIG_ANALYSER_I_OUT */
+ {2,88,0,0,8,1,0}, /* SIG_ANALYSER_Q_OUT */
+ {2,89,0,0,1,0,0}, /* GPS_EN */
+ {2,89,1,0,1,0,1}, /* GPS_POL */
+ {2,90,0,1,8,0,0}, /* SW_TEST_REG1 */
+ {2,91,2,1,6,0,0}, /* SW_TEST_REG2 */
+ {2,92,0,1,16,0,0}, /* SW_TEST_REG3 */
+ {2,94,0,0,4,1,0}, /* DATA_MNGT_STATUS */
+ {2,95,0,0,5,1,0}, /* DATA_MNGT_CPT_FRAME_ALLOCATED */
+ {2,96,0,0,5,1,0}, /* DATA_MNGT_CPT_FRAME_FINISHED */
+ {2,97,0,0,5,1,0}, /* DATA_MNGT_CPT_FRAME_READEN */
+ {1,33,0,0,8,0,0} /* TX_TRIG_ALL (alias) */
+};
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE VARIABLES ---------------------------------------------------- */
+
+static int lgw_regpage = -1; /*! keep the value of the register page selected */
+
+/* -------------------------------------------------------------------------- */
+/* --- INTERNAL SHARED VARIABLES -------------------------------------------- */
+
+void *lgw_spi_target = NULL; /*! generic pointer to the SPI device */
+uint8_t lgw_spi_mux_mode = 0; /*! current SPI mux mode used */
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE FUNCTIONS ---------------------------------------------------- */
+
+int page_switch(uint8_t target) {
+ lgw_regpage = PAGE_MASK & target;
+ lgw_spi_w(lgw_spi_target, lgw_spi_mux_mode, LGW_SPI_MUX_TARGET_SX1301, PAGE_ADDR, (uint8_t)lgw_regpage);
+ return LGW_REG_SUCCESS;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+bool check_fpga_version(uint8_t version) {
+ int i;
+
+ for (i = 0; i < (int)(sizeof FPGA_VERSION); i++) {
+ if (FPGA_VERSION[i] == version ) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int reg_w_align32(void *spi_target, uint8_t spi_mux_mode, uint8_t spi_mux_target, struct lgw_reg_s r, int32_t reg_value) {
+ int spi_stat = LGW_REG_SUCCESS;
+ int i, size_byte;
+ uint8_t buf[4] = "\x00\x00\x00\x00";
+
+ if ((r.leng == 8) && (r.offs == 0)) {
+ /* direct write */
+ spi_stat += lgw_spi_w(spi_target, spi_mux_mode, spi_mux_target, r.addr, (uint8_t)reg_value);
+ } else if ((r.offs + r.leng) <= 8) {
+ /* single-byte read-modify-write, offs:[0-7], leng:[1-7] */
+ spi_stat += lgw_spi_r(spi_target, spi_mux_mode, spi_mux_target, r.addr, &buf[0]);
+ buf[1] = ((1 << r.leng) - 1) << r.offs; /* bit mask */
+ buf[2] = ((uint8_t)reg_value) << r.offs; /* new data offsetted */
+ buf[3] = (~buf[1] & buf[0]) | (buf[1] & buf[2]); /* mixing old & new data */
+ spi_stat += lgw_spi_w(spi_target, spi_mux_mode, spi_mux_target, r.addr, buf[3]);
+ } else if ((r.offs == 0) && (r.leng > 0) && (r.leng <= 32)) {
+ /* multi-byte direct write routine */
+ size_byte = (r.leng + 7) / 8; /* add a byte if it's not an exact multiple of 8 */
+ for (i=0; i<size_byte; ++i) {
+ /* big endian register file for a file on N bytes
+ Least significant byte is stored in buf[0], most one in buf[N-1] */
+ buf[i] = (uint8_t)(0x000000FF & reg_value);
+ reg_value = (reg_value >> 8);
+ }
+ spi_stat += lgw_spi_wb(spi_target, spi_mux_mode, spi_mux_target, r.addr, buf, size_byte); /* write the register in one burst */
+ } else {
+ /* register spanning multiple memory bytes but with an offset */
+ DEBUG_MSG("ERROR: REGISTER SIZE AND OFFSET ARE NOT SUPPORTED\n");
+ return LGW_REG_ERROR;
+ }
+
+ return spi_stat;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int reg_r_align32(void *spi_target, uint8_t spi_mux_mode, uint8_t spi_mux_target, struct lgw_reg_s r, int32_t *reg_value) {
+ int spi_stat = LGW_SPI_SUCCESS;
+ uint8_t bufu[4] = "\x00\x00\x00\x00";
+ int8_t *bufs = (int8_t *)bufu;
+ int i, size_byte;
+ uint32_t u = 0;
+
+ if ((r.offs + r.leng) <= 8) {
+ /* read one byte, then shift and mask bits to get reg value with sign extension if needed */
+ spi_stat += lgw_spi_r(spi_target, spi_mux_mode, spi_mux_target, r.addr, &bufu[0]);
+ bufu[1] = bufu[0] << (8 - r.leng - r.offs); /* left-align the data */
+ if (r.sign == true) {
+ bufs[2] = bufs[1] >> (8 - r.leng); /* right align the data with sign extension (ARITHMETIC right shift) */
+ *reg_value = (int32_t)bufs[2]; /* signed pointer -> 32b sign extension */
+ } else {
+ bufu[2] = bufu[1] >> (8 - r.leng); /* right align the data, no sign extension */
+ *reg_value = (int32_t)bufu[2]; /* unsigned pointer -> no sign extension */
+ }
+ } else if ((r.offs == 0) && (r.leng > 0) && (r.leng <= 32)) {
+ size_byte = (r.leng + 7) / 8; /* add a byte if it's not an exact multiple of 8 */
+ spi_stat += lgw_spi_rb(spi_target, spi_mux_mode, spi_mux_target, r.addr, bufu, size_byte);
+ u = 0;
+ for (i=(size_byte-1); i>=0; --i) {
+ u = (uint32_t)bufu[i] + (u << 8); /* transform a 4-byte array into a 32 bit word */
+ }
+ if (r.sign == true) {
+ u = u << (32 - r.leng); /* left-align the data */
+ *reg_value = (int32_t)u >> (32 - r.leng); /* right-align the data with sign extension (ARITHMETIC right shift) */
+ } else {
+ *reg_value = (int32_t)u; /* unsigned value -> return 'as is' */
+ }
+ } else {
+ /* register spanning multiple memory bytes but with an offset */
+ DEBUG_MSG("ERROR: REGISTER SIZE AND OFFSET ARE NOT SUPPORTED\n");
+ return LGW_REG_ERROR;
+ }
+
+ return spi_stat;
+}
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC FUNCTIONS DEFINITION ------------------------------------------ */
+
+/* Concentrator connect */
+int lgw_connect(bool spi_only, uint32_t tx_notch_freq) {
+ int spi_stat = LGW_SPI_SUCCESS;
+ uint8_t u = 0;
+ int x;
+
+ /* check SPI link status */
+ if (lgw_spi_target != NULL) {
+ DEBUG_MSG("WARNING: concentrator was already connected\n");
+ lgw_spi_close(lgw_spi_target);
+ }
+
+ /* open the SPI link */
+ spi_stat = lgw_spi_open(&lgw_spi_target);
+ if (spi_stat != LGW_SPI_SUCCESS) {
+ DEBUG_MSG("ERROR CONNECTING CONCENTRATOR\n");
+ return LGW_REG_ERROR;
+ }
+
+ if (spi_only == false ) {
+ /* Detect if the gateway has an FPGA with SPI mux header support */
+ /* First, we assume there is an FPGA, and try to read its version */
+ spi_stat = lgw_spi_r(lgw_spi_target, LGW_SPI_MUX_MODE1, LGW_SPI_MUX_TARGET_FPGA, loregs[LGW_VERSION].addr, &u);
+ if (spi_stat != LGW_SPI_SUCCESS) {
+ DEBUG_MSG("ERROR READING VERSION REGISTER\n");
+ return LGW_REG_ERROR;
+ }
+ if (check_fpga_version(u) != true) {
+ /* We failed to read expected FPGA version, so let's assume there is no FPGA */
+ DEBUG_PRINTF("INFO: no FPGA detected or version not supported (v%u)\n", u);
+ lgw_spi_mux_mode = LGW_SPI_MUX_MODE0;
+ } else {
+ DEBUG_PRINTF("INFO: detected FPGA with SPI mux header (v%u)\n", u);
+ lgw_spi_mux_mode = LGW_SPI_MUX_MODE1;
+ /* FPGA Soft Reset */
+ lgw_spi_w(lgw_spi_target, lgw_spi_mux_mode, LGW_SPI_MUX_TARGET_FPGA, 0, 1);
+ lgw_spi_w(lgw_spi_target, lgw_spi_mux_mode, LGW_SPI_MUX_TARGET_FPGA, 0, 0);
+ /* FPGA configure */
+ x = lgw_fpga_configure(tx_notch_freq);
+ if (x != LGW_REG_SUCCESS) {
+ DEBUG_MSG("ERROR CONFIGURING FPGA\n");
+ return LGW_REG_ERROR;
+ }
+ }
+
+ /* check SX1301 version */
+ spi_stat = lgw_spi_r(lgw_spi_target, lgw_spi_mux_mode, LGW_SPI_MUX_TARGET_SX1301, loregs[LGW_VERSION].addr, &u);
+ if (spi_stat != LGW_SPI_SUCCESS) {
+ DEBUG_MSG("ERROR READING CHIP VERSION REGISTER\n");
+ return LGW_REG_ERROR;
+ }
+ if (u != loregs[LGW_VERSION].dflt) {
+ DEBUG_PRINTF("ERROR: NOT EXPECTED CHIP VERSION (v%u)\n", u);
+ return LGW_REG_ERROR;
+ }
+
+ /* write 0 to the page/reset register */
+ spi_stat = lgw_spi_w(lgw_spi_target, lgw_spi_mux_mode, LGW_SPI_MUX_TARGET_SX1301, loregs[LGW_PAGE_REG].addr, 0);
+ if (spi_stat != LGW_SPI_SUCCESS) {
+ DEBUG_MSG("ERROR WRITING PAGE REGISTER\n");
+ return LGW_REG_ERROR;
+ } else {
+ lgw_regpage = 0;
+ }
+ }
+
+ DEBUG_MSG("Note: success connecting the concentrator\n");
+ return LGW_REG_SUCCESS;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+/* Concentrator disconnect */
+int lgw_disconnect(void) {
+ if (lgw_spi_target != NULL) {
+ lgw_spi_close(lgw_spi_target);
+ lgw_spi_target = NULL;
+ DEBUG_MSG("Note: success disconnecting the concentrator\n");
+ return LGW_REG_SUCCESS;
+ } else {
+ DEBUG_MSG("WARNING: concentrator was already disconnected\n");
+ return LGW_REG_ERROR;
+ }
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+/* soft-reset function */
+int lgw_soft_reset(void) {
+ /* check if SPI is initialised */
+ if ((lgw_spi_target == NULL) || (lgw_regpage < 0)) {
+ DEBUG_MSG("ERROR: CONCENTRATOR UNCONNECTED\n");
+ return LGW_REG_ERROR;
+ }
+ lgw_spi_w(lgw_spi_target, lgw_spi_mux_mode, LGW_SPI_MUX_TARGET_SX1301, 0, 0x80); /* 1 -> SOFT_RESET bit */
+ lgw_regpage = 0; /* reset the paging static variable */
+ return LGW_REG_SUCCESS;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+/* register verification */
+int lgw_reg_check(FILE *f) {
+ struct lgw_reg_s r;
+ int32_t read_value;
+ char ok_msg[] = "+++MATCH+++";
+ char notok_msg[] = "###MISMATCH###";
+ char *ptr;
+ int i;
+
+ /* check if SPI is initialised */
+ if ((lgw_spi_target == NULL) || (lgw_regpage < 0)) {
+ DEBUG_MSG("ERROR: CONCENTRATOR UNCONNECTED\n");
+ fprintf(f, "ERROR: CONCENTRATOR UNCONNECTED\n");
+ return LGW_REG_ERROR;
+ }
+
+ fprintf(f, "Start of register verification\n");
+ for (i=0; i<LGW_TOTALREGS; ++i) {
+ r = loregs[i];
+ lgw_reg_r(i, &read_value);
+ ptr = (read_value == r.dflt) ? ok_msg : notok_msg;
+ if (r.sign == true)
+ fprintf(f, "%s reg number %d read: %d (%x) default: %d (%x)\n", ptr, i, read_value, read_value, r.dflt, r.dflt);
+ else
+ fprintf(f, "%s reg number %d read: %u (%x) default: %u (%x)\n", ptr, i, read_value, read_value, r.dflt, r.dflt);
+ }
+ fprintf(f, "End of register verification\n");
+
+ return LGW_REG_SUCCESS;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+/* Write to a register addressed by name */
+int lgw_reg_w(uint16_t register_id, int32_t reg_value) {
+ int spi_stat = LGW_SPI_SUCCESS;
+ struct lgw_reg_s r;
+
+ /* check input parameters */
+ if (register_id >= LGW_TOTALREGS) {
+ DEBUG_MSG("ERROR: REGISTER NUMBER OUT OF DEFINED RANGE\n");
+ return LGW_REG_ERROR;
+ }
+
+ /* check if SPI is initialised */
+ if ((lgw_spi_target == NULL) || (lgw_regpage < 0)) {
+ DEBUG_MSG("ERROR: CONCENTRATOR UNCONNECTED\n");
+ return LGW_REG_ERROR;
+ }
+
+ /* intercept direct access to PAGE_REG & SOFT_RESET */
+ if (register_id == LGW_PAGE_REG) {
+ page_switch(reg_value);
+ return LGW_REG_SUCCESS;
+ } else if (register_id == LGW_SOFT_RESET) {
+ /* only reset if lsb is 1 */
+ if ((reg_value & 0x01) != 0)
+ lgw_soft_reset();
+ return LGW_REG_SUCCESS;
+ }
+
+ /* get register struct from the struct array */
+ r = loregs[register_id];
+
+ /* reject write to read-only registers */
+ if (r.rdon == 1){
+ DEBUG_MSG("ERROR: TRYING TO WRITE A READ-ONLY REGISTER\n");
+ return LGW_REG_ERROR;
+ }
+
+ /* select proper register page if needed */
+ if ((r.page != -1) && (r.page != lgw_regpage)) {
+ spi_stat += page_switch(r.page);
+ }
+
+ spi_stat += reg_w_align32(lgw_spi_target, lgw_spi_mux_mode, LGW_SPI_MUX_TARGET_SX1301, r, reg_value);
+
+ if (spi_stat != LGW_SPI_SUCCESS) {
+ DEBUG_MSG("ERROR: SPI ERROR DURING REGISTER WRITE\n");
+ return LGW_REG_ERROR;
+ } else {
+ return LGW_REG_SUCCESS;
+ }
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+/* Read to a register addressed by name */
+int lgw_reg_r(uint16_t register_id, int32_t *reg_value) {
+ int spi_stat = LGW_SPI_SUCCESS;
+ struct lgw_reg_s r;
+
+ /* check input parameters */
+ CHECK_NULL(reg_value);
+ if (register_id >= LGW_TOTALREGS) {
+ DEBUG_MSG("ERROR: REGISTER NUMBER OUT OF DEFINED RANGE\n");
+ return LGW_REG_ERROR;
+ }
+
+ /* check if SPI is initialised */
+ if ((lgw_spi_target == NULL) || (lgw_regpage < 0)) {
+ DEBUG_MSG("ERROR: CONCENTRATOR UNCONNECTED\n");
+ return LGW_REG_ERROR;
+ }
+
+ /* get register struct from the struct array */
+ r = loregs[register_id];
+
+ /* select proper register page if needed */
+ if ((r.page != -1) && (r.page != lgw_regpage)) {
+ spi_stat += page_switch(r.page);
+ }
+
+ spi_stat += reg_r_align32(lgw_spi_target, lgw_spi_mux_mode, LGW_SPI_MUX_TARGET_SX1301, r, reg_value);
+
+ if (spi_stat != LGW_SPI_SUCCESS) {
+ DEBUG_MSG("ERROR: SPI ERROR DURING REGISTER WRITE\n");
+ return LGW_REG_ERROR;
+ } else {
+ return LGW_REG_SUCCESS;
+ }
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+/* Point to a register by name and do a burst write */
+int lgw_reg_wb(uint16_t register_id, uint8_t *data, uint16_t size) {
+ int spi_stat = LGW_SPI_SUCCESS;
+ struct lgw_reg_s r;
+
+ /* check input parameters */
+ CHECK_NULL(data);
+ if (size == 0) {
+ DEBUG_MSG("ERROR: BURST OF NULL LENGTH\n");
+ return LGW_REG_ERROR;
+ }
+ if (register_id >= LGW_TOTALREGS) {
+ DEBUG_MSG("ERROR: REGISTER NUMBER OUT OF DEFINED RANGE\n");
+ return LGW_REG_ERROR;
+ }
+
+ /* check if SPI is initialised */
+ if ((lgw_spi_target == NULL) || (lgw_regpage < 0)) {
+ DEBUG_MSG("ERROR: CONCENTRATOR UNCONNECTED\n");
+ return LGW_REG_ERROR;
+ }
+
+ /* get register struct from the struct array */
+ r = loregs[register_id];
+
+ /* reject write to read-only registers */
+ if (r.rdon == 1){
+ DEBUG_MSG("ERROR: TRYING TO BURST WRITE A READ-ONLY REGISTER\n");
+ return LGW_REG_ERROR;
+ }
+
+ /* select proper register page if needed */
+ if ((r.page != -1) && (r.page != lgw_regpage)) {
+ spi_stat += page_switch(r.page);
+ }
+
+ /* do the burst write */
+ spi_stat += lgw_spi_wb(lgw_spi_target, lgw_spi_mux_mode, LGW_SPI_MUX_TARGET_SX1301, r.addr, data, size);
+
+ if (spi_stat != LGW_SPI_SUCCESS) {
+ DEBUG_MSG("ERROR: SPI ERROR DURING REGISTER BURST WRITE\n");
+ return LGW_REG_ERROR;
+ } else {
+ return LGW_REG_SUCCESS;
+ }
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+/* Point to a register by name and do a burst read */
+int lgw_reg_rb(uint16_t register_id, uint8_t *data, uint16_t size) {
+ int spi_stat = LGW_SPI_SUCCESS;
+ struct lgw_reg_s r;
+
+ /* check input parameters */
+ CHECK_NULL(data);
+ if (size == 0) {
+ DEBUG_MSG("ERROR: BURST OF NULL LENGTH\n");
+ return LGW_REG_ERROR;
+ }
+ if (register_id >= LGW_TOTALREGS) {
+ DEBUG_MSG("ERROR: REGISTER NUMBER OUT OF DEFINED RANGE\n");
+ return LGW_REG_ERROR;
+ }
+
+ /* check if SPI is initialised */
+ if ((lgw_spi_target == NULL) || (lgw_regpage < 0)) {
+ DEBUG_MSG("ERROR: CONCENTRATOR UNCONNECTED\n");
+ return LGW_REG_ERROR;
+ }
+
+ /* get register struct from the struct array */
+ r = loregs[register_id];
+
+ /* select proper register page if needed */
+ if ((r.page != -1) && (r.page != lgw_regpage)) {
+ spi_stat += page_switch(r.page);
+ }
+
+ /* do the burst read */
+ spi_stat += lgw_spi_rb(lgw_spi_target, lgw_spi_mux_mode, LGW_SPI_MUX_TARGET_SX1301, r.addr, data, size);
+
+ if (spi_stat != LGW_SPI_SUCCESS) {
+ DEBUG_MSG("ERROR: SPI ERROR DURING REGISTER BURST READ\n");
+ return LGW_REG_ERROR;
+ } else {
+ return LGW_REG_SUCCESS;
+ }
+}
+
+/* --- EOF ------------------------------------------------------------------ */
diff --git a/libloragw/src/loragw_spi.native.c b/libloragw/src/loragw_spi.native.c
new file mode 100644
index 0000000..c01ed1c
--- /dev/null
+++ b/libloragw/src/loragw_spi.native.c
@@ -0,0 +1,385 @@
+/*
+ / _____) _ | |
+( (____ _____ ____ _| |_ _____ ____| |__
+ \____ \| ___ | (_ _) ___ |/ ___) _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+ (C)2013 Semtech-Cycleo
+
+Description:
+ Host specific functions to address the LoRa concentrator registers through
+ a SPI interface.
+ Single-byte read/write and burst read/write.
+ Does not handle pagination.
+ Could be used with multiple SPI ports in parallel (explicit file descriptor)
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+Maintainer: Sylvain Miermont
+*/
+
+
+/* -------------------------------------------------------------------------- */
+/* --- DEPENDANCIES --------------------------------------------------------- */
+
+#include <stdint.h> /* C99 types */
+#include <stdio.h> /* printf fprintf */
+#include <stdlib.h> /* malloc free */
+#include <unistd.h> /* lseek, close */
+#include <fcntl.h> /* open */
+#include <string.h> /* memset */
+
+#include <sys/ioctl.h>
+#include <linux/spi/spidev.h>
+
+#include "loragw_spi.h"
+#include "loragw_hal.h"
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE MACROS ------------------------------------------------------- */
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+#if DEBUG_SPI == 1
+ #define DEBUG_MSG(str) fprintf(stderr, str)
+ #define DEBUG_PRINTF(fmt, args...) fprintf(stderr,"%s:%d: "fmt, __FUNCTION__, __LINE__, args)
+ #define CHECK_NULL(a) if(a==NULL){fprintf(stderr,"%s:%d: ERROR: NULL POINTER AS ARGUMENT\n", __FUNCTION__, __LINE__);return LGW_SPI_ERROR;}
+#else
+ #define DEBUG_MSG(str)
+ #define DEBUG_PRINTF(fmt, args...)
+ #define CHECK_NULL(a) if(a==NULL){return LGW_SPI_ERROR;}
+#endif
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE CONSTANTS ---------------------------------------------------- */
+
+#define READ_ACCESS 0x00
+#define WRITE_ACCESS 0x80
+#define SPI_SPEED 8000000
+#define SPI_DEV_PATH "/dev/spidev0.0"
+//#define SPI_DEV_PATH "/dev/spidev32766.0"
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC FUNCTIONS DEFINITION ------------------------------------------ */
+
+/* SPI initialization and configuration */
+int lgw_spi_open(void **spi_target_ptr) {
+ int *spi_device = NULL;
+ int dev;
+ int a=0, b=0;
+ int i;
+
+ /* check input variables */
+ CHECK_NULL(spi_target_ptr); /* cannot be null, must point on a void pointer (*spi_target_ptr can be null) */
+
+ /* allocate memory for the device descriptor */
+ spi_device = malloc(sizeof(int));
+ if (spi_device == NULL) {
+ DEBUG_MSG("ERROR: MALLOC FAIL\n");
+ return LGW_SPI_ERROR;
+ }
+
+ /* open SPI device */
+ dev = open(SPI_DEV_PATH, O_RDWR);
+ if (dev < 0) {
+ DEBUG_PRINTF("ERROR: failed to open SPI device %s\n", SPI_DEV_PATH);
+ return LGW_SPI_ERROR;
+ }
+
+ /* setting SPI mode to 'mode 0' */
+ i = SPI_MODE_0;
+ a = ioctl(dev, SPI_IOC_WR_MODE, &i);
+ b = ioctl(dev, SPI_IOC_RD_MODE, &i);
+ if ((a < 0) || (b < 0)) {
+ DEBUG_MSG("ERROR: SPI PORT FAIL TO SET IN MODE 0\n");
+ close(dev);
+ free(spi_device);
+ return LGW_SPI_ERROR;
+ }
+
+ /* setting SPI max clk (in Hz) */
+ i = SPI_SPEED;
+ a = ioctl(dev, SPI_IOC_WR_MAX_SPEED_HZ, &i);
+ b = ioctl(dev, SPI_IOC_RD_MAX_SPEED_HZ, &i);
+ if ((a < 0) || (b < 0)) {
+ DEBUG_MSG("ERROR: SPI PORT FAIL TO SET MAX SPEED\n");
+ close(dev);
+ free(spi_device);
+ return LGW_SPI_ERROR;
+ }
+
+ /* setting SPI to MSB first */
+ i = 0;
+ a = ioctl(dev, SPI_IOC_WR_LSB_FIRST, &i);
+ b = ioctl(dev, SPI_IOC_RD_LSB_FIRST, &i);
+ if ((a < 0) || (b < 0)) {
+ DEBUG_MSG("ERROR: SPI PORT FAIL TO SET MSB FIRST\n");
+ close(dev);
+ free(spi_device);
+ return LGW_SPI_ERROR;
+ }
+
+ /* setting SPI to 8 bits per word */
+ i = 0;
+ a = ioctl(dev, SPI_IOC_WR_BITS_PER_WORD, &i);
+ b = ioctl(dev, SPI_IOC_RD_BITS_PER_WORD, &i);
+ if ((a < 0) || (b < 0)) {
+ DEBUG_MSG("ERROR: SPI PORT FAIL TO SET 8 BITS-PER-WORD\n");
+ close(dev);
+ return LGW_SPI_ERROR;
+ }
+
+ *spi_device = dev;
+ *spi_target_ptr = (void *)spi_device;
+ DEBUG_MSG("Note: SPI port opened and configured ok\n");
+ return LGW_SPI_SUCCESS;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+/* SPI release */
+int lgw_spi_close(void *spi_target) {
+ int spi_device;
+ int a;
+
+ /* check input variables */
+ CHECK_NULL(spi_target);
+
+ /* close file & deallocate file descriptor */
+ spi_device = *(int *)spi_target; /* must check that spi_target is not null beforehand */
+ a = close(spi_device);
+ free(spi_target);
+
+ /* determine return code */
+ if (a < 0) {
+ DEBUG_MSG("ERROR: SPI PORT FAILED TO CLOSE\n");
+ return LGW_SPI_ERROR;
+ } else {
+ DEBUG_MSG("Note: SPI port closed\n");
+ return LGW_SPI_SUCCESS;
+ }
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+/* Simple write */
+int lgw_spi_w(void *spi_target, uint8_t spi_mux_mode, uint8_t spi_mux_target, uint8_t address, uint8_t data) {
+ int spi_device;
+ uint8_t out_buf[3];
+ uint8_t command_size;
+ struct spi_ioc_transfer k;
+ int a;
+
+ /* check input variables */
+ CHECK_NULL(spi_target);
+ if ((address & 0x80) != 0) {
+ DEBUG_MSG("WARNING: SPI address > 127\n");
+ }
+
+ spi_device = *(int *)spi_target; /* must check that spi_target is not null beforehand */
+
+ /* prepare frame to be sent */
+ if (spi_mux_mode == LGW_SPI_MUX_MODE1) {
+ out_buf[0] = spi_mux_target;
+ out_buf[1] = WRITE_ACCESS | (address & 0x7F);
+ out_buf[2] = data;
+ command_size = 3;
+ } else {
+ out_buf[0] = WRITE_ACCESS | (address & 0x7F);
+ out_buf[1] = data;
+ command_size = 2;
+ }
+
+ /* I/O transaction */
+ memset(&k, 0, sizeof(k)); /* clear k */
+ k.tx_buf = (unsigned long) out_buf;
+ k.len = command_size;
+ k.speed_hz = SPI_SPEED;
+ k.cs_change = 0;
+ k.bits_per_word = 8;
+ a = ioctl(spi_device, SPI_IOC_MESSAGE(1), &k);
+
+ /* determine return code */
+ if (a != (int)k.len) {
+ DEBUG_MSG("ERROR: SPI WRITE FAILURE\n");
+ return LGW_SPI_ERROR;
+ } else {
+ DEBUG_MSG("Note: SPI write success\n");
+ return LGW_SPI_SUCCESS;
+ }
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+/* Simple read */
+int lgw_spi_r(void *spi_target, uint8_t spi_mux_mode, uint8_t spi_mux_target, uint8_t address, uint8_t *data) {
+ int spi_device;
+ uint8_t out_buf[3];
+ uint8_t command_size;
+ uint8_t in_buf[ARRAY_SIZE(out_buf)];
+ struct spi_ioc_transfer k;
+ int a;
+
+ /* check input variables */
+ CHECK_NULL(spi_target);
+ if ((address & 0x80) != 0) {
+ DEBUG_MSG("WARNING: SPI address > 127\n");
+ }
+ CHECK_NULL(data);
+
+ spi_device = *(int *)spi_target; /* must check that spi_target is not null beforehand */
+
+ /* prepare frame to be sent */
+ if (spi_mux_mode == LGW_SPI_MUX_MODE1) {
+ out_buf[0] = spi_mux_target;
+ out_buf[1] = READ_ACCESS | (address & 0x7F);
+ out_buf[2] = 0x00;
+ command_size = 3;
+ } else {
+ out_buf[0] = READ_ACCESS | (address & 0x7F);
+ out_buf[1] = 0x00;
+ command_size = 2;
+ }
+
+ /* I/O transaction */
+ memset(&k, 0, sizeof(k)); /* clear k */
+ k.tx_buf = (unsigned long) out_buf;
+ k.rx_buf = (unsigned long) in_buf;
+ k.len = command_size;
+ k.cs_change = 0;
+ a = ioctl(spi_device, SPI_IOC_MESSAGE(1), &k);
+
+ /* determine return code */
+ if (a != (int)k.len) {
+ DEBUG_MSG("ERROR: SPI READ FAILURE\n");
+ return LGW_SPI_ERROR;
+ } else {
+ DEBUG_MSG("Note: SPI read success\n");
+ *data = in_buf[command_size - 1];
+ return LGW_SPI_SUCCESS;
+ }
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+/* Burst (multiple-byte) write */
+int lgw_spi_wb(void *spi_target, uint8_t spi_mux_mode, uint8_t spi_mux_target, uint8_t address, uint8_t *data, uint16_t size) {
+ int spi_device;
+ uint8_t command[2];
+ uint8_t command_size;
+ struct spi_ioc_transfer k[2];
+ int size_to_do, chunk_size, offset;
+ int byte_transfered = 0;
+ int i;
+
+ /* check input parameters */
+ CHECK_NULL(spi_target);
+ if ((address & 0x80) != 0) {
+ DEBUG_MSG("WARNING: SPI address > 127\n");
+ }
+ CHECK_NULL(data);
+ if (size == 0) {
+ DEBUG_MSG("ERROR: BURST OF NULL LENGTH\n");
+ return LGW_SPI_ERROR;
+ }
+
+ spi_device = *(int *)spi_target; /* must check that spi_target is not null beforehand */
+
+ /* prepare command byte */
+ if (spi_mux_mode == LGW_SPI_MUX_MODE1) {
+ command[0] = spi_mux_target;
+ command[1] = WRITE_ACCESS | (address & 0x7F);
+ command_size = 2;
+ } else {
+ command[0] = WRITE_ACCESS | (address & 0x7F);
+ command_size = 1;
+ }
+ size_to_do = size;
+
+ /* I/O transaction */
+ memset(&k, 0, sizeof(k)); /* clear k */
+ k[0].tx_buf = (unsigned long) &command[0];
+ k[0].len = command_size;
+ k[0].cs_change = 0;
+ k[1].cs_change = 0;
+ for (i=0; size_to_do > 0; ++i) {
+ chunk_size = (size_to_do < LGW_BURST_CHUNK) ? size_to_do : LGW_BURST_CHUNK;
+ offset = i * LGW_BURST_CHUNK;
+ k[1].tx_buf = (unsigned long)(data + offset);
+ k[1].len = chunk_size;
+ byte_transfered += (ioctl(spi_device, SPI_IOC_MESSAGE(2), &k) - k[0].len );
+ DEBUG_PRINTF("BURST WRITE: to trans %d # chunk %d # transferred %d \n", size_to_do, chunk_size, byte_transfered);
+ size_to_do -= chunk_size; /* subtract the quantity of data already transferred */
+ }
+
+ /* determine return code */
+ if (byte_transfered != size) {
+ DEBUG_MSG("ERROR: SPI BURST WRITE FAILURE\n");
+ return LGW_SPI_ERROR;
+ } else {
+ DEBUG_MSG("Note: SPI burst write success\n");
+ return LGW_SPI_SUCCESS;
+ }
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+/* Burst (multiple-byte) read */
+int lgw_spi_rb(void *spi_target, uint8_t spi_mux_mode, uint8_t spi_mux_target, uint8_t address, uint8_t *data, uint16_t size) {
+ int spi_device;
+ uint8_t command[2];
+ uint8_t command_size;
+ struct spi_ioc_transfer k[2];
+ int size_to_do, chunk_size, offset;
+ int byte_transfered = 0;
+ int i;
+
+ /* check input parameters */
+ CHECK_NULL(spi_target);
+ if ((address & 0x80) != 0) {
+ DEBUG_MSG("WARNING: SPI address > 127\n");
+ }
+ CHECK_NULL(data);
+ if (size == 0) {
+ DEBUG_MSG("ERROR: BURST OF NULL LENGTH\n");
+ return LGW_SPI_ERROR;
+ }
+
+ spi_device = *(int *)spi_target; /* must check that spi_target is not null beforehand */
+
+ /* prepare command byte */
+ if (spi_mux_mode == LGW_SPI_MUX_MODE1) {
+ command[0] = spi_mux_target;
+ command[1] = READ_ACCESS | (address & 0x7F);
+ command_size = 2;
+ } else {
+ command[0] = READ_ACCESS | (address & 0x7F);
+ command_size = 1;
+ }
+ size_to_do = size;
+
+ /* I/O transaction */
+ memset(&k, 0, sizeof(k)); /* clear k */
+ k[0].tx_buf = (unsigned long) &command[0];
+ k[0].len = command_size;
+ k[0].cs_change = 0;
+ k[1].cs_change = 0;
+ for (i=0; size_to_do > 0; ++i) {
+ chunk_size = (size_to_do < LGW_BURST_CHUNK) ? size_to_do : LGW_BURST_CHUNK;
+ offset = i * LGW_BURST_CHUNK;
+ k[1].rx_buf = (unsigned long)(data + offset);
+ k[1].len = chunk_size;
+ byte_transfered += (ioctl(spi_device, SPI_IOC_MESSAGE(2), &k) - k[0].len );
+ DEBUG_PRINTF("BURST READ: to trans %d # chunk %d # transferred %d \n", size_to_do, chunk_size, byte_transfered);
+ size_to_do -= chunk_size; /* subtract the quantity of data already transferred */
+ }
+
+ /* determine return code */
+ if (byte_transfered != size) {
+ DEBUG_MSG("ERROR: SPI BURST READ FAILURE\n");
+ return LGW_SPI_ERROR;
+ } else {
+ DEBUG_MSG("Note: SPI burst read success\n");
+ return LGW_SPI_SUCCESS;
+ }
+}
+
+/* --- EOF ------------------------------------------------------------------ */
diff --git a/libloragw/tst/test_loragw_cal.c b/libloragw/tst/test_loragw_cal.c
new file mode 100644
index 0000000..533d189
--- /dev/null
+++ b/libloragw/tst/test_loragw_cal.c
@@ -0,0 +1,756 @@
+/*
+ / _____) _ | |
+( (____ _____ ____ _| |_ _____ ____| |__
+ \____ \| ___ | (_ _) ___ |/ ___) _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+ (C)2013 Semtech-Cycleo
+
+Description:
+ Minimum test program for the loragw_hal 'library'
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+Maintainer: Sylvain Miermont
+*/
+
+
+/* -------------------------------------------------------------------------- */
+/* --- DEPENDANCIES --------------------------------------------------------- */
+
+/* fix an issue between POSIX and C99 */
+#if __STDC_VERSION__ >= 199901L
+ #define _XOPEN_SOURCE 600
+#else
+ #define _XOPEN_SOURCE 500
+#endif
+
+#include <stdint.h> /* C99 types */
+#include <stdbool.h> /* bool type */
+#include <stdio.h> /* printf */
+#include <string.h> /* memset */
+#include <signal.h> /* sigaction */
+#include <math.h> /* cos */
+#include <unistd.h> /* getopt access */
+
+#include "loragw_hal.h"
+#include "loragw_reg.h"
+#include "loragw_aux.h"
+#include "loragw_radio.h"
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE MACROS ------------------------------------------------------- */
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE CONSTANTS ---------------------------------------------------- */
+
+#define DEFAULT_TX_NOTCH_FREQ 129E3
+#define DEFAULT_RSSI_OFFSET 0.0
+#define NB_CAL_MAX 100
+#define MCU_AGC 1
+#define MCU_AGC_FW_BYTE 8192 /* size of the firmware IN BYTES (= twice the number of 14b words) */
+#define FW_VERSION_ADDR 0x20
+#define FW_VERSION_CAL 2
+#define RAM_SIZE 4096
+#define FREQ_SIG_NORM 0.078125
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE VARIABLES ---------------------------------------------------- */
+
+#include "../src/cal_fw.var" /* external definition of the variable */
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE TYPES --------------------------------------------------------- */
+
+struct cal_res_s {
+ int8_t amp_a;
+ int8_t phi_a;
+ int8_t amp_b;
+ int8_t phi_b;
+ int8_t offset_i_a [8];
+ int8_t offset_q_a [8];
+ int8_t offset_i_b [8];
+ int8_t offset_q_b [8];
+ uint8_t img_rej_a;
+ uint8_t img_rej_b;
+ uint8_t offset_rej_a [8];
+ uint8_t offset_rej_b [8];
+ uint8_t debug [8];
+};
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE FUNCTIONS DECLARATION ---------------------------------------- */
+
+int load_firmware(uint8_t target, uint8_t *firmware, uint16_t size); /* defined in loragw_hal.c */
+
+uint8_t sx125x_cal(uint8_t cal_cmd, struct cal_res_s *cal_res);
+
+int read_capture(int16_t *i, int16_t *q, int nb_samp);
+
+uint8_t get_img_rej(int16_t *sig_i, int16_t *sig_q, int nb_samp, double f_sig_norm);
+
+void usage (void);
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE FUNCTIONS DEFINITION ----------------------------------------- */
+
+/* describe command line options */
+void usage(void) {
+ printf("Library version information: %s\n", lgw_version_info());
+ printf( "Available options:\n");
+ printf( " -h print this help\n");
+ printf( " -a <float> Radio A frequency in MHz\n");
+ printf( " -b <float> Radio B frequency in MHz\n");
+ printf( " -r <int> Radio type (SX1255:1255, SX1257:1257)\n");
+ printf( " -n <uint> Number of calibration iterations\n");
+ printf( " -k <int> Concentrator clock source (0:radio_A, 1:radio_B(default))\n");
+ printf( " -t <int> Radio to run TX calibration on (0:None(default), 1:radio_A, 2:radio_B, 3:both)\n");
+}
+
+/* -------------------------------------------------------------------------- */
+/* --- MAIN FUNCTION -------------------------------------------------------- */
+
+int main(int argc, char **argv)
+{
+ int i, j, x;
+ int32_t read_val;
+ struct lgw_conf_board_s boardconf;
+ struct lgw_conf_rxrf_s rfconf;
+ uint8_t fw_version;
+ uint8_t cal_cmd;
+ uint8_t cal_status;
+ struct cal_res_s cal_res [NB_CAL_MAX];
+ struct cal_res_s cal_res_max;
+ struct cal_res_s cal_res_min;
+ int16_t sig_i [RAM_SIZE];
+ int16_t sig_q [RAM_SIZE];
+ uint8_t img_rej_a [NB_CAL_MAX];
+ uint8_t img_rej_b [NB_CAL_MAX];
+ uint8_t img_rej_a_max;
+ uint8_t img_rej_a_min;
+ uint8_t img_rej_b_max;
+ uint8_t img_rej_b_min;
+ //FILE *file;
+
+ /* command line options */
+ int xi = 0;
+ double xd = 0.0;
+ uint32_t fa = 0, fb = 0;
+ enum lgw_radio_type_e radio_type = LGW_RADIO_TYPE_NONE;
+ uint8_t clocksource = 1; /* Radio B is source by default */
+ uint8_t tx_enable = 0;
+ int nb_cal = 5;
+
+ /* parse command line options */
+ while ((i = getopt (argc, argv, "ha:b:r:n:k:t:")) != -1) {
+ switch (i) {
+ case 'h':
+ usage();
+ return -1;
+ break;
+ case 'a': /* <float> Radio A frequency in MHz */
+ sscanf(optarg, "%lf", &xd);
+ fa = (uint32_t)((xd*1e6) + 0.5); /* .5 Hz offset to get rounding instead of truncating */
+ break;
+ case 'b': /* <float> Radio B frequency in MHz */
+ sscanf(optarg, "%lf", &xd);
+ fb = (uint32_t)((xd*1e6) + 0.5); /* .5 Hz offset to get rounding instead of truncating */
+ break;
+ case 'r': /* <int> Radio type (1255, 1257) */
+ sscanf(optarg, "%i", &xi);
+ switch (xi) {
+ case 1255:
+ radio_type = LGW_RADIO_TYPE_SX1255;
+ break;
+ case 1257:
+ radio_type = LGW_RADIO_TYPE_SX1257;
+ break;
+ default:
+ printf("ERROR: invalid radio type\n");
+ usage();
+ return -1;
+ }
+ break;
+ case 'n': /* <uint> Number of calibration iterations */
+ i = sscanf(optarg, "%i", &xi);
+ if ((i != 1) || (xi > NB_CAL_MAX)) {
+ printf("ERROR: invalid number of calibration iterations (MAX %d)\n",NB_CAL_MAX);
+ usage();
+ return -1;
+ } else {
+ nb_cal = xi;
+ }
+ break;
+ case 'k': /* <int> Concentrator clock source (Radio A or Radio B) */
+ sscanf(optarg, "%i", &xi);
+ clocksource = (uint8_t)xi;
+ break;
+ case 't': /* <int> Radio to run TX calibration on */
+ sscanf(optarg, "%i", &xi);
+ tx_enable = (uint8_t)xi;
+ break;
+ default:
+ printf("ERROR: argument parsing\n");
+ usage();
+ return -1;
+ }
+ }
+
+ /* check input parameters */
+ if ((fa == 0) || (fb == 0)) {
+ printf("ERROR: missing frequency input parameter:\n");
+ printf(" Radio A RX: %u\n", fa);
+ printf(" Radio B RX: %u\n", fb);
+ usage();
+ return -1;
+ }
+
+ if (radio_type == LGW_RADIO_TYPE_NONE) {
+ printf("ERROR: missing radio type parameter:\n");
+ usage();
+ return -1;
+ }
+
+ /* starting the concentrator */
+ /* board config */
+ memset(&boardconf, 0, sizeof(boardconf));
+
+ boardconf.lorawan_public = true;
+ boardconf.clksrc = clocksource;
+ lgw_board_setconf(boardconf);
+
+ /* RF config */
+ memset(&rfconf, 0, sizeof(rfconf));
+
+ rfconf.enable = true;
+ rfconf.freq_hz = fa;
+ rfconf.rssi_offset = DEFAULT_RSSI_OFFSET;
+ rfconf.type = radio_type;
+ rfconf.tx_enable = false; /* ignored */
+ lgw_rxrf_setconf(0, rfconf);
+
+ rfconf.freq_hz = fb;
+ rfconf.tx_enable = false; /* ignored */
+ lgw_rxrf_setconf(1, rfconf);
+
+ /* Calibration command */
+ cal_cmd = 0;
+ //cal_cmd |= 0x01; /* Bit 0: Calibrate Rx IQ mismatch compensation on radio A */
+ //cal_cmd |= 0x02; /* Bit 1: Calibrate Rx IQ mismatch compensation on radio B */
+ //cal_cmd |= 0x04; /* Bit 2: Calibrate Tx DC offset on radio A */
+ //cal_cmd |= 0x08; /* Bit 3: Calibrate Tx DC offset on radio B */
+ cal_cmd |= 0x10; /* Bit 4: 0: calibrate with DAC gain=2, 1: with DAC gain=3 (use 3) */
+
+ switch (radio_type) {
+ case LGW_RADIO_TYPE_SX1255:
+ cal_cmd |= 0x20; /* Bit 5: 0: SX1257, 1: SX1255 */
+ break;
+ case LGW_RADIO_TYPE_SX1257:
+ cal_cmd |= 0x00; /* Bit 5: 0: SX1257, 1: SX1255 */
+ break;
+ default:
+ break;
+ }
+
+ cal_cmd |= 0x00; /* Bit 6-7: Board type 0: ref, 1: FPGA, 3: board X */
+
+ /* Recap parameters*/
+ printf("Library version information: %s\n", lgw_version_info());
+ printf("Radio type: %d\n",radio_type);
+ printf("Radio A frequency: %f MHz\n",fa/1e6);
+ printf("Radio B frequency: %f MHz\n",fb/1e6);
+ printf("Number of calibration iterations: %d\n",nb_cal);
+ printf("Calibration command: brd: %d, chip: %d, dac: %d\n\n", cal_cmd >> 6, 1257-2*((cal_cmd & 0x20) >> 5), 2+((cal_cmd & 0x10) >> 4));
+
+ x = lgw_connect(false, DEFAULT_TX_NOTCH_FREQ);
+ if (x == -1) {
+ printf("ERROR: FAIL TO CONNECT BOARD\n");
+ return -1;
+ }
+
+ /* reset the registers (also shuts the radios down) */
+ lgw_soft_reset();
+
+ /* ungate clocks (gated by default) */
+ lgw_reg_w(LGW_GLOBAL_EN, 1);
+
+ /* switch on and reset the radios (also starts the 32 MHz XTAL) */
+ lgw_reg_w(LGW_RADIO_A_EN,1);
+ lgw_reg_w(LGW_RADIO_B_EN,1);
+ wait_ms(500); /* TODO: optimize */
+ lgw_reg_w(LGW_RADIO_RST,1);
+ wait_ms(5);
+ lgw_reg_w(LGW_RADIO_RST,0);
+
+ /* setup the radios */
+ lgw_setup_sx125x(0, clocksource, true, radio_type, fa);
+ lgw_setup_sx125x(1, clocksource, false, radio_type, fb);
+
+ /* Set GPIO 4 high for calibration */
+ lgw_reg_w(LGW_GPIO_MODE,31); /* Set all GPIOs as output */
+ lgw_reg_w(LGW_GPIO_SELECT_OUTPUT,2); /* AGC MCU drives GPIOs */
+
+ /* Load the calibration firmware */
+ load_firmware(MCU_AGC, cal_firmware, MCU_AGC_FW_BYTE);
+ lgw_reg_w(LGW_MCU_RST_1,0);
+ lgw_reg_w(LGW_DBG_AGC_MCU_RAM_ADDR, FW_VERSION_ADDR);
+ lgw_reg_r(LGW_DBG_AGC_MCU_RAM_DATA, &read_val);
+ fw_version = (uint8_t)read_val;
+ if (fw_version != FW_VERSION_CAL) {
+ printf("ERROR: Version of calibration firmware not expected, actual:%d expected:%d\n", fw_version, FW_VERSION_CAL);
+ return -1;
+ }
+
+ /* Run Rx A IQ mismatch calibration only */
+ for (i=0; i<nb_cal; i++) {
+ cal_status = sx125x_cal(cal_cmd | 0x01, &cal_res[i]);
+ x = read_capture(sig_i, sig_q, RAM_SIZE);
+ /*
+ file = fopen("toto.txt","w");
+ for (j=0; j<RAM_SIZE; j++) {
+ fprintf(file, "%d %d\n", sig_i[j], sig_q[j]);
+ }
+ fclose(file);
+ */
+ img_rej_a[i] = get_img_rej(sig_i, sig_q, RAM_SIZE, FREQ_SIG_NORM);
+
+ printf("Rx A IQ mismatch: Amp: %3d Phi: %3d Rej: %2d dB Status: %3d | Debug: Rej: %2d dB Lna: %1d BB: %2d Dec: %2d\n", cal_res[i].amp_a, cal_res[i].phi_a, cal_res[i].img_rej_a, cal_status, img_rej_a[i], cal_res[i].debug[0], cal_res[i].debug[1], cal_res[i].debug[2]);
+ }
+
+ /* Run Rx B IQ mismatch calibation only */
+ printf("\n");
+ for (i=0; i<nb_cal; i++) {
+ cal_status = sx125x_cal(cal_cmd | 0x02, &cal_res[i]);
+ x = read_capture(sig_i, sig_q, RAM_SIZE);
+ img_rej_b[i] = get_img_rej(sig_i, sig_q, RAM_SIZE, FREQ_SIG_NORM);
+
+ printf("Rx B IQ mismatch: Amp: %3d Phi: %3d Rej: %2d dB Status: %3d | Debug: Rej: %2d dB Lna: %1d BB: %2d Dec: %2d\n", cal_res[i].amp_b, cal_res[i].phi_b, cal_res[i].img_rej_b, cal_status, img_rej_b[i], cal_res[i].debug[0], cal_res[i].debug[1], cal_res[i].debug[2]);
+ }
+
+ /* Run Tx A DC offset calibation only */
+ printf("\n");
+ if ((tx_enable == 1) || (tx_enable == 3)) {
+ for (i=0; i<nb_cal; i++) {
+ cal_status = sx125x_cal(cal_cmd | 0x04, &cal_res[i]);
+
+ printf("Tx A DC offset I :");
+ for (j=0; j<8; j++) {
+ printf(" %3d", cal_res[i].offset_i_a[j]);
+ }
+ printf("\n");
+ printf("Tx A DC offset Q :");
+ for (j=0; j<8; j++) {
+ printf(" %3d", cal_res[i].offset_q_a[j]);
+ }
+ printf("\n");
+ printf("Tx A DC rejection:");
+ for (j=0; j<8; j++) {
+ printf(" %3d", cal_res[i].offset_rej_a[j]);
+ }
+ printf("\n");
+ printf("Tx A DC debug BB :");
+ for (j=0; j<8; j++) {
+ printf(" %3d", (cal_res[i].debug[j] & 0xF0) >> 4);
+ }
+ printf("\n");
+ printf("Tx A DC debug Dec:");
+ for (j=0; j<8; j++) {
+ printf(" %3d", cal_res[i].debug[j] & 0x0F);
+ }
+ printf("\n");
+ printf("Tx A DC Status : %3d\n", cal_status);
+ }
+ } else {
+ printf("Tx A calibration bypassed\n");
+ }
+
+ /* Run Tx B DC offset calibation only */
+ printf("\n");
+ if ((tx_enable == 2) || (tx_enable == 3)) {
+ for (i=0; i<nb_cal; i++) {
+ cal_status = sx125x_cal(cal_cmd | 0x08, &cal_res[i]);
+
+ printf("Tx B DC offset I :");
+ for (j=0; j<8; j++) {
+ printf(" %3d", cal_res[i].offset_i_b[j]);
+ }
+ printf("\n");
+ printf("Tx B DC offset Q :");
+ for (j=0; j<8; j++) {
+ printf(" %3d", cal_res[i].offset_q_b[j]);
+ }
+ printf("\n");
+ printf("Tx B DC rejection:");
+ for (j=0; j<8; j++) {
+ printf(" %3d", cal_res[i].offset_rej_b[j]);
+ }
+ printf("\n");
+ printf("Tx B DC debug BB :");
+ for (j=0; j<8; j++) {
+ printf(" %3d", (cal_res[i].debug[j] & 0xF0) >> 4);
+ }
+ printf("\n");
+ printf("Tx B DC debug Dec:");
+ for (j=0; j<8; j++) {
+ printf(" %3d", cal_res[i].debug[j] & 0x0F);
+ }
+ printf("\n");
+ printf("Tx B DC Status : %3d\n", cal_status);
+ }
+ } else {
+ printf("Tx B calibration bypassed\n");
+ }
+
+ /* Compute statistics */
+ cal_res_max.amp_a = -128;
+ cal_res_max.phi_a = -128;
+ cal_res_max.amp_b = -128;
+ cal_res_max.phi_b = -128;
+ cal_res_max.img_rej_a = 0;
+ cal_res_max.img_rej_b = 0;
+ for (j=0; j<8; j++) {
+ cal_res_max.offset_i_a[j] = -128;
+ cal_res_max.offset_q_a[j] = -128;
+ cal_res_max.offset_i_b[j] = -128;
+ cal_res_max.offset_q_b[j] = -128;
+ cal_res_max.offset_rej_a[j] = 0;
+ cal_res_max.offset_rej_b[j] = 0;
+ }
+
+ cal_res_min.amp_a = 127;
+ cal_res_min.phi_a = 127;
+ cal_res_min.amp_b = 127;
+ cal_res_min.phi_b = 127;
+ cal_res_min.img_rej_a = 255;
+ cal_res_min.img_rej_b = 255;
+ for (j=0; j<8; j++) {
+ cal_res_min.offset_i_a[j] = 127;
+ cal_res_min.offset_q_a[j] = 127;
+ cal_res_min.offset_i_b[j] = 127;
+ cal_res_min.offset_q_b[j] = 127;
+ cal_res_min.offset_rej_a[j] = 255;
+ cal_res_min.offset_rej_b[j] = 255;
+ }
+
+ img_rej_a_max = 0;
+ img_rej_a_min = 255;
+ img_rej_b_max = 0;
+ img_rej_b_min = 255;
+
+ for (i=0; i<nb_cal; i++) {
+ if (cal_res[i].amp_a > cal_res_max.amp_a) {
+ cal_res_max.amp_a = cal_res[i].amp_a;
+ }
+ if (cal_res[i].phi_a > cal_res_max.phi_a) {
+ cal_res_max.phi_a = cal_res[i].phi_a;
+ }
+ if (cal_res[i].amp_b > cal_res_max.amp_b) {
+ cal_res_max.amp_b = cal_res[i].amp_b;
+ }
+ if (cal_res[i].phi_b > cal_res_max.phi_b) {
+ cal_res_max.phi_b = cal_res[i].phi_b;
+ }
+ if (cal_res[i].phi_b > cal_res_max.phi_b) {
+ cal_res_max.phi_b = cal_res[i].phi_b;
+ }
+ if (cal_res[i].img_rej_a > cal_res_max.img_rej_a) {
+ cal_res_max.img_rej_a = cal_res[i].img_rej_a;
+ }
+ if (cal_res[i].img_rej_b > cal_res_max.img_rej_b) {
+ cal_res_max.img_rej_b = cal_res[i].img_rej_b;
+ }
+ for (j=0; j<8; j++) {
+ if (cal_res[i].offset_i_a[j] > cal_res_max.offset_i_a[j]) {
+ cal_res_max.offset_i_a[j] = cal_res[i].offset_i_a[j];
+ }
+ if (cal_res[i].offset_q_a[j] > cal_res_max.offset_q_a[j]) {
+ cal_res_max.offset_q_a[j] = cal_res[i].offset_q_a[j];
+ }
+ if (cal_res[i].offset_i_b[j] > cal_res_max.offset_i_b[j]) {
+ cal_res_max.offset_i_b[j] = cal_res[i].offset_i_b[j];
+ }
+ if (cal_res[i].offset_q_b[j] > cal_res_max.offset_q_b[j]) {
+ cal_res_max.offset_q_b[j] = cal_res[i].offset_q_b[j];
+ }
+ if (cal_res[i].offset_rej_a[j] > cal_res_max.offset_rej_a[j]) {
+ cal_res_max.offset_rej_a[j] = cal_res[i].offset_rej_a[j];
+ }
+ if (cal_res[i].offset_rej_b[j] > cal_res_max.offset_rej_b[j]) {
+ cal_res_max.offset_rej_b[j] = cal_res[i].offset_rej_b[j];
+ }
+ }
+
+ if (cal_res[i].amp_a < cal_res_min.amp_a) {
+ cal_res_min.amp_a = cal_res[i].amp_a;
+ }
+ if (cal_res[i].phi_a < cal_res_min.phi_a) {
+ cal_res_min.phi_a = cal_res[i].phi_a;
+ }
+ if (cal_res[i].amp_b < cal_res_min.amp_b) {
+ cal_res_min.amp_b = cal_res[i].amp_b;
+ }
+ if (cal_res[i].phi_b < cal_res_min.phi_b) {
+ cal_res_min.phi_b = cal_res[i].phi_b;
+ }
+ if (cal_res[i].phi_b < cal_res_min.phi_b) {
+ cal_res_min.phi_b = cal_res[i].phi_b;
+ }
+ if (cal_res[i].img_rej_a < cal_res_min.img_rej_a) {
+ cal_res_min.img_rej_a = cal_res[i].img_rej_a;
+ }
+ if (cal_res[i].img_rej_b < cal_res_min.img_rej_b) {
+ cal_res_min.img_rej_b = cal_res[i].img_rej_b;
+ }
+ for (j=0; j<8; j++) {
+ if (cal_res[i].offset_i_a[j] < cal_res_min.offset_i_a[j]) {
+ cal_res_min.offset_i_a[j] = cal_res[i].offset_i_a[j];
+ }
+ if (cal_res[i].offset_q_a[j] < cal_res_min.offset_q_a[j]) {
+ cal_res_min.offset_q_a[j] = cal_res[i].offset_q_a[j];
+ }
+ if (cal_res[i].offset_i_b[j] < cal_res_min.offset_i_b[j]) {
+ cal_res_min.offset_i_b[j] = cal_res[i].offset_i_b[j];
+ }
+ if (cal_res[i].offset_q_b[j] < cal_res_min.offset_q_b[j]) {
+ cal_res_min.offset_q_b[j] = cal_res[i].offset_q_b[j];
+ }
+ if (cal_res[i].offset_rej_a[j] < cal_res_min.offset_rej_a[j]) {
+ cal_res_min.offset_rej_a[j] = cal_res[i].offset_rej_a[j];
+ }
+ if (cal_res[i].offset_rej_b[j] < cal_res_min.offset_rej_b[j]) {
+ cal_res_min.offset_rej_b[j] = cal_res[i].offset_rej_b[j];
+ }
+ }
+
+ if (img_rej_a[i] > img_rej_a_max) {
+ img_rej_a_max = img_rej_a[i];
+ }
+ if (img_rej_a[i] < img_rej_a_min) {
+ img_rej_a_min = img_rej_a[i];
+ }
+ if (img_rej_b[i] > img_rej_b_max) {
+ img_rej_b_max = img_rej_b[i];
+ }
+ if (img_rej_b[i] < img_rej_b_min) {
+ img_rej_b_min = img_rej_b[i];
+ }
+ }
+
+ /* Print statistics */
+ printf("\n");
+ printf("Rx A IQ mismatch calibration statistics on %3d iterations (min, max):\n", nb_cal);
+ printf("Amp: %3d %3d Phi: %3d %3d Rej: %2d %2d dB (capt.: %2d %2d dB)\n", cal_res_min.amp_a, cal_res_max.amp_a, cal_res_min.phi_a, cal_res_max.phi_a, cal_res_min.img_rej_a, cal_res_max.img_rej_a, img_rej_a_min, img_rej_a_max);
+
+ printf("\n");
+ printf("Rx B IQ mismatch calibration statistics on %3d iterations (min, max):\n", nb_cal);
+ printf("Amp: %3d %3d Phi: %3d %3d Rej: %2d %2d dB (capt.: %2d %2d dB)\n", cal_res_min.amp_b, cal_res_max.amp_b, cal_res_min.phi_b, cal_res_max.phi_b, cal_res_min.img_rej_b, cal_res_max.img_rej_b, img_rej_b_min, img_rej_b_max);
+
+ if ((tx_enable == 1) || (tx_enable == 3)) {
+ printf("\n");
+ printf("Tx A DC offset calibration statistics on %3d iterations (min, max):\n", nb_cal);
+ for (j=0; j<8; j++) {
+ printf(" Mix gain %2d: I: %3d %3d Q: %3d %3d Rej: %2d %2d dB\n", 8+j, cal_res_min.offset_i_a[j], cal_res_max.offset_i_a[j], cal_res_min.offset_q_a[j], cal_res_max.offset_q_a[j], cal_res_min.offset_rej_a[j], cal_res_max.offset_rej_a[j]);
+ }
+ }
+
+ if ((tx_enable == 2) || (tx_enable == 3)) {
+ printf("\n");
+ printf("Tx B DC offset calibration statistics on %3d iterations (min, max):\n", nb_cal);
+ for (j=0; j<8; j++) {
+ printf(" Mix gain %2d: I: %3d %3d Q: %3d %3d Rej: %2d %2d dB\n", 8+j, cal_res_min.offset_i_b[j], cal_res_max.offset_i_b[j], cal_res_min.offset_q_b[j], cal_res_max.offset_q_b[j], cal_res_min.offset_rej_b[j], cal_res_max.offset_rej_b[j]);
+ }
+ }
+
+ lgw_stop();
+
+ printf("\nEnd of radio calibration test\n");
+
+ return 0;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+uint8_t sx125x_cal(uint8_t cal_cmd, struct cal_res_s *cal_res) {
+
+ int i;
+ int32_t read_val;
+ uint8_t cal_status;
+
+ lgw_reg_w(LGW_FORCE_HOST_RADIO_CTRL,0); /* gives to AGC MCU the control of the radios */
+ lgw_reg_w(LGW_RADIO_SELECT,cal_cmd); /* send calibration configuration word */
+ lgw_reg_w(LGW_MCU_RST_1,1);
+ lgw_reg_w(LGW_MCU_RST_1,0);
+ lgw_reg_w(LGW_PAGE_REG,3); /* Calibration will start on this condition as soon as MCU can talk to concentrator registers */
+ lgw_reg_w(LGW_EMERGENCY_FORCE_HOST_CTRL,0); /* Give control of concentrator registers to MCU */
+
+ wait_ms(2000); /* Wait for end of calibration */
+
+ lgw_reg_w(LGW_EMERGENCY_FORCE_HOST_CTRL,1); /* Take back control */
+
+ /* Get calibration status */
+ lgw_reg_r(LGW_MCU_AGC_STATUS, &read_val);
+ cal_status = (uint8_t)read_val;
+
+ /* Check calibration flags
+ bit 0: could access SX1301 registers
+ bit 1: could access radio A registers
+ bit 2: could access radio B registers
+ bit 3: radio A RX image rejection successful
+ bit 4: radio B RX image rejection successful
+ bit 5: radio A TX imbalance correction successful
+ bit 6: radio B TX imbalance correction successful
+ bit 7: calibration finished */
+
+ if ((cal_status & 0x01) == 0) {
+ printf("WARNING: calibration could not access SX1301 registers\n");
+ }
+ if ((cal_status & 0x02) == 0) {
+ printf("WARNING: calibration could not access radio A\n");
+ }
+ if ((cal_status & 0x04) == 0) {
+ printf("WARNING: calibration could not access radio B\n");
+ }
+ if ((cal_cmd & 0x01) && ((cal_status & 0x08) == 0)) {
+ printf("WARNING: problem in calibration of radio A for image rejection\n");
+ }
+ if ((cal_cmd & 0x02) && ((cal_status & 0x10) == 0)) {
+ printf("WARNING: problem in calibration of radio B for image rejection\n");
+ }
+ if ((cal_cmd & 0x04) && ((cal_status & 0x20) == 0)) {
+ printf("WARNING: problem in calibration of radio A for TX imbalance\n");
+ }
+ if ((cal_cmd & 0x08) && ((cal_status & 0x40) == 0)) {
+ printf("WARNING: problem in calibration of radio B for TX imbalance\n");
+ }
+ if ((cal_status & 0x80) == 0) {
+ printf("WARNING: Calibration not finished\n");
+ }
+
+ /* Get calibration results */
+ if (cal_cmd & 0x01) {
+ lgw_reg_r(LGW_IQ_MISMATCH_A_AMP_COEFF, &read_val);
+ (*cal_res).amp_a = (int8_t)((read_val > 31) ? read_val - 64 : read_val);
+ lgw_reg_r(LGW_IQ_MISMATCH_A_PHI_COEFF, &read_val);
+ (*cal_res).phi_a = (int8_t)((read_val > 31) ? read_val - 64 : read_val);
+ lgw_reg_w(LGW_DBG_AGC_MCU_RAM_ADDR, 0xD0);
+ lgw_reg_r(LGW_DBG_AGC_MCU_RAM_DATA, &read_val);
+ (*cal_res).img_rej_a = (uint8_t)read_val;
+ lgw_reg_w(LGW_DBG_AGC_MCU_RAM_ADDR, 0xD2);
+ lgw_reg_r(LGW_DBG_AGC_MCU_RAM_DATA, &read_val);
+ (*cal_res).debug[0] = (uint8_t)read_val;
+ lgw_reg_w(LGW_DBG_AGC_MCU_RAM_ADDR, 0xD3);
+ lgw_reg_r(LGW_DBG_AGC_MCU_RAM_DATA, &read_val);
+ (*cal_res).debug[1] = (uint8_t)read_val;
+ lgw_reg_w(LGW_DBG_AGC_MCU_RAM_ADDR, 0xD4);
+ lgw_reg_r(LGW_DBG_AGC_MCU_RAM_DATA, &read_val);
+ (*cal_res).debug[2] = (uint8_t)read_val;
+ }
+ if (cal_cmd & 0x02) {
+ lgw_reg_r(LGW_IQ_MISMATCH_B_AMP_COEFF, &read_val);
+ (*cal_res).amp_b = (int8_t)((read_val > 31) ? read_val - 64 : read_val);
+ lgw_reg_r(LGW_IQ_MISMATCH_B_PHI_COEFF, &read_val);
+ (*cal_res).phi_b = (int8_t)((read_val > 31) ? read_val - 64 : read_val);
+ lgw_reg_w(LGW_DBG_AGC_MCU_RAM_ADDR, 0xD1);
+ lgw_reg_r(LGW_DBG_AGC_MCU_RAM_DATA, &read_val);
+ (*cal_res).img_rej_b = (uint8_t)read_val;
+ lgw_reg_w(LGW_DBG_AGC_MCU_RAM_ADDR, 0xD2);
+ lgw_reg_r(LGW_DBG_AGC_MCU_RAM_DATA, &read_val);
+ (*cal_res).debug[0] = (uint8_t)read_val;
+ lgw_reg_w(LGW_DBG_AGC_MCU_RAM_ADDR, 0xD3);
+ lgw_reg_r(LGW_DBG_AGC_MCU_RAM_DATA, &read_val);
+ (*cal_res).debug[1] = (uint8_t)read_val;
+ lgw_reg_w(LGW_DBG_AGC_MCU_RAM_ADDR, 0xD4);
+ lgw_reg_r(LGW_DBG_AGC_MCU_RAM_DATA, &read_val);
+ (*cal_res).debug[2] = (uint8_t)read_val;
+ }
+ if (cal_cmd & 0x04) {
+ for (i=0; i<=7; ++i) {
+ lgw_reg_w(LGW_DBG_AGC_MCU_RAM_ADDR, 0xA0+i);
+ lgw_reg_r(LGW_DBG_AGC_MCU_RAM_DATA, &read_val);
+ (*cal_res).offset_i_a[i] = (int8_t)read_val;
+ lgw_reg_w(LGW_DBG_AGC_MCU_RAM_ADDR, 0xA8+i);
+ lgw_reg_r(LGW_DBG_AGC_MCU_RAM_DATA, &read_val);
+ (*cal_res).offset_q_a[i] = (int8_t)read_val;
+ lgw_reg_w(LGW_DBG_AGC_MCU_RAM_ADDR, 0xC0+i);
+ lgw_reg_r(LGW_DBG_AGC_MCU_RAM_DATA, &read_val);
+ (*cal_res).offset_rej_a[i] = (uint8_t)read_val;
+ lgw_reg_w(LGW_DBG_AGC_MCU_RAM_ADDR, 0xD2+i);
+ lgw_reg_r(LGW_DBG_AGC_MCU_RAM_DATA, &read_val);
+ (*cal_res).debug[i] = (uint8_t)read_val;
+ }
+ }
+ if (cal_cmd & 0x08) {
+ for (i=0; i<=7; ++i) {
+ lgw_reg_w(LGW_DBG_AGC_MCU_RAM_ADDR, 0xB0+i);
+ lgw_reg_r(LGW_DBG_AGC_MCU_RAM_DATA, &read_val);
+ (*cal_res).offset_i_b[i] = (int8_t)read_val;
+ lgw_reg_w(LGW_DBG_AGC_MCU_RAM_ADDR, 0xB8+i);
+ lgw_reg_r(LGW_DBG_AGC_MCU_RAM_DATA, &read_val);
+ (*cal_res).offset_q_b[i] = (int8_t)read_val;
+ lgw_reg_w(LGW_DBG_AGC_MCU_RAM_ADDR, 0xC8+i);
+ lgw_reg_r(LGW_DBG_AGC_MCU_RAM_DATA, &read_val);
+ (*cal_res).offset_rej_b[i] = (uint8_t)read_val;
+ lgw_reg_w(LGW_DBG_AGC_MCU_RAM_ADDR, 0xD2+i);
+ lgw_reg_r(LGW_DBG_AGC_MCU_RAM_DATA, &read_val);
+ (*cal_res).debug[i] = (uint8_t)read_val;
+ }
+ }
+
+ return cal_status;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int read_capture(int16_t *sig_i, int16_t *sig_q, int nb_samp) {
+
+ uint8_t read_burst[4];
+ uint16_t data_i_c2;
+ uint16_t data_q_c2;
+ int i;
+
+ lgw_reg_w(LGW_CAPTURE_RAM_ADDR, 0);
+ for (i=0 ; i<nb_samp ; i++) {
+ lgw_reg_rb(LGW_CAPTURE_RAM_DATA, read_burst, 4);
+ data_i_c2 = ((uint16_t)read_burst[3] << 4) + ((uint16_t)read_burst[2] >> 4);
+ data_q_c2 = ((uint16_t)read_burst[1] << 4) + ((uint16_t)read_burst[0] >> 4);
+ sig_i[i] = (int16_t)((data_i_c2 > 2047) ? data_i_c2 - 4096 : data_i_c2);
+ sig_q[i] = (int16_t)((data_q_c2 > 2047) ? data_q_c2 - 4096 : data_q_c2);
+ }
+
+ return 0;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+uint8_t get_img_rej(int16_t *sig_i, int16_t *sig_q, int nb_samp, double f_sig_norm) {
+
+ int i;
+ double phase;
+ double corr_sig_i, corr_sig_q, corr_sig_abs;
+ double corr_img_i, corr_img_q, corr_img_abs;
+ double img_rej;
+
+ corr_sig_i = 0;
+ corr_sig_q = 0;
+ corr_img_i = 0;
+ corr_img_q = 0;
+
+ for (i=0 ; i<nb_samp ; i++) {
+ phase = 6.28318530717959*i*f_sig_norm;
+ corr_sig_i += (double)sig_i[i]*cos( phase) - (double)sig_q[i]*sin( phase);
+ corr_sig_q += (double)sig_q[i]*cos( phase) + (double)sig_i[i]*sin( phase);
+ corr_img_i += (double)sig_i[i]*cos(-phase) - (double)sig_q[i]*sin(-phase);
+ corr_img_q += (double)sig_q[i]*cos(-phase) + (double)sig_i[i]*sin(-phase);
+ }
+
+ corr_sig_abs = sqrt( corr_sig_i*corr_sig_i + corr_sig_q*corr_sig_q );
+ corr_img_abs = sqrt( corr_img_i*corr_img_i + corr_img_q*corr_img_q );
+
+ img_rej = 20*log10(corr_sig_abs/corr_img_abs);
+
+ return (uint8_t)img_rej;
+}
+
+
+/* --- EOF ------------------------------------------------------------------ */
diff --git a/libloragw/tst/test_loragw_gps.c b/libloragw/tst/test_loragw_gps.c
new file mode 100644
index 0000000..a4164a3
--- /dev/null
+++ b/libloragw/tst/test_loragw_gps.c
@@ -0,0 +1,288 @@
+/*
+ / _____) _ | |
+( (____ _____ ____ _| |_ _____ ____| |__
+ \____ \| ___ | (_ _) ___ |/ ___) _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+ (C)2013 Semtech-Cycleo
+
+Description:
+ Minimum test program for the loragw_gps 'library'
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+Maintainer: Michael Coracin
+*/
+
+
+/* -------------------------------------------------------------------------- */
+/* --- DEPENDANCIES --------------------------------------------------------- */
+
+/* fix an issue between POSIX and C99 */
+#if __STDC_VERSION__ >= 199901L
+ #define _XOPEN_SOURCE 600
+#else
+ #define _XOPEN_SOURCE 500
+#endif
+
+#include <stdint.h> /* C99 types */
+#include <stdbool.h> /* bool type */
+#include <stdio.h> /* printf */
+#include <string.h> /* memset */
+#include <signal.h> /* sigaction */
+#include <stdlib.h> /* exit */
+#include <unistd.h> /* read */
+
+#include "loragw_hal.h"
+#include "loragw_gps.h"
+#include "loragw_aux.h"
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE VARIABLES ---------------------------------------------------- */
+
+static int exit_sig = 0; /* 1 -> application terminates cleanly (shut down hardware, close open files, etc) */
+static int quit_sig = 0; /* 1 -> application terminates without shutting down the hardware */
+
+struct tref ppm_ref;
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE FUNCTIONS DECLARATION ---------------------------------------- */
+
+static void sig_handler(int sigio);
+static void gps_process_sync(void);
+static void gps_process_coords(void);
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE FUNCTIONS DEFINITION ----------------------------------------- */
+
+static void sig_handler(int sigio) {
+ if (sigio == SIGQUIT) {
+ quit_sig = 1;;
+ } else if ((sigio == SIGINT) || (sigio == SIGTERM)) {
+ exit_sig = 1;
+ }
+}
+
+static void gps_process_sync(void) {
+ /* variables for PPM pulse GPS synchronization */
+ uint32_t ppm_tstamp;
+ struct timespec ppm_gps;
+ struct timespec ppm_utc;
+
+ /* variables for timestamp <-> GPS time conversions */
+ uint32_t x, z;
+ struct timespec y;
+
+ /* get GPS time for synchronization */
+ int i = lgw_gps_get(&ppm_utc, &ppm_gps, NULL, NULL);
+ if (i != LGW_GPS_SUCCESS) {
+ printf(" No valid reference GPS time available, synchronization impossible.\n");
+ return;
+ }
+
+ /* get timestamp for synchronization */
+ i = lgw_get_trigcnt(&ppm_tstamp);
+ if (i != LGW_HAL_SUCCESS) {
+ printf(" Failed to read timestamp, synchronization impossible.\n");
+ return;
+ }
+
+ /* try to update synchronize time reference with the new GPS & timestamp */
+ i = lgw_gps_sync(&ppm_ref, ppm_tstamp, ppm_utc, ppm_gps);
+ if (i != LGW_GPS_SUCCESS) {
+ printf(" Synchronization error.\n");
+ return;
+ }
+
+ /* display result */
+ printf(" * Synchronization successful *\n");
+ printf(" UTC reference time: %lld.%09ld\n", (long long)ppm_ref.utc.tv_sec, ppm_ref.utc.tv_nsec);
+ printf(" GPS reference time: %lld.%09ld\n", (long long)ppm_ref.gps.tv_sec, ppm_ref.gps.tv_nsec);
+ printf(" Internal counter reference value: %u\n", ppm_ref.count_us);
+ printf(" Clock error: %.9f\n", ppm_ref.xtal_err);
+
+ x = ppm_tstamp + 500000;
+ printf(" * Test of timestamp counter <-> GPS value conversion *\n");
+ printf(" Test value: %u\n", x);
+ lgw_cnt2gps(ppm_ref, x, &y);
+ printf(" Conversion to GPS: %lld.%09ld\n", (long long)y.tv_sec, y.tv_nsec);
+ lgw_gps2cnt(ppm_ref, y, &z);
+ printf(" Converted back: %u ==> %dµs\n", z, (int32_t)(z-x));
+ printf(" * Test of timestamp counter <-> UTC value conversion *\n");
+ printf(" Test value: %u\n", x);
+ lgw_cnt2utc(ppm_ref, x, &y);
+ printf(" Conversion to UTC: %lld.%09ld\n", (long long)y.tv_sec, y.tv_nsec);
+ lgw_utc2cnt(ppm_ref, y, &z);
+ printf(" Converted back: %u ==> %dµs\n", z, (int32_t)(z-x));
+}
+
+static void gps_process_coords(void) {
+ /* position variable */
+ struct coord_s coord;
+ struct coord_s gpserr;
+ int i = lgw_gps_get(NULL, NULL, &coord, &gpserr);
+
+ /* update gateway coordinates */
+ if (i == LGW_GPS_SUCCESS) {
+ printf("# GPS coordinates: latitude %.5f, longitude %.5f, altitude %i m\n", coord.lat, coord.lon, coord.alt);
+ printf("# GPS err: latitude %.5f, longitude %.5f, altitude %i m\n", gpserr.lat, gpserr.lon, gpserr.alt);
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+/* --- MAIN FUNCTION -------------------------------------------------------- */
+
+int main()
+{
+ struct sigaction sigact; /* SIGQUIT&SIGINT&SIGTERM signal handling */
+
+ int i;
+
+ /* concentrator variables */
+ struct lgw_conf_board_s boardconf;
+ struct lgw_conf_rxrf_s rfconf;
+
+ /* serial variables */
+ char serial_buff[128]; /* buffer to receive GPS data */
+ size_t wr_idx = 0; /* pointer to end of chars in buffer */
+ int gps_tty_dev; /* file descriptor to the serial port of the GNSS module */
+
+ /* NMEA/UBX variables */
+ enum gps_msg latest_msg; /* keep track of latest NMEA/UBX message parsed */
+
+ /* configure signal handling */
+ sigemptyset(&sigact.sa_mask);
+ sigact.sa_flags = 0;
+ sigact.sa_handler = sig_handler;
+ sigaction(SIGQUIT, &sigact, NULL);
+ sigaction(SIGINT, &sigact, NULL);
+ sigaction(SIGTERM, &sigact, NULL);
+
+ /* Intro message and library information */
+ printf("Beginning of test for loragw_gps.c\n");
+ printf("*** Library version information ***\n%s\n***\n", lgw_version_info());
+
+ /* Open and configure GPS */
+ i = lgw_gps_enable("/dev/ttyAMA0", "ubx7", 0, &gps_tty_dev);
+ if (i != LGW_GPS_SUCCESS) {
+ printf("ERROR: IMPOSSIBLE TO ENABLE GPS\n");
+ exit(EXIT_FAILURE);
+ }
+
+ /* start concentrator (default conf for IoT SK) */
+ /* board config */
+ memset(&boardconf, 0, sizeof(boardconf));
+ boardconf.lorawan_public = true;
+ boardconf.clksrc = 1;
+ lgw_board_setconf(boardconf);
+
+ /* RF config */
+ memset(&rfconf, 0, sizeof(rfconf));
+ rfconf.enable = true;
+ rfconf.freq_hz = 868000000;
+ rfconf.rssi_offset = 0.0;
+ rfconf.type = LGW_RADIO_TYPE_SX1257;
+ rfconf.tx_enable = true;
+ lgw_rxrf_setconf(0, rfconf);
+
+ lgw_start();
+
+ /* initialize some variables before loop */
+ memset(serial_buff, 0, sizeof serial_buff);
+ memset(&ppm_ref, 0, sizeof ppm_ref);
+
+ /* loop until user action */
+ while ((quit_sig != 1) && (exit_sig != 1)) {
+ size_t rd_idx = 0;
+ size_t frame_end_idx = 0;
+
+ /* blocking non-canonical read on serial port */
+ ssize_t nb_char = read(gps_tty_dev, serial_buff + wr_idx, LGW_GPS_MIN_MSG_SIZE);
+ if (nb_char <= 0) {
+ printf("WARNING: [gps] read() returned value %d\n", nb_char);
+ continue;
+ }
+ wr_idx += (size_t)nb_char;
+
+ /*******************************************
+ * Scan buffer for UBX/NMEA sync chars and *
+ * attempt to decode frame if one is found *
+ *******************************************/
+ while (rd_idx < wr_idx) {
+ size_t frame_size = 0;
+
+ /* Scan buffer for UBX sync char */
+ if (serial_buff[rd_idx] == LGW_GPS_UBX_SYNC_CHAR) {
+
+ /***********************
+ * Found UBX sync char *
+ ***********************/
+ latest_msg = lgw_parse_ubx(&serial_buff[rd_idx], (wr_idx - rd_idx), &frame_size);
+
+ if (frame_size > 0) {
+ if (latest_msg == INCOMPLETE) {
+ /* UBX header found but frame appears to be missing bytes */
+ frame_size = 0;
+ } else if (latest_msg == INVALID) {
+ /* message header received but message appears to be corrupted */
+ printf("WARNING: [gps] could not get a valid message from GPS (no time)\n");
+ frame_size = 0;
+ } else if (latest_msg == UBX_NAV_TIMEGPS) {
+ printf("\n~~ UBX NAV-TIMEGPS sentence, triggering synchronization attempt ~~\n");
+ gps_process_sync();
+ }
+ }
+ } else if(serial_buff[rd_idx] == LGW_GPS_NMEA_SYNC_CHAR) {
+ /************************
+ * Found NMEA sync char *
+ ************************/
+ /* scan for NMEA end marker (LF = 0x0a) */
+ char* nmea_end_ptr = memchr(&serial_buff[rd_idx],(int)0x0a, (wr_idx - rd_idx));
+
+ if (nmea_end_ptr) {
+ /* found end marker */
+ frame_size = nmea_end_ptr - &serial_buff[rd_idx] + 1;
+ latest_msg = lgw_parse_nmea(&serial_buff[rd_idx], frame_size);
+
+ if(latest_msg == INVALID || latest_msg == UNKNOWN) {
+ /* checksum failed */
+ frame_size = 0;
+ } else if (latest_msg == NMEA_RMC) { /* Get location from RMC frames */
+ gps_process_coords();
+ }
+ }
+ }
+
+ if (frame_size > 0) {
+ /* At this point message is a checksum verified frame
+ we're processed or ignored. Remove frame from buffer */
+ rd_idx += frame_size;
+ frame_end_idx = rd_idx;
+ } else {
+ rd_idx++;
+ }
+ } /* ...for(rd_idx = 0... */
+
+ if (frame_end_idx) {
+ /* Frames have been processed. Remove bytes to end of last processed frame */
+ memcpy(serial_buff,&serial_buff[frame_end_idx],wr_idx - frame_end_idx);
+ wr_idx -= frame_end_idx;
+ } /* ...for(rd_idx = 0... */
+
+ /* Prevent buffer overflow */
+ if ((sizeof(serial_buff) - wr_idx) < LGW_GPS_MIN_MSG_SIZE) {
+ memcpy(serial_buff,&serial_buff[LGW_GPS_MIN_MSG_SIZE],wr_idx - LGW_GPS_MIN_MSG_SIZE);
+ wr_idx -= LGW_GPS_MIN_MSG_SIZE;
+ }
+ }
+
+ /* clean up before leaving */
+ if (exit_sig == 1) {
+ lgw_gps_disable(gps_tty_dev);
+ lgw_stop();
+ }
+
+ printf("\nEnd of test for loragw_gps.c\n");
+ exit(EXIT_SUCCESS);
+}
+
+/* --- EOF ------------------------------------------------------------------ */
diff --git a/libloragw/tst/test_loragw_hal.c b/libloragw/tst/test_loragw_hal.c
new file mode 100644
index 0000000..e2fee5e
--- /dev/null
+++ b/libloragw/tst/test_loragw_hal.c
@@ -0,0 +1,416 @@
+/*
+ / _____) _ | |
+( (____ _____ ____ _| |_ _____ ____| |__
+ \____ \| ___ | (_ _) ___ |/ ___) _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+ (C)2013 Semtech-Cycleo
+
+Description:
+ Minimum test program for the loragw_hal 'library'
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+Maintainer: Sylvain Miermont
+*/
+
+
+/* -------------------------------------------------------------------------- */
+/* --- DEPENDANCIES --------------------------------------------------------- */
+
+/* fix an issue between POSIX and C99 */
+#if __STDC_VERSION__ >= 199901L
+ #define _XOPEN_SOURCE 600
+#else
+ #define _XOPEN_SOURCE 500
+#endif
+
+#include <stdint.h> /* C99 types */
+#include <stdbool.h> /* bool type */
+#include <stdio.h> /* printf */
+#include <string.h> /* memset */
+#include <signal.h> /* sigaction */
+#include <unistd.h> /* getopt access */
+
+#include "loragw_hal.h"
+#include "loragw_reg.h"
+#include "loragw_aux.h"
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE MACROS ------------------------------------------------------- */
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE CONSTANTS ---------------------------------------------------- */
+
+#define DEFAULT_RSSI_OFFSET 0.0
+#define DEFAULT_NOTCH_FREQ 129000U
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE VARIABLES ---------------------------------------------------- */
+
+static int exit_sig = 0; /* 1 -> application terminates cleanly (shut down hardware, close open files, etc) */
+static int quit_sig = 0; /* 1 -> application terminates without shutting down the hardware */
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE FUNCTIONS DECLARATION ---------------------------------------- */
+
+static void sig_handler(int sigio);
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE FUNCTIONS DEFINITION ----------------------------------------- */
+
+static void sig_handler(int sigio) {
+ if (sigio == SIGQUIT) {
+ quit_sig = 1;;
+ } else if ((sigio == SIGINT) || (sigio == SIGTERM)) {
+ exit_sig = 1;
+ }
+}
+
+/* describe command line options */
+void usage(void) {
+ printf("Library version information: %s\n", lgw_version_info());
+ printf( "Available options:\n");
+ printf( " -h print this help\n");
+ printf( " -a <float> Radio A RX frequency in MHz\n");
+ printf( " -b <float> Radio B RX frequency in MHz\n");
+ printf( " -t <float> Radio TX frequency in MHz\n");
+ printf( " -r <int> Radio type (SX1255:1255, SX1257:1257)\n");
+ printf( " -k <int> Concentrator clock source (0: radio_A, 1: radio_B(default))\n");
+}
+
+/* -------------------------------------------------------------------------- */
+/* --- MAIN FUNCTION -------------------------------------------------------- */
+
+int main(int argc, char **argv)
+{
+ struct sigaction sigact; /* SIGQUIT&SIGINT&SIGTERM signal handling */
+
+ struct lgw_conf_board_s boardconf;
+ struct lgw_conf_rxrf_s rfconf;
+ struct lgw_conf_rxif_s ifconf;
+
+ struct lgw_pkt_rx_s rxpkt[4]; /* array containing up to 4 inbound packets metadata */
+ struct lgw_pkt_tx_s txpkt; /* configuration and metadata for an outbound packet */
+ struct lgw_pkt_rx_s *p; /* pointer on a RX packet */
+
+ int i, j;
+ int nb_pkt;
+ uint32_t fa = 0, fb = 0, ft = 0;
+ enum lgw_radio_type_e radio_type = LGW_RADIO_TYPE_NONE;
+ uint8_t clocksource = 1; /* Radio B is source by default */
+
+ uint32_t tx_cnt = 0;
+ unsigned long loop_cnt = 0;
+ uint8_t status_var = 0;
+ double xd = 0.0;
+ int xi = 0;
+
+ /* parse command line options */
+ while ((i = getopt (argc, argv, "ha:b:t:r:k:")) != -1) {
+ switch (i) {
+ case 'h':
+ usage();
+ return -1;
+ break;
+ case 'a': /* <float> Radio A RX frequency in MHz */
+ sscanf(optarg, "%lf", &xd);
+ fa = (uint32_t)((xd*1e6) + 0.5); /* .5 Hz offset to get rounding instead of truncating */
+ break;
+ case 'b': /* <float> Radio B RX frequency in MHz */
+ sscanf(optarg, "%lf", &xd);
+ fb = (uint32_t)((xd*1e6) + 0.5); /* .5 Hz offset to get rounding instead of truncating */
+ break;
+ case 't': /* <float> Radio TX frequency in MHz */
+ sscanf(optarg, "%lf", &xd);
+ ft = (uint32_t)((xd*1e6) + 0.5); /* .5 Hz offset to get rounding instead of truncating */
+ break;
+ case 'r': /* <int> Radio type (1255, 1257) */
+ sscanf(optarg, "%i", &xi);
+ switch (xi) {
+ case 1255:
+ radio_type = LGW_RADIO_TYPE_SX1255;
+ break;
+ case 1257:
+ radio_type = LGW_RADIO_TYPE_SX1257;
+ break;
+ default:
+ printf("ERROR: invalid radio type\n");
+ usage();
+ return -1;
+ }
+ break;
+ case 'k': /* <int> Concentrator clock source (Radio A or Radio B) */
+ sscanf(optarg, "%i", &xi);
+ clocksource = (uint8_t)xi;
+ break;
+ default:
+ printf("ERROR: argument parsing\n");
+ usage();
+ return -1;
+ }
+ }
+
+ /* check input parameters */
+ if ((fa == 0) || (fb == 0) || (ft == 0)) {
+ printf("ERROR: missing frequency input parameter:\n");
+ printf(" Radio A RX: %u\n", fa);
+ printf(" Radio B RX: %u\n", fb);
+ printf(" Radio TX: %u\n", ft);
+ usage();
+ return -1;
+ }
+
+ if (radio_type == LGW_RADIO_TYPE_NONE) {
+ printf("ERROR: missing radio type parameter:\n");
+ usage();
+ return -1;
+ }
+
+ /* configure signal handling */
+ sigemptyset(&sigact.sa_mask);
+ sigact.sa_flags = 0;
+ sigact.sa_handler = sig_handler;
+ sigaction(SIGQUIT, &sigact, NULL);
+ sigaction(SIGINT, &sigact, NULL);
+ sigaction(SIGTERM, &sigact, NULL);
+
+ /* beginning of LoRa concentrator-specific code */
+ printf("Beginning of test for loragw_hal.c\n");
+
+ printf("*** Library version information ***\n%s\n\n", lgw_version_info());
+
+ /* set configuration for board */
+ memset(&boardconf, 0, sizeof(boardconf));
+
+ boardconf.lorawan_public = true;
+ boardconf.clksrc = clocksource;
+ lgw_board_setconf(boardconf);
+
+ /* set configuration for RF chains */
+ memset(&rfconf, 0, sizeof(rfconf));
+
+ rfconf.enable = true;
+ rfconf.freq_hz = fa;
+ rfconf.rssi_offset = DEFAULT_RSSI_OFFSET;
+ rfconf.type = radio_type;
+ rfconf.tx_enable = true;
+ rfconf.tx_notch_freq = DEFAULT_NOTCH_FREQ;
+ lgw_rxrf_setconf(0, rfconf); /* radio A, f0 */
+
+ rfconf.enable = true;
+ rfconf.freq_hz = fb;
+ rfconf.rssi_offset = DEFAULT_RSSI_OFFSET;
+ rfconf.type = radio_type;
+ rfconf.tx_enable = false;
+ lgw_rxrf_setconf(1, rfconf); /* radio B, f1 */
+
+ /* set configuration for LoRa multi-SF channels (bandwidth cannot be set) */
+ memset(&ifconf, 0, sizeof(ifconf));
+
+ ifconf.enable = true;
+ ifconf.rf_chain = 1;
+ ifconf.freq_hz = -400000;
+ ifconf.datarate = DR_LORA_MULTI;
+ lgw_rxif_setconf(0, ifconf); /* chain 0: LoRa 125kHz, all SF, on f1 - 0.4 MHz */
+
+ ifconf.enable = true;
+ ifconf.rf_chain = 1;
+ ifconf.freq_hz = -200000;
+ ifconf.datarate = DR_LORA_MULTI;
+ lgw_rxif_setconf(1, ifconf); /* chain 1: LoRa 125kHz, all SF, on f1 - 0.2 MHz */
+
+ ifconf.enable = true;
+ ifconf.rf_chain = 1;
+ ifconf.freq_hz = 0;
+ ifconf.datarate = DR_LORA_MULTI;
+ lgw_rxif_setconf(2, ifconf); /* chain 2: LoRa 125kHz, all SF, on f1 - 0.0 MHz */
+
+ ifconf.enable = true;
+ ifconf.rf_chain = 0;
+ ifconf.freq_hz = -400000;
+ ifconf.datarate = DR_LORA_MULTI;
+ lgw_rxif_setconf(3, ifconf); /* chain 3: LoRa 125kHz, all SF, on f0 - 0.4 MHz */
+
+ ifconf.enable = true;
+ ifconf.rf_chain = 0;
+ ifconf.freq_hz = -200000;
+ ifconf.datarate = DR_LORA_MULTI;
+ lgw_rxif_setconf(4, ifconf); /* chain 4: LoRa 125kHz, all SF, on f0 - 0.2 MHz */
+
+ ifconf.enable = true;
+ ifconf.rf_chain = 0;
+ ifconf.freq_hz = 0;
+ ifconf.datarate = DR_LORA_MULTI;
+ lgw_rxif_setconf(5, ifconf); /* chain 5: LoRa 125kHz, all SF, on f0 + 0.0 MHz */
+
+ ifconf.enable = true;
+ ifconf.rf_chain = 0;
+ ifconf.freq_hz = 200000;
+ ifconf.datarate = DR_LORA_MULTI;
+ lgw_rxif_setconf(6, ifconf); /* chain 6: LoRa 125kHz, all SF, on f0 + 0.2 MHz */
+
+ ifconf.enable = true;
+ ifconf.rf_chain = 0;
+ ifconf.freq_hz = 400000;
+ ifconf.datarate = DR_LORA_MULTI;
+ lgw_rxif_setconf(7, ifconf); /* chain 7: LoRa 125kHz, all SF, on f0 + 0.4 MHz */
+
+ /* set configuration for LoRa 'stand alone' channel */
+ memset(&ifconf, 0, sizeof(ifconf));
+ ifconf.enable = true;
+ ifconf.rf_chain = 0;
+ ifconf.freq_hz = 0;
+ ifconf.bandwidth = BW_250KHZ;
+ ifconf.datarate = DR_LORA_SF10;
+ lgw_rxif_setconf(8, ifconf); /* chain 8: LoRa 250kHz, SF10, on f0 MHz */
+
+ /* set configuration for FSK channel */
+ memset(&ifconf, 0, sizeof(ifconf));
+ ifconf.enable = true;
+ ifconf.rf_chain = 1;
+ ifconf.freq_hz = 0;
+ ifconf.bandwidth = BW_250KHZ;
+ ifconf.datarate = 64000;
+ lgw_rxif_setconf(9, ifconf); /* chain 9: FSK 64kbps, on f1 MHz */
+
+ /* set configuration for TX packet */
+ memset(&txpkt, 0, sizeof(txpkt));
+ txpkt.freq_hz = ft;
+ txpkt.tx_mode = IMMEDIATE;
+ txpkt.rf_power = 10;
+ txpkt.modulation = MOD_LORA;
+ txpkt.bandwidth = BW_125KHZ;
+ txpkt.datarate = DR_LORA_SF9;
+ txpkt.coderate = CR_LORA_4_5;
+ strcpy((char *)txpkt.payload, "TX.TEST.LORA.GW.????" );
+ txpkt.size = 20;
+ txpkt.preamble = 6;
+ txpkt.rf_chain = 0;
+/*
+ memset(&txpkt, 0, sizeof(txpkt));
+ txpkt.freq_hz = F_TX;
+ txpkt.tx_mode = IMMEDIATE;
+ txpkt.rf_power = 10;
+ txpkt.modulation = MOD_FSK;
+ txpkt.f_dev = 50;
+ txpkt.datarate = 64000;
+ strcpy((char *)txpkt.payload, "TX.TEST.LORA.GW.????" );
+ txpkt.size = 20;
+ txpkt.preamble = 4;
+ txpkt.rf_chain = 0;
+*/
+
+ /* connect, configure and start the LoRa concentrator */
+ i = lgw_start();
+ if (i == LGW_HAL_SUCCESS) {
+ printf("*** Concentrator started ***\n");
+ } else {
+ printf("*** Impossible to start concentrator ***\n");
+ return -1;
+ }
+
+ /* once configured, dump content of registers to a file, for reference */
+ // FILE * reg_dump = NULL;
+ // reg_dump = fopen("reg_dump.log", "w");
+ // if (reg_dump != NULL) {
+ // lgw_reg_check(reg_dump);
+ // fclose(reg_dump);
+ // }
+
+ while ((quit_sig != 1) && (exit_sig != 1)) {
+ loop_cnt++;
+
+ /* fetch N packets */
+ nb_pkt = lgw_receive(ARRAY_SIZE(rxpkt), rxpkt);
+
+ if (nb_pkt == 0) {
+ wait_ms(300);
+ } else {
+ /* display received packets */
+ for(i=0; i < nb_pkt; ++i) {
+ p = &rxpkt[i];
+ printf("---\nRcv pkt #%d >>", i+1);
+ if (p->status == STAT_CRC_OK) {
+ printf(" if_chain:%2d", p->if_chain);
+ printf(" tstamp:%010u", p->count_us);
+ printf(" size:%3u", p->size);
+ switch (p-> modulation) {
+ case MOD_LORA: printf(" LoRa"); break;
+ case MOD_FSK: printf(" FSK"); break;
+ default: printf(" modulation?");
+ }
+ switch (p->datarate) {
+ case DR_LORA_SF7: printf(" SF7"); break;
+ case DR_LORA_SF8: printf(" SF8"); break;
+ case DR_LORA_SF9: printf(" SF9"); break;
+ case DR_LORA_SF10: printf(" SF10"); break;
+ case DR_LORA_SF11: printf(" SF11"); break;
+ case DR_LORA_SF12: printf(" SF12"); break;
+ default: printf(" datarate?");
+ }
+ switch (p->coderate) {
+ case CR_LORA_4_5: printf(" CR1(4/5)"); break;
+ case CR_LORA_4_6: printf(" CR2(2/3)"); break;
+ case CR_LORA_4_7: printf(" CR3(4/7)"); break;
+ case CR_LORA_4_8: printf(" CR4(1/2)"); break;
+ default: printf(" coderate?");
+ }
+ printf("\n");
+ printf(" RSSI:%+6.1f SNR:%+5.1f (min:%+5.1f, max:%+5.1f) payload:\n", p->rssi, p->snr, p->snr_min, p->snr_max);
+
+ for (j = 0; j < p->size; ++j) {
+ printf(" %02X", p->payload[j]);
+ }
+ printf(" #\n");
+ } else if (p->status == STAT_CRC_BAD) {
+ printf(" if_chain:%2d", p->if_chain);
+ printf(" tstamp:%010u", p->count_us);
+ printf(" size:%3u\n", p->size);
+ printf(" CRC error, damaged packet\n\n");
+ } else if (p->status == STAT_NO_CRC){
+ printf(" if_chain:%2d", p->if_chain);
+ printf(" tstamp:%010u", p->count_us);
+ printf(" size:%3u\n", p->size);
+ printf(" no CRC\n\n");
+ } else {
+ printf(" if_chain:%2d", p->if_chain);
+ printf(" tstamp:%010u", p->count_us);
+ printf(" size:%3u\n", p->size);
+ printf(" invalid status ?!?\n\n");
+ }
+ }
+ }
+
+ /* send a packet every X loop */
+ if (loop_cnt%16 == 0) {
+ /* 32b counter in the payload, big endian */
+ txpkt.payload[16] = 0xff & (tx_cnt >> 24);
+ txpkt.payload[17] = 0xff & (tx_cnt >> 16);
+ txpkt.payload[18] = 0xff & (tx_cnt >> 8);
+ txpkt.payload[19] = 0xff & tx_cnt;
+ i = lgw_send(txpkt); /* non-blocking scheduling of TX packet */
+ j = 0;
+ printf("+++\nSending packet #%d, rf path %d, return %d\nstatus -> ", tx_cnt, txpkt.rf_chain, i);
+ do {
+ ++j;
+ wait_ms(100);
+ lgw_status(TX_STATUS, &status_var); /* get TX status */
+ printf("%d:", status_var);
+ } while ((status_var != TX_FREE) && (j < 100));
+ ++tx_cnt;
+ printf("\nTX finished\n");
+ }
+ }
+
+ if (exit_sig == 1) {
+ /* clean up before leaving */
+ lgw_stop();
+ }
+
+ printf("\nEnd of test for loragw_hal.c\n");
+ return 0;
+}
+
+/* --- EOF ------------------------------------------------------------------ */
diff --git a/libloragw/tst/test_loragw_reg.c b/libloragw/tst/test_loragw_reg.c
new file mode 100644
index 0000000..37a6f5a
--- /dev/null
+++ b/libloragw/tst/test_loragw_reg.c
@@ -0,0 +1,134 @@
+/*
+ / _____) _ | |
+( (____ _____ ____ _| |_ _____ ____| |__
+ \____ \| ___ | (_ _) ___ |/ ___) _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+ (C)2013 Semtech-Cycleo
+
+Description:
+ Minimum test program for the loragw_spi 'library'
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+Maintainer: Sylvain Miermont
+*/
+
+
+/* -------------------------------------------------------------------------- */
+/* --- DEPENDANCIES --------------------------------------------------------- */
+
+#include <stdint.h>
+#include <stdio.h>
+
+#include "loragw_reg.h"
+
+/* -------------------------------------------------------------------------- */
+/* --- MAIN FUNCTION -------------------------------------------------------- */
+
+#define BURST_TEST_LENGTH 8192
+
+int main()
+{
+ int32_t read_value, test_value;
+ uint16_t lfsr;
+ uint8_t burst_buffout[BURST_TEST_LENGTH];
+ uint8_t burst_buffin[BURST_TEST_LENGTH];
+ int i;
+
+ printf("Beginning of test for loragw_reg.c\n");
+
+ lgw_connect(false, 129E3);
+ /* 2 SPI transactions:
+ -> 0x80 0x00 <- 0x00 0x00 forcing page 0
+ -> 0x01 0x00 <- 0x00 0x64 checking version
+ */
+
+ /* --- READ TEST --- */
+
+ lgw_reg_w(LGW_SOFT_RESET, 1);
+ lgw_reg_check(stdout);
+
+ /* --- READ/WRITE COHERENCY TEST --- */
+
+ /* 8b unsigned */
+ test_value = 197; /* 11000101b */
+ lgw_reg_w(LGW_IMPLICIT_PAYLOAD_LENGHT, test_value);
+ lgw_reg_r(LGW_IMPLICIT_PAYLOAD_LENGHT, &read_value);
+ printf("IMPLICIT_PAYLOAD_LENGHT = %d (should be %d)\n", read_value, test_value);
+
+ /* 8b signed */
+ /* NO SUCH REG AVAILABLE */
+ // /* RADIO_SELECT is normally unsigned, modify it manually in loragw_reg.c */
+ // test_value = -59; /* 11000101b */
+ // lgw_reg_w(LGW_RADIO_SELECT, test_value);
+ // lgw_reg_r(LGW_RADIO_SELECT, &read_value);
+ // printf("RADIO_SELECT = %d (should be %d)\n", read_value, test_value);
+
+ /* less than 8b, with offset, unsigned */
+ test_value = 11; /* 1011b */
+ lgw_reg_w(LGW_FRAME_SYNCH_PEAK2_POS, test_value);
+ lgw_reg_r(LGW_FRAME_SYNCH_PEAK2_POS, &read_value);
+ printf("FRAME_SYNCH_PEAK2_POS = %d (should be %d)\n", read_value, test_value);
+
+ /* less than 8b, with offset, signed */
+ /* NO SUCH REG AVAILABLE */
+ // /* MBWSSF_FRAME_SYNCH_PEAK2_POS is normally unsigned, modify it manually in loragw_reg.c */
+ // test_value = -5; /* 1011b */
+ // lgw_reg_w(LGW_MBWSSF_FRAME_SYNCH_PEAK2_POS, test_value);
+ // lgw_reg_r(LGW_MBWSSF_FRAME_SYNCH_PEAK2_POS, &read_value);
+ // printf("MBWSSF_FRAME_SYNCH_PEAK2_POS = %d (should be %d)\n", read_value, test_value);
+
+ /* 16b unsigned */
+ test_value = 49253; /* 11000000 01100101b */
+ lgw_reg_w(LGW_PREAMBLE_SYMB1_NB, test_value);
+ lgw_reg_r(LGW_PREAMBLE_SYMB1_NB, &read_value);
+ printf("PREAMBLE_SYMB1_NB = %d (should be %d)\n", read_value, test_value);
+
+ /* 16b signed */
+ /* NO SUCH REG AVAILABLE */
+ // /* CAPTURE_PERIOD is normally unsigned, modify it manually in loragw_reg.c */
+ // test_value = -16283; /* 11000000 01100101b */
+ // lgw_reg_w(LGW_CAPTURE_PERIOD, test_value);
+ // lgw_reg_r(LGW_CAPTURE_PERIOD, &read_value);
+ // printf("CAPTURE_PERIOD = %d (should be %d)\n", read_value, test_value);
+
+ /* between 8b and 16b, unsigned */
+ test_value = 3173; /* 1100 01100101b */
+ lgw_reg_w(LGW_ADJUST_MODEM_START_OFFSET_SF12_RDX4, test_value);
+ lgw_reg_r(LGW_ADJUST_MODEM_START_OFFSET_SF12_RDX4, &read_value);
+ printf("ADJUST_MODEM_START_OFFSET_SF12_RDX4 = %d (should be %d)\n", read_value, test_value);
+
+ /* between 8b and 16b, signed */
+ test_value = -1947; /* 11000 01100101b */
+ lgw_reg_w(LGW_IF_FREQ_1, test_value);
+ lgw_reg_r(LGW_IF_FREQ_1, &read_value);
+ printf("IF_FREQ_1 = %d (should be %d)\n", read_value, test_value);
+
+ /* --- BURST WRITE AND READ TEST --- */
+
+ /* initialize data for SPI test */
+ lfsr = 0xFFFF;
+ for(i=0; i<BURST_TEST_LENGTH; ++i) {
+ burst_buffout[i] = (uint8_t)(lfsr ^ (lfsr >> 4));
+ /* printf("%05d # 0x%04x 0x%02x\n", i, lfsr, burst_buffout[i]); */
+ lfsr = (lfsr & 1) ? ((lfsr >> 1) ^ 0x8679) : (lfsr >> 1);
+ }
+
+ lgw_reg_wb(LGW_TX_DATA_BUF_DATA, burst_buffout, 256);
+ lgw_reg_rb(LGW_RX_DATA_BUF_DATA, burst_buffin, 256);
+
+ /* impossible to check in software,
+ RX_DATA_BUF_DATA is read-only,
+ TX_DATA_BUF_DATA is write only,
+ use a logic analyser */
+
+ /* --- END OF TEST --- */
+
+ lgw_disconnect();
+ /* no SPI transaction */
+
+ printf("End of test for loragw_reg.c\n");
+ return 0;
+}
+
+/* --- EOF ------------------------------------------------------------------ */
diff --git a/libloragw/tst/test_loragw_spi.c b/libloragw/tst/test_loragw_spi.c
new file mode 100644
index 0000000..872a075
--- /dev/null
+++ b/libloragw/tst/test_loragw_spi.c
@@ -0,0 +1,85 @@
+/*
+ / _____) _ | |
+( (____ _____ ____ _| |_ _____ ____| |__
+ \____ \| ___ | (_ _) ___ |/ ___) _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+ (C)2013 Semtech-Cycleo
+
+Description:
+ Minimum test program for the loragw_spi 'library'
+ Use logic analyser to check the results.
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+Maintainer: Sylvain Miermont
+*/
+
+
+/* -------------------------------------------------------------------------- */
+/* --- DEPENDANCIES --------------------------------------------------------- */
+
+#include <stdint.h>
+#include <stdio.h>
+
+#include "loragw_spi.h"
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE MACROS ------------------------------------------------------- */
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE CONSTANTS ---------------------------------------------------- */
+
+#define BURST_TEST_SIZE 2500 /* >> LGW_BURST_CHUNK */
+#define TIMING_REPEAT 1 /* repeat transactions multiple times for timing characterisation */
+
+/* -------------------------------------------------------------------------- */
+/* --- MAIN FUNCTION -------------------------------------------------------- */
+
+int main()
+{
+ int i;
+ void *spi_target = NULL;
+ uint8_t data = 0;
+ uint8_t dataout[BURST_TEST_SIZE];
+ uint8_t datain[BURST_TEST_SIZE];
+ uint8_t spi_mux_mode = LGW_SPI_MUX_MODE0;
+
+ for (i = 0; i < BURST_TEST_SIZE; ++i) {
+ dataout[i] = 0x30 + (i % 10); /* ASCCI code for 0 -> 9 */
+ datain[i] = 0x23; /* garbage data, to be overwritten by received data */
+ }
+
+ printf("Beginning of test for loragw_spi.c\n");
+ lgw_spi_open(&spi_target);
+
+ /* normal R/W test */
+ for (i = 0; i < TIMING_REPEAT; ++i)
+ lgw_spi_w(spi_target, spi_mux_mode, LGW_SPI_MUX_TARGET_SX1301, 0xAA, 0x96);
+ for (i = 0; i < TIMING_REPEAT; ++i)
+ lgw_spi_r(spi_target, spi_mux_mode, LGW_SPI_MUX_TARGET_SX1301, 0x55, &data);
+
+ /* burst R/W test, small bursts << LGW_BURST_CHUNK */
+ for (i = 0; i < TIMING_REPEAT; ++i)
+ lgw_spi_wb(spi_target, spi_mux_mode, LGW_SPI_MUX_TARGET_SX1301, 0x55, dataout, 16);
+ for (i = 0; i < TIMING_REPEAT; ++i)
+ lgw_spi_rb(spi_target, spi_mux_mode, LGW_SPI_MUX_TARGET_SX1301, 0x55, datain, 16);
+
+ /* burst R/W test, large bursts >> LGW_BURST_CHUNK */
+ for (i = 0; i < TIMING_REPEAT; ++i)
+ lgw_spi_wb(spi_target, spi_mux_mode, LGW_SPI_MUX_TARGET_SX1301, 0x5A, dataout, ARRAY_SIZE(dataout));
+ for (i = 0; i < TIMING_REPEAT; ++i)
+ lgw_spi_rb(spi_target, spi_mux_mode, LGW_SPI_MUX_TARGET_SX1301, 0x5A, datain, ARRAY_SIZE(datain));
+
+ /* last read (blocking), just to be sure no to quit before the FTDI buffer is flushed */
+ lgw_spi_r(spi_target, spi_mux_mode, LGW_SPI_MUX_TARGET_SX1301, 0x55, &data);
+ printf("data received (simple read): %d\n",data);
+
+ lgw_spi_close(spi_target);
+ printf("End of test for loragw_spi.c\n");
+
+ return 0;
+}
+
+/* --- EOF ------------------------------------------------------------------ */
diff --git a/readme.md b/readme.md
new file mode 100644
index 0000000..cdfd8d1
--- /dev/null
+++ b/readme.md
@@ -0,0 +1,410 @@
+ / _____) _ | |
+ ( (____ _____ ____ _| |_ _____ ____| |__
+ \____ \| ___ | (_ _) ___ |/ ___) _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+ (______/|_____)_|_|_| \__)_____)\____)_| |_|
+ (C)2013 Semtech-Cycleo
+
+LoRa Gateway project
+=====================
+
+1. Core library: libloragw
+---------------------------
+
+This directory contains the sources of the library to build a gateway based on
+a Semtech LoRa multi-channel RF receiver (a.k.a. concentrator).
+Once compiled all the code is contained in the libloragw.a file that will be
+statically linked (ie. integrated in the final executable).
+
+The library also comes with a bunch of basic tests programs that are used to
+test the different sub-modules of the library.
+
+2. Helper programs
+-------------------
+
+Those programs are included in the project to provide examples on how to use
+the HAL library, and to help the system builder test different parts of it.
+
+### 2.1. util_pkt_logger ###
+
+This software is used to set up a LoRa concentrator using a JSON configuration
+file and then record all the packets received in a log file, indefinitely, until
+the user stops the application.
+
+### 2.2. util_spi_stress ###
+
+This software is used to check the reliability of the link between the host
+platform (on which the program is run) and the LoRa concentrator register file
+that is the interface through which all interaction with the LoRa concentrator
+happens.
+
+### 2.3. util_tx_test ###
+
+This software is used to send test packets with a LoRa concentrator. The packets
+contain little information, on no protocol (ie. MAC address) information but
+can be used to assess the functionality of a gateway downlink using other
+gateways as receivers.
+
+### 2.4. util_tx_continuous ###
+
+This software is used to set LoRa concentrator in Tx continuous mode,
+for spectral measurement.
+
+### 2.5. util_spectral_scan ###
+
+This software is used to scan the spectral band in background, where the LoRa
+gateway operates.
+
+### 2.6. util_lbt_test ###
+
+This software is used to test "Listen-Before-Talk" channels timestamps.
+
+3. Helper scripts
+-----------------
+
+### 3.1. reset_lgw.sh
+
+This script must be launched on IoT Start Kit platform to reset concentrator
+chip through GPIO, before starting any application using the concentrator.
+
+4. Changelog
+-------------
+
+### v5.0.1 ###
+
+* HAL: Reworked the way the TX start delay is calculated, taking into account
+the delay introduced by TX notch filter (when enabled) and the delay linked to
+signal bandwidth separately.
+
+### v5.0.0 ###
+
+* HAL: Changed GPS module to get native GPS time (monotonic, no leap second).
+**WARNING**: The native GPS time is not given in standard NMEA messages, so we
+get it from a proprietary message of the GPS module used on gateway reference
+design, u-blox 7. If you are not using the same GPS module, you may have to
+update the lgw_parse_ubx() function.
+* HAL: Added lgw_cnt2gps() and lgw_gps2cnt() functions for SX1301<->GPS time
+conversion.
+* HAL: Changed serial port configuration for GPS to properly handle binary
+messages (UBX).
+* HAL: Added a lgw_gps_disable() function to restore serial configuration as
+it was before HAL initialization.
+* HAL: Fixed packet time on air calculation using the actual packet preamble
+size.
+* HAL: Adjusted TX_START_DELAY based on the board reference design to ensure
+that a packet is sent exactly at 1500µs after the TX trigger (TIMESTAMP or PPS),
+with a tolerance of +/- 1µs. This is mandatory to comply with LoRaWAN
+specification for Class-B beaconing precise timing.
+**WARNING**: This release provides tx start delay values to be used for Semtech
+reference designs AP1 and AP2. The HAL automatically detects the board version
+by detecting a FPGA or not. If you are using a different reference design or
+a different FPGA binary version than the one provided with this release, the
+value to be used for TX start delay may be different.
+
+### v4.1.3 ###
+
+* HAL: Reference clock frequency error improvement: The lora_gateway HAL has
+been updated (3 registers changed) to improve the performance of all gateways
+based on SX130x. The fix greatly improves the reception of packet at SF12, when
+the frequency offset of the incoming packet is large (mostly below -20ppm of
+frequency offset).
+
+WARNING: Systems which do not have the patch will be more prone to packet loss
+over time, when the crystals of the end-devices will be ageing and have more
+frequency offset.
+
+### v4.1.2 ###
+
+* HAL: Changed configuration of IQ polarity of FPGA for TX to comply with FPGA
+version greater than v27. (Only required for AP2 Semtech reference design)
+* HAL: Updated default LoRa preamble size according to LoRaWAN spec.
+
+### v4.1.1 ###
+
+* HAL: Fixed bug in "Listen-Before-Talk" which was preventing from configuring
+the Scan Time to 5ms.
+* MISC: Added GPIO number to reset_lgw.sh command arguments.
+
+### v4.1.0 ###
+
+* HAL: Reworked "Listen-Before-Talk" feature to have more flexibility to define
+LBT channels frequency, and to be able to have spectral scan running in parallel
+* HAL: Updated lgw_time_on_air() function for FSK packets
+* HAL: Disabled GPS UART input being re-echoed as output to avoid sending wrong
+commands to GPS module
+* HAL: Fixed IF frequency configuration check issue for channel bandwidths 250K
+and 500HKz.
+* FPGA: Updated to v31 for new LBT and spectral scan design.
+* util_spectral_scan: updated to match new spectral scan FPGA sequence
+* util_lbt_test: updated to match LBT rework
+
+Note: The provided LBT feature has been validated for Japan only, and supports
+8 downlink channels maximum.
+
+### v4.0.1 ###
+
+* HAL: SX1301AP2: Only FPGA v27 is supported, removed (v18,v19) from the list
+ of supported FPGA images.
+
+WARNING: If you are using a Semtech SX1301AP2 ref design (GW1.5), the FPGA must
+be reprogrammed with one of the images provided with this release (fpga/ dir).
+
+### v4.0.0 ###
+
+* HAL: Added "Listen-Before-Talk" support for Semtech SX1301AP2 Ref Design.
+ A description of the feature implementation can be found in
+ libloragw/readme.md.
+* HAL: Updated FSK RSSI calculation for better linearization
+* util_lbt_test: New utility provided for basic "Listen-Before-Talk" testing.
+* util_tx_test: Extended to configure and test "LBT" through the HAL.
+* Added a reset_lgw.sh script to be used with IoT Starter Kit (v1.0) to reset
+the concentrator through the HOST GPIO pin.
+
+### v3.2.1 ###
+
+* HAL: Fixed downlink support for SX1301AP2 reference design: soft reset of the
+FPGA was missing for proper IQ inversion configuration.
+* HAL: Added support for several versions of FPGA (currently v18 and v19)
+* HAL: Reduced radio TX PLL bandwidth to reduce the noise level.
+* util_tx_test: Added FSK support and added minimal TX gain LUT.
+* util_spectral_scan: Removed FPGA soft reset, now done by the HAL.
+* util_tx_continous: reworked to use HAL functions instead of 'manual' config,
+and use same SX1301 calibration firmware as the HAL.
+* Updated all makefiles to handle the creation of obj directory when necessary.
+* Change cs_change usage policy in SPI module to let the driver handle the chip
+select.
+
+### v3.2.0 ###
+
+* Added support for SX1301AP2 reference design (with FPGA and additional
+SX127x). When a FPGA is detected at startup, the HAL automatically adapts SPI
+communication requests (using SPI header or not).
+* Added util_spectral_scan diagnostic tool to scan the spectral band in
+background, where the LoRa gateway operates. (can only be used with SX1301AP2
+or similar design). By default it uses the same SPI device as the one used by
+the HAL, but it can be changed depending on the hardware architecture on which
+it is used by updating the SPI_DEV_PATH constant defined in file
+util_spectral_scan/src/loragw_fpga_spi.c.
+Note: when using same SPI device from 2 applications, we rely on the host SPI
+driver and OS to properly handle concurrent SPI requests. It has been tested on
+Raspberry Pi / Raspbian with spi_bcm2708 driver.* Removed SPI FTDI support due
+to lack of performances to properly handle heavy packet traffic. Only native
+SPI usage is recommended.
+* HAL: added a check that SX1301 firmwares have been properly loaded at startup.
+
+### v3.1.0 ###
+
+* Removed GPIO module from HAL, that was specific to IoT Starter Kit platform.
+GPIO configuration will be done from application script instead.
+* Removed CFG_BRD configuration from library.cfg, not needed anymore
+
+### v3.0.2 ###
+
+* Bugfix: Fixed frequency calculation on uplinks: lgw_receive() function was
+using a variable to calculate the frequency before it was initialized with
+correct value.
+* Bugfix: util_pkt_logger crashed when no gateway_ID is not defined in
+global_conf.json
+
+### v3.0.1 ###
+
+* Bufgix: Fixed util_tx_continuous compilation issue, by adding empty obj
+directory
+* Bugfix: Fixed HAL compilation issue for CFG_SPI=ftdi, removed dependency on
+loragw_gpio in this case
+
+### v3.0.0 ###
+
+* Added new HAL function lgw_board_setconf() to configure board/concentrator
+specific parameters: network type (LoRa public or private), concentrator clock
+source. Note: those parameters are not any more set from the library.cfg file
+configuration (CFG_NET, CFG_BRD),
+and should be passed at initialization by the application.
+* Added new HAL function lgw_txgain_setconf() to configure concentrator TX gain
+table. It can now be dynamically set by the application at initialization time.
+* Changed HAL function lgw_rxrf_setconf(), it will now also configure the radio
+type (CFG_RADIO has been removed from library.cfg), the RSSI offset to be used
+for this radio and if TX is enabled or not on this radio.
+* Added support of IoT Starter Kit platform, which is now the default board.
+* Added util_tx_continuous utility for gateway TX power calibration and
+spectral emission measurements/qualification.
+* Removed CFG_BAND configuration from library.cfg. Band configuration is done
+by application and passed dynamically at initialization time.
+* Updated makefiles to allow cross compilation from environment variable (ARCH,
+CROSS_COMPILE).
+
+** WARNING: **
+** Known issue: a problem with carrier leakage calibration has been seen on
+433MHz boards. **
+
+### v2.0.0 ###
+
+* Added support for Kerlink 868 27dBm gateway
+* Updated global_conf.eu868.json (in packet logger) to new LoRaWAN frequency
+plan
+* Added version numbers to AGC, arbiter and calibration firmware (those
+versions are checked at startup)
+* Added test_loragw_cal to test radio calibrations
+* Fixed minor bug in error coverage in register read/write functions
+
+/!\ warning: Kerlink 868 27dBm gateway includes a FPGA that MUST be programmed
+before running any application
+
+### v1.7.0 ###
+
+* Added TX 'start delay' compensation for timestamp mode (fix time window
+alignment issue at low SF and/or high BW)
+* Added adaptive narrowband/wideband TX filtering for LoRa
+* Added a command-line option to set CR in util_tx_test
+* Added notes for TX 'start delay' in immediate and triggered mode
+
+/!\ warning: due to start delay compensation being implemented, TX that were
+previously 1.5ms late will be sent on time. At low datarate, this is not an
+issue. At high LoRa data rate (and FSK) you might have to adjust your timing.
+
+### v1.6.0 ###
+
+* Fixed bug with 250kHz and 500 kHz TX filtering
+* Adjusted FSK timestamp calibration in RX for accurate RX/TX alignment
+* Added lgw_abort_tx() function to stop a TX at any time (scheduled or ongoing)
+* Added support for user-settable FSK sync word (same for RX and TX)
+* Added support for the Chinese 780 MHz band
+* Added support for Kerlink 433 gateway
+* Added support for Cisco 433, 470 & 780 MHz concentrators boards
+
+### v1.5.0 ###
+
+* Adding option to isolate public LoRa MAC networks at PHY level.
+
+### v1.4.1 ###
+
+* Enabling support for FSK per LoRa MAC specification
+* Adjusting TX and RX calibration set on 868 reference board
+* Added specific RX/TX calibration set for Kerlink 868 "IoT station" gateway
+* Changed default SPI port for native driver to Kerlink SPI device number
+
+### v1.4.0 ###
+
+* Added calibration routine to optimize RF performance
+* Added support for SX1301 433 MHz reference board
+* Improved AGC firmware
+* Improved RSSI accuracy
+* Improved utilities Makefile
+
+### v1.3.0 ###
+
+* Added TX power management.
+* Added full support for SX1301 reference board.
+* Changed build system with configuration for multiple chip/radio/band support.
+* SX125x bandwidth set to 1MHz by default (was 800 kHz).
+* Solved warnings with 64b integer printf when compiling on x86_64.
+* Renamed helper programs to reduce the concentrator vs. gateway confusion.
+
+### v1.2.2 ###
+
+* Added a GPIO toggle on the FTDI SPI module to reset the SX1301 board.
+
+### v1.2.1 ###
+
+* Fixed 'floating point exception' crash when concentrator returned a packet
+with SF=0 (CRC error on LoRa header).
+* Fixed buggy timezone handling.
+
+### v1.2.0 ###
+
+* Added feature: new GPS module in the library for synchronization.
+* Removed feature: no more missed deadline detection in TX because of
+incompatibility with GPS.
+* Added documentation for GPS and legal notice.
+* Added flags in Makefiles for easier cross-compilation.
+
+### v1.1.0 ###
+
+* Fixed bug 'no TX on radio B' (rfch 1).
+* Added feature: concentrator processing delay compensation in the receive()
+function for accurate 'end of packet' even timestamping.
+* Added feature: TX 'start delay' compensation in the send() function to emit
+packet exactly on target timestamp.
+* Added feature: timestamp counter verification in send() function, return an
+error if scheduling was too late.
+* Switched license to 'Revised BSD'.
+
+### v1.0.0 (from beta 8) ###
+
+* Switched FTDI as default SPI phy layer in library.cfg.
+* Fixed a bug in TX power control; still only two TW power available, 14 and
+24dBm.
+* Changed library directory name from loragw_hal to libloragw to follow usual
+conventions.
+
+### Beta 8 (from beta 7) ###
+
+* API: lgw_receive now return info on RX frequency and RF path for each packet
+(no need to keep track of RF/IF settings).
+* Unified some portion of the code with the 470 MHz variant of the HAL (use
+SX1255 radios instead of SX1257).
+* Improved AGC and ARB firmwares.
+* Adding -Wall -Wextra for compilation, fixing all the new warnings for cleaner
+code.
+* Fixed bugs in handling of FSK datarate.
+* test_loragw_hal now dumps the content of all LoRa registers after
+configuration in reg_dump.log.
+
+### Beta 7 (from beta 5) ###
+
+* Reduced number of SPI transactions to fetch a packet (improved number a
+packets par second that can be downloaded from concentrator).
+* Streamlined build process, main target is now a static library: libloragw.a.
+* Change memory allocation for payload: they are now part of the struct for
+TX/RX, no need to malloc/free.
+* All RX chains can use any of the two radios now.
+* FSK is available and working in TX and RX (variable length mode).
+* Calibrated RSSI for FSK.
+* lgw_connect now check the CHIP_ID.
+* Added a license file and a changelog.
+* Added a function returning a version string to allow identification of the
+version/options once compiled.
+
+### Beta 6 ###
+
+Private release, not taken into account in that changelog.
+
+### Beta 5 (from beta 4) ###
+
+* Updated registers, firmware and configuration to align with r986 bitstream
+revision.
+* Calibrated RSSI for LoRa "multi" and LoRa "stand alone" modems.
+* Renamed some confusing TX status code.
+* Added preliminary FSK support.
+
+### Beta 4 (from beta 3) ###
+
+* Unified build environment with selectable SPI layer (Linux native or FTDI
+SPI-over-USB bridge).
+* Remove the 500 kHz limit on radio bandwith, back to the nominal 800 kHz.
+* Renamed debug flags.
+
+5. Legal notice
+----------------
+
+The information presented in this project documentation does not form part of
+any quotation or contract, is believed to be accurate and reliable and may be
+changed without notice. No liability will be accepted by the publisher for any
+consequence of its use. Publication thereof does not convey nor imply any
+license under patent or other industrial or intellectual property rights.
+Semtech assumes no responsibility or liability whatsoever for any failure or
+unexpected operation resulting from misuse, neglect improper installation,
+repair or improper handling or unusual physical or electrical stress
+including, but not limited to, exposure to parameters beyond the specified
+maximum ratings or operation outside the specified range.
+
+SEMTECH PRODUCTS ARE NOT DESIGNED, INTENDED, AUTHORIZED OR WARRANTED TO BE
+SUITABLE FOR USE IN LIFE-SUPPORT APPLICATIONS, DEVICES OR SYSTEMS OR OTHER
+CRITICAL APPLICATIONS. INCLUSION OF SEMTECH PRODUCTS IN SUCH APPLICATIONS IS
+UNDERSTOOD TO BE UNDERTAKEN SOLELY AT THE CUSTOMER'S OWN RISK. Should a
+customer purchase or use Semtech products for any such unauthorized
+application, the customer shall indemnify and hold Semtech and its officers,
+employees, subsidiaries, affiliates, and distributors harmless against all
+claims, costs damages and attorney fees which could arise.
+
+*EOF*
diff --git a/reset_lgw.sh b/reset_lgw.sh
new file mode 100755
index 0000000..77de63e
--- /dev/null
+++ b/reset_lgw.sh
@@ -0,0 +1,62 @@
+#!/bin/sh
+
+# This script is intended to be used on IoT Starter Kit platform, it performs
+# the following actions:
+# - export/unpexort GPIO7 used to reset the SX1301 chip
+#
+# Usage examples:
+# ./reset_lgw.sh stop
+# ./reset_lgw.sh start
+
+# The reset pin of SX1301 is wired with RPi GPIO7
+# If used on another platform, the GPIO number can be given as parameter.
+if [ -z "$2" ]; then
+ IOT_SK_SX1301_RESET_PIN=7
+else
+ IOT_SK_SX1301_RESET_PIN=$2
+fi
+
+echo "Accessing concentrator reset pin through GPIO$IOT_SK_SX1301_RESET_PIN..."
+
+WAIT_GPIO() {
+ sleep 0.1
+}
+
+iot_sk_init() {
+ # setup GPIO 7
+ echo "$IOT_SK_SX1301_RESET_PIN" > /sys/class/gpio/export; WAIT_GPIO
+
+ # set GPIO 7 as output
+ echo "out" > /sys/class/gpio/gpio$IOT_SK_SX1301_RESET_PIN/direction; WAIT_GPIO
+
+ # write output for SX1301 reset
+ echo "1" > /sys/class/gpio/gpio$IOT_SK_SX1301_RESET_PIN/value; WAIT_GPIO
+ echo "0" > /sys/class/gpio/gpio$IOT_SK_SX1301_RESET_PIN/value; WAIT_GPIO
+
+ # set GPIO 7 as input
+ echo "in" > /sys/class/gpio/gpio$IOT_SK_SX1301_RESET_PIN/direction; WAIT_GPIO
+}
+
+iot_sk_term() {
+ # cleanup GPIO 7
+ if [ -d /sys/class/gpio/gpio$IOT_SK_SX1301_RESET_PIN ]
+ then
+ echo "$IOT_SK_SX1301_RESET_PIN" > /sys/class/gpio/unexport; WAIT_GPIO
+ fi
+}
+
+case "$1" in
+ start)
+ iot_sk_term
+ iot_sk_init
+ ;;
+ stop)
+ iot_sk_term
+ ;;
+ *)
+ echo "Usage: $0 {start|stop} [<gpio number>]"
+ exit 1
+ ;;
+esac
+
+exit 0
diff --git a/util_lbt_test/Makefile b/util_lbt_test/Makefile
new file mode 100644
index 0000000..de937e4
--- /dev/null
+++ b/util_lbt_test/Makefile
@@ -0,0 +1,65 @@
+### Application-specific constants
+
+APP_NAME := util_lbt_test
+
+### Environment constants
+
+LGW_PATH ?= ../libloragw
+ARCH ?=
+CROSS_COMPILE ?=
+
+### External constant definitions
+
+include $(LGW_PATH)/library.cfg
+
+### Constant symbols
+
+CC := $(CROSS_COMPILE)gcc
+AR := $(CROSS_COMPILE)ar
+
+CFLAGS=-O2 -Wall -Wextra -std=c99 -Iinc -I.
+
+OBJDIR = obj
+
+### Constants for LoRa concentrator HAL library
+# List the library sub-modules that are used by the application
+
+LGW_INC = $(LGW_PATH)/inc/config.h
+LGW_INC += $(LGW_PATH)/inc/loragw_reg.h
+LGW_INC += $(LGW_PATH)/inc/loragw_fpga.h
+
+### Linking options
+
+LIBS := -lloragw -lrt -lm
+
+### General build targets
+
+all: $(APP_NAME)
+
+clean:
+ rm -f $(OBJDIR)/*.o
+ rm -f $(APP_NAME)
+
+### HAL library (do no force multiple library rebuild even with 'make -B')
+
+$(LGW_PATH)/inc/config.h:
+ @if test ! -f $@; then \
+ $(MAKE) all -C $(LGW_PATH); \
+ fi
+
+$(LGW_PATH)/libloragw.a: $(LGW_INC)
+ @if test ! -f $@; then \
+ $(MAKE) all -C $(LGW_PATH); \
+ fi
+
+### Main program compilation and assembly
+$(OBJDIR):
+ mkdir -p $(OBJDIR)
+
+$(OBJDIR)/$(APP_NAME).o: src/$(APP_NAME).c $(LGW_INC) | $(OBJDIR)
+ $(CC) -c $(CFLAGS) -I$(LGW_PATH)/inc $< -o $@
+
+$(APP_NAME): $(OBJDIR)/$(APP_NAME).o $(LGW_PATH)/libloragw.a
+ $(CC) -L$(LGW_PATH) $< -o $@ $(LIBS)
+
+### EOF
diff --git a/util_lbt_test/readme.md b/util_lbt_test/readme.md
new file mode 100644
index 0000000..db6cd58
--- /dev/null
+++ b/util_lbt_test/readme.md
@@ -0,0 +1,50 @@
+ / _____) _ | |
+ ( (____ _____ ____ _| |_ _____ ____| |__
+ \____ \| ___ | (_ _) ___ |/ ___) _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+ (______/|_____)_|_|_| \__)_____)\____)_| |_|
+ ©2013 Semtech-Cycleo
+
+Lora Gateway LBT basic test application
+=======================================
+
+1. Introduction
+----------------
+
+This software configures the FPGA for "Liste-Before-Talk" feature and
+continuously reads the LBT channels timestamps which indicate when was the last
+instant when the channel was free.
+
+2. Dependencies
+----------------
+
+A SX1301AP2 Ref Design board with its FPGA programmed with LBT feature
+
+3. Usage
+---------
+
+Before running the util_lbt_test application, the concentrator MUST be first
+started with the HAL, using for example util_pkt_logger or the packet forwarder
+with LBT feature disabled, as the util_lbt_test will configure it.
+
+For a description of the command line options available:
+./util_lbt_test -h
+
+ex:
+./util_lbt_test -f 867.1 -r -80 -s 5000
+
+This will set 8 LBT channels, starting from 867.1 MHz, then each subsequent
+channel being set to the frequency of the previous channel +200 KHz (867.3,
+867.5, ...).
+
+The above test will run for ever, with a CHANNEL_SCAN_TIME of 5000µs
+and a target RSSI of -80dBm.
+
+Please refer to the lora_gateway library readme.md to get more details on the
+LBT feature implementation and configuration.
+
+4. Changelog
+-------------
+
+2016-03-03 v1.0 Initial version
+2016-08-31 v1.1 LBT feature rework
diff --git a/util_lbt_test/src/util_lbt_test.c b/util_lbt_test/src/util_lbt_test.c
new file mode 100644
index 0000000..1c8b185
--- /dev/null
+++ b/util_lbt_test/src/util_lbt_test.c
@@ -0,0 +1,274 @@
+/*
+ / _____) _ | |
+( (____ _____ ____ _| |_ _____ ____| |__
+ \____ \| ___ | (_ _) ___ |/ ___) _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+ (C)2013 Semtech-Cycleo
+
+Description:
+ Listen Before Talk basic test application
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+Maintainer: Michael Coracin
+*/
+
+
+/* -------------------------------------------------------------------------- */
+/* --- DEPENDANCIES --------------------------------------------------------- */
+
+/* fix an issue between POSIX and C99 */
+#if __STDC_VERSION__ >= 199901L
+ #define _XOPEN_SOURCE 600
+#else
+ #define _XOPEN_SOURCE 500
+#endif
+
+#include <stdint.h> /* C99 types */
+#include <stdbool.h> /* bool type */
+#include <stdio.h> /* printf fprintf sprintf fopen fputs */
+
+#include <signal.h> /* sigaction */
+#include <unistd.h> /* getopt access */
+#include <stdlib.h> /* rand */
+
+#include "loragw_aux.h"
+#include "loragw_reg.h"
+#include "loragw_hal.h"
+#include "loragw_radio.h"
+#include "loragw_fpga.h"
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE MACROS & CONSTANTS ------------------------------------------- */
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+#define MSG(args...) fprintf(stderr, args) /* message that is destined to the user */
+
+#define DEFAULT_SX127X_RSSI_OFFSET -1
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE VARIABLES (GLOBAL) ------------------------------------------- */
+
+/* signal handling variables */
+struct sigaction sigact; /* SIGQUIT&SIGINT&SIGTERM signal handling */
+static int exit_sig = 0; /* 1 -> application terminates cleanly (shut down hardware, close open files, etc) */
+static int quit_sig = 0; /* 1 -> application terminates without shutting down the hardware */
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE FUNCTIONS DECLARATION ---------------------------------------- */
+
+static void sig_handler(int sigio);
+
+void usage (void);
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE FUNCTIONS DEFINITION ----------------------------------------- */
+
+static void sig_handler(int sigio) {
+ if (sigio == SIGQUIT) {
+ quit_sig = 1;;
+ } else if ((sigio == SIGINT) || (sigio == SIGTERM)) {
+ exit_sig = 1;
+ }
+}
+
+/* describe command line options */
+void usage(void) {
+ printf("Available options:\n");
+ printf(" -h print this help\n");
+ printf(" -f <float> frequency in MHz of the first LBT channel\n");
+ printf(" -o <int> offset in dB to be applied to the SX127x RSSI [-128..127]\n");
+ printf(" -r <int> target RSSI: signal strength target used to detect if the channel is clear or not [-128..0]\n");
+ printf(" -s <uint> scan time in µs for all 8 LBT channels [128,5000]\n");
+}
+
+/* -------------------------------------------------------------------------- */
+/* --- MAIN FUNCTION -------------------------------------------------------- */
+
+int main(int argc, char **argv)
+{
+ int i;
+ int xi = 0;
+
+ /* in/out variables */
+ double f1 = 0.0;
+ uint32_t f_init = 0; /* in Hz */
+ uint32_t f_start = 0; /* in Hz */
+ uint16_t loop_cnt = 0;
+ int8_t rssi_target_dBm = -80;
+ uint16_t scan_time_us = 128;
+ uint32_t timestamp;
+ uint8_t rssi_value;
+ int8_t rssi_offset = DEFAULT_SX127X_RSSI_OFFSET;
+ int32_t val, val2;
+ int channel;
+ uint32_t freq_offset;
+
+ /* parse command line options */
+ while ((i = getopt (argc, argv, "h:f:s:r:o:")) != -1) {
+ switch (i) {
+ case 'h':
+ usage();
+ return EXIT_FAILURE;
+ break;
+
+ case 'f':
+ i = sscanf(optarg, "%lf", &f1);
+ if ((i != 1) || (f1 < 30.0) || (f1 > 3000.0)) {
+ MSG("ERROR: Invalid LBT start frequency\n");
+ usage();
+ return EXIT_FAILURE;
+ } else {
+ f_start = (uint32_t)((f1*1e6) + 0.5);/* .5 Hz offset to get rounding instead of truncating */
+ }
+ break;
+ case 's':
+ i = sscanf(optarg, "%i", &xi);
+ if ((i != 1) || ((xi != 128) && (xi != 5000))) {
+ MSG("ERROR: scan_time_us must be 128 or 5000 \n");
+ usage();
+ return EXIT_FAILURE;
+ } else {
+ scan_time_us = xi;
+ }
+ break;
+ case 'r':
+ i = sscanf(optarg, "%i", &xi);
+ if ((i != 1) || ((xi < -128) && (xi > 0))) {
+ MSG("ERROR: rssi_target must be b/w -128 & 0 \n");
+ usage();
+ return EXIT_FAILURE;
+ } else {
+ rssi_target_dBm = xi;
+ }
+ break;
+ case 'o': /* -o <int> SX127x RSSI offset [-128..127] */
+ i = sscanf(optarg, "%i", &xi);
+ if((i != 1) || (xi < -128) || (xi > 127)) {
+ MSG("ERROR: rssi_offset must be b/w -128 & 127\n");
+ usage();
+ return EXIT_FAILURE;
+ } else {
+ rssi_offset = (int8_t)xi;
+ }
+ break;
+ default:
+ MSG("ERROR: argument parsing use -h option for help\n");
+ usage();
+ return EXIT_FAILURE;
+ }
+ }
+
+ MSG("INFO: Starting LoRa Gateway v1.5 LBT test\n");
+
+ /* configure signal handling */
+ sigemptyset(&sigact.sa_mask);
+ sigact.sa_flags = 0;
+ sigact.sa_handler = sig_handler;
+ sigaction(SIGQUIT, &sigact, NULL);
+ sigaction(SIGINT, &sigact, NULL);
+ sigaction(SIGTERM, &sigact, NULL);
+
+ /* Connect to concentrator */
+ i = lgw_connect(false, LGW_DEFAULT_NOTCH_FREQ);
+ if (i != LGW_REG_SUCCESS) {
+ MSG("ERROR: lgw_connect() did not return SUCCESS\n");
+ return EXIT_FAILURE;
+ }
+
+ /* Check if FPGA supports LBT */
+ lgw_fpga_reg_r(LGW_FPGA_FEATURE, &val);
+ if (TAKE_N_BITS_FROM((uint8_t)val, 2, 1) != true) {
+ MSG("ERROR: LBT is not supported (0x%x)\n", (uint8_t)val);
+ return EXIT_FAILURE;
+ }
+
+ /* Get FPGA lowest frequency for LBT channels */
+ lgw_fpga_reg_r(LGW_FPGA_LBT_INITIAL_FREQ, &val);
+ switch (val) {
+ case 0:
+ f_init = 915000000;
+ break;
+ case 1:
+ f_init = 863000000;
+ break;
+ default:
+ MSG("ERROR: LBT start frequency %d is not supported\n", val);
+ return EXIT_FAILURE;
+ }
+
+ /* Initialize 1st LBT channel freq if not given by user */
+ if (f_start == 0) {
+ f_start = f_init;
+ } else if (f_start < f_init) {
+ MSG("ERROR: LBT start frequency %u is not supported (f_init=%u)\n", f_start, f_init);
+ return EXIT_FAILURE;
+ }
+ MSG("FREQ: %u\n", f_start);
+
+ /* Configure SX127x and read few RSSI points */
+ lgw_setup_sx127x(f_init, MOD_FSK, LGW_SX127X_RXBW_100K_HZ, rssi_offset); /* 200KHz LBT channels */
+ for (i = 0; i < 100; i++) {
+ lgw_sx127x_reg_r(0x11, &rssi_value); /* 0x11: RegRssiValue */
+ MSG("SX127x RSSI:%i dBm\n", -(rssi_value/2));
+ wait_ms(10);
+ }
+
+ /* Configure LBT */
+ val = -2*(rssi_target_dBm);
+ lgw_fpga_reg_w(LGW_FPGA_RSSI_TARGET, val);
+ for (i = 0; i < LBT_CHANNEL_FREQ_NB; i++) {
+ freq_offset = (f_start - f_init)/100E3 + i*2; /* 200KHz between each channel */
+ lgw_fpga_reg_w(LGW_FPGA_LBT_CH0_FREQ_OFFSET+i, (int32_t)freq_offset);
+ if (scan_time_us == 5000) { /* configured to 128 by default */
+ lgw_fpga_reg_w(LGW_FPGA_LBT_SCAN_TIME_CH0+i, 1);
+ }
+ }
+
+ lgw_fpga_reg_r(LGW_FPGA_RSSI_TARGET, &val);
+ MSG("RSSI_TARGET = %d\n", val);
+ if (val != (-2*rssi_target_dBm)) {
+ MSG("ERROR: failed to read back RSSI target register value\n");
+ return EXIT_FAILURE;
+ }
+ for (i = 0; i < LBT_CHANNEL_FREQ_NB; i++) {
+ lgw_fpga_reg_r(LGW_FPGA_LBT_CH0_FREQ_OFFSET+i, &val);
+ lgw_fpga_reg_r(LGW_FPGA_LBT_SCAN_TIME_CH0+i, &val2);
+ MSG("CH_%i: freq=%u (offset=%i), scan_time=%u (%i)\n", i, (uint32_t)((val*100E3)+f_init), val, (val2==1)?5000:128, val2);
+ }
+ lgw_fpga_reg_r(LGW_FPGA_VERSION, &val);
+ MSG("FPGA VERSION = %d\n", val);
+
+ /* Enable LBT FSM */
+ lgw_fpga_reg_w(LGW_FPGA_CTRL_FEATURE_START, 1);
+
+ /* Start test */
+ while ((quit_sig != 1) && (exit_sig != 1)) {
+ MSG("~~~~\n");
+ for (channel = 0; channel < LBT_CHANNEL_FREQ_NB; channel++) {
+ /* Select LBT channel */
+ lgw_fpga_reg_w(LGW_FPGA_LBT_TIMESTAMP_SELECT_CH, channel);
+
+ /* Get last instant when the selected channel was free */
+ lgw_fpga_reg_r(LGW_FPGA_LBT_TIMESTAMP_CH, &val);
+ timestamp = (uint32_t)(val & 0x0000FFFF) * 256; /* 16bits (1LSB = 256µs) */
+ MSG(" TIMESTAMP_CH%u = %u\n", channel, timestamp);
+ }
+
+ loop_cnt += 1;
+ wait_ms(400);
+ }
+
+ /* close SPI link */
+ i = lgw_disconnect();
+ if (i != LGW_REG_SUCCESS) {
+ MSG("ERROR: lgw_disconnect() did not return SUCCESS\n");
+ return EXIT_FAILURE;
+ }
+
+ MSG("INFO: Exiting LoRa Gateway v1.5 LBT test successfully\n");
+ return EXIT_SUCCESS;
+}
+
+/* --- EOF ------------------------------------------------------------------ */
+
diff --git a/util_pkt_logger/Makefile b/util_pkt_logger/Makefile
new file mode 100644
index 0000000..264ccc1
--- /dev/null
+++ b/util_pkt_logger/Makefile
@@ -0,0 +1,70 @@
+### Application-specific constants
+
+APP_NAME := util_pkt_logger
+
+### Environment constants
+
+LGW_PATH ?= ../libloragw
+ARCH ?=
+CROSS_COMPILE ?=
+
+### External constant definitions
+
+include $(LGW_PATH)/library.cfg
+
+### Constant symbols
+
+CC := $(CROSS_COMPILE)gcc
+AR := $(CROSS_COMPILE)ar
+
+CFLAGS=-O2 -Wall -Wextra -std=c99 -Iinc -I.
+
+OBJDIR = obj
+
+### Constants for LoRa concentrator HAL library
+# List the library sub-modules that are used by the application
+
+LGW_INC = $(LGW_PATH)/inc/config.h
+LGW_INC += $(LGW_PATH)/inc/loragw_hal.h
+
+### Linking options
+
+LIBS := -lloragw -lrt -lm
+
+### General build targets
+
+all: $(APP_NAME)
+
+clean:
+ rm -f $(OBJDIR)/*.o
+ rm -f $(APP_NAME)
+
+### HAL library (do no force multiple library rebuild even with 'make -B')
+
+$(LGW_PATH)/inc/config.h:
+ @if test ! -f $@; then \
+ $(MAKE) all -C $(LGW_PATH); \
+ fi
+
+$(LGW_PATH)/libloragw.a: $(LGW_INC)
+ @if test ! -f $@; then \
+ $(MAKE) all -C $(LGW_PATH); \
+ fi
+
+### Sub-modules compilation
+
+$(OBJDIR):
+ mkdir -p $(OBJDIR)
+
+$(OBJDIR)/parson.o: src/parson.c inc/parson.h | $(OBJDIR)
+ $(CC) -c $(CFLAGS) $< -o $@
+
+### Main program compilation and assembly
+
+$(OBJDIR)/$(APP_NAME).o: src/$(APP_NAME).c $(LGW_INC) inc/parson.h | $(OBJDIR)
+ $(CC) -c $(CFLAGS) -I$(LGW_PATH)/inc $< -o $@
+
+$(APP_NAME): $(OBJDIR)/$(APP_NAME).o $(LGW_PATH)/libloragw.a $(OBJDIR)/parson.o
+ $(CC) -L$(LGW_PATH) $< $(OBJDIR)/parson.o -o $@ $(LIBS)
+
+### EOF
diff --git a/util_pkt_logger/global_conf.json b/util_pkt_logger/global_conf.json
new file mode 100644
index 0000000..a3f327a
--- /dev/null
+++ b/util_pkt_logger/global_conf.json
@@ -0,0 +1,87 @@
+{
+ "SX1301_conf": {
+ "lorawan_public": true,
+ "clksrc": 1, /* radio_1 provides clock to concentrator */
+ "radio_0": {
+ "enable": true,
+ "type": "SX1257",
+ "freq": 867500000,
+ "rssi_offset": -166.0,
+ "tx_enable": false
+ },
+ "radio_1": {
+ "enable": true,
+ "type": "SX1257",
+ "freq": 868500000,
+ "rssi_offset": -166.0,
+ "tx_enable": false
+ },
+ "chan_multiSF_0": {
+ /* Lora MAC channel, 125kHz, all SF, 868.1 MHz */
+ "enable": true,
+ "radio": 1,
+ "if": -400000
+ },
+ "chan_multiSF_1": {
+ /* Lora MAC channel, 125kHz, all SF, 868.3 MHz */
+ "enable": true,
+ "radio": 1,
+ "if": -200000
+ },
+ "chan_multiSF_2": {
+ /* Lora MAC channel, 125kHz, all SF, 868.5 MHz */
+ "enable": true,
+ "radio": 1,
+ "if": 0
+ },
+ "chan_multiSF_3": {
+ /* Lora MAC channel, 125kHz, all SF, 867.1 MHz */
+ "enable": true,
+ "radio": 0,
+ "if": -400000
+ },
+ "chan_multiSF_4": {
+ /* Lora MAC channel, 125kHz, all SF, 867.3 MHz */
+ "enable": true,
+ "radio": 0,
+ "if": -200000
+ },
+ "chan_multiSF_5": {
+ /* Lora MAC channel, 125kHz, all SF, 867.5 MHz */
+ "enable": true,
+ "radio": 0,
+ "if": 0
+ },
+ "chan_multiSF_6": {
+ /* Lora MAC channel, 125kHz, all SF, 867.7 MHz */
+ "enable": true,
+ "radio": 0,
+ "if": 200000
+ },
+ "chan_multiSF_7": {
+ /* Lora MAC channel, 125kHz, all SF, 867.9 MHz */
+ "enable": true,
+ "radio": 0,
+ "if": 400000
+ },
+ "chan_Lora_std": {
+ /* Lora MAC channel, 250kHz, SF7, 868.3 MHz */
+ "enable": true,
+ "radio": 1,
+ "if": -200000,
+ "bandwidth": 250000,
+ "spread_factor": 7
+ },
+ "chan_FSK": {
+ /* FSK 50kbps channel, 868.8 MHz */
+ "enable": true,
+ "radio": 1,
+ "if": 300000,
+ "bandwidth": 125000,
+ "datarate": 50000
+ }
+ },
+ "gateway_conf": {
+ "gateway_ID": "AA555A0000000000"
+ }
+}
diff --git a/util_pkt_logger/inc/parson.h b/util_pkt_logger/inc/parson.h
new file mode 100644
index 0000000..2669a18
--- /dev/null
+++ b/util_pkt_logger/inc/parson.h
@@ -0,0 +1,222 @@
+/*
+ Parson ( http://kgabis.github.com/parson/ )
+ Copyright (c) 2012 - 2016 Krzysztof Gabis
+
+ 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.
+*/
+
+#ifndef parson_parson_h
+#define parson_parson_h
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <stddef.h> /* size_t */
+
+/* Types and enums */
+typedef struct json_object_t JSON_Object;
+typedef struct json_array_t JSON_Array;
+typedef struct json_value_t JSON_Value;
+
+enum json_value_type {
+ JSONError = -1,
+ JSONNull = 1,
+ JSONString = 2,
+ JSONNumber = 3,
+ JSONObject = 4,
+ JSONArray = 5,
+ JSONBoolean = 6
+};
+typedef int JSON_Value_Type;
+
+enum json_result_t {
+ JSONSuccess = 0,
+ JSONFailure = -1
+};
+typedef int JSON_Status;
+
+typedef void * (*JSON_Malloc_Function)(size_t);
+typedef void (*JSON_Free_Function)(void *);
+
+/* Call only once, before calling any other function from parson API. If not called, malloc and free
+ from stdlib will be used for all allocations */
+void json_set_allocation_functions(JSON_Malloc_Function malloc_fun, JSON_Free_Function free_fun);
+
+/* Parses first JSON value in a file, returns NULL in case of error */
+JSON_Value * json_parse_file(const char *filename);
+
+/* Parses first JSON value in a file and ignores comments (/ * * / and //),
+ returns NULL in case of error */
+JSON_Value * json_parse_file_with_comments(const char *filename);
+
+/* Parses first JSON value in a string, returns NULL in case of error */
+JSON_Value * json_parse_string(const char *string);
+
+/* Parses first JSON value in a string and ignores comments (/ * * / and //),
+ returns NULL in case of error */
+JSON_Value * json_parse_string_with_comments(const char *string);
+
+/* Serialization */
+size_t json_serialization_size(const JSON_Value *value); /* returns 0 on fail */
+JSON_Status json_serialize_to_buffer(const JSON_Value *value, char *buf, size_t buf_size_in_bytes);
+JSON_Status json_serialize_to_file(const JSON_Value *value, const char *filename);
+char * json_serialize_to_string(const JSON_Value *value);
+
+/* Pretty serialization */
+size_t json_serialization_size_pretty(const JSON_Value *value); /* returns 0 on fail */
+JSON_Status json_serialize_to_buffer_pretty(const JSON_Value *value, char *buf, size_t buf_size_in_bytes);
+JSON_Status json_serialize_to_file_pretty(const JSON_Value *value, const char *filename);
+char * json_serialize_to_string_pretty(const JSON_Value *value);
+
+void json_free_serialized_string(char *string); /* frees string from json_serialize_to_string and json_serialize_to_string_pretty */
+
+/* Comparing */
+int json_value_equals(const JSON_Value *a, const JSON_Value *b);
+
+/* Validation
+ This is *NOT* JSON Schema. It validates json by checking if object have identically
+ named fields with matching types.
+ For example schema {"name":"", "age":0} will validate
+ {"name":"Joe", "age":25} and {"name":"Joe", "age":25, "gender":"m"},
+ but not {"name":"Joe"} or {"name":"Joe", "age":"Cucumber"}.
+ In case of arrays, only first value in schema is checked against all values in tested array.
+ Empty objects ({}) validate all objects, empty arrays ([]) validate all arrays,
+ null validates values of every type.
+ */
+JSON_Status json_validate(const JSON_Value *schema, const JSON_Value *value);
+
+/*
+ * JSON Object
+ */
+JSON_Value * json_object_get_value (const JSON_Object *object, const char *name);
+const char * json_object_get_string (const JSON_Object *object, const char *name);
+JSON_Object * json_object_get_object (const JSON_Object *object, const char *name);
+JSON_Array * json_object_get_array (const JSON_Object *object, const char *name);
+double json_object_get_number (const JSON_Object *object, const char *name); /* returns 0 on fail */
+int json_object_get_boolean(const JSON_Object *object, const char *name); /* returns -1 on fail */
+
+/* dotget functions enable addressing values with dot notation in nested objects,
+ just like in structs or c++/java/c# objects (e.g. objectA.objectB.value).
+ Because valid names in JSON can contain dots, some values may be inaccessible
+ this way. */
+JSON_Value * json_object_dotget_value (const JSON_Object *object, const char *name);
+const char * json_object_dotget_string (const JSON_Object *object, const char *name);
+JSON_Object * json_object_dotget_object (const JSON_Object *object, const char *name);
+JSON_Array * json_object_dotget_array (const JSON_Object *object, const char *name);
+double json_object_dotget_number (const JSON_Object *object, const char *name); /* returns 0 on fail */
+int json_object_dotget_boolean(const JSON_Object *object, const char *name); /* returns -1 on fail */
+
+/* Functions to get available names */
+size_t json_object_get_count(const JSON_Object *object);
+const char * json_object_get_name (const JSON_Object *object, size_t index);
+
+/* Creates new name-value pair or frees and replaces old value with a new one.
+ * json_object_set_value does not copy passed value so it shouldn't be freed afterwards. */
+JSON_Status json_object_set_value(JSON_Object *object, const char *name, JSON_Value *value);
+JSON_Status json_object_set_string(JSON_Object *object, const char *name, const char *string);
+JSON_Status json_object_set_number(JSON_Object *object, const char *name, double number);
+JSON_Status json_object_set_boolean(JSON_Object *object, const char *name, int boolean);
+JSON_Status json_object_set_null(JSON_Object *object, const char *name);
+
+/* Works like dotget functions, but creates whole hierarchy if necessary.
+ * json_object_dotset_value does not copy passed value so it shouldn't be freed afterwards. */
+JSON_Status json_object_dotset_value(JSON_Object *object, const char *name, JSON_Value *value);
+JSON_Status json_object_dotset_string(JSON_Object *object, const char *name, const char *string);
+JSON_Status json_object_dotset_number(JSON_Object *object, const char *name, double number);
+JSON_Status json_object_dotset_boolean(JSON_Object *object, const char *name, int boolean);
+JSON_Status json_object_dotset_null(JSON_Object *object, const char *name);
+
+/* Frees and removes name-value pair */
+JSON_Status json_object_remove(JSON_Object *object, const char *name);
+
+/* Works like dotget function, but removes name-value pair only on exact match. */
+JSON_Status json_object_dotremove(JSON_Object *object, const char *key);
+
+/* Removes all name-value pairs in object */
+JSON_Status json_object_clear(JSON_Object *object);
+
+/*
+ *JSON Array
+ */
+JSON_Value * json_array_get_value (const JSON_Array *array, size_t index);
+const char * json_array_get_string (const JSON_Array *array, size_t index);
+JSON_Object * json_array_get_object (const JSON_Array *array, size_t index);
+JSON_Array * json_array_get_array (const JSON_Array *array, size_t index);
+double json_array_get_number (const JSON_Array *array, size_t index); /* returns 0 on fail */
+int json_array_get_boolean(const JSON_Array *array, size_t index); /* returns -1 on fail */
+size_t json_array_get_count (const JSON_Array *array);
+
+/* Frees and removes value at given index, does nothing and returns JSONFailure if index doesn't exist.
+ * Order of values in array may change during execution. */
+JSON_Status json_array_remove(JSON_Array *array, size_t i);
+
+/* Frees and removes from array value at given index and replaces it with given one.
+ * Does nothing and returns JSONFailure if index doesn't exist.
+ * json_array_replace_value does not copy passed value so it shouldn't be freed afterwards. */
+JSON_Status json_array_replace_value(JSON_Array *array, size_t i, JSON_Value *value);
+JSON_Status json_array_replace_string(JSON_Array *array, size_t i, const char* string);
+JSON_Status json_array_replace_number(JSON_Array *array, size_t i, double number);
+JSON_Status json_array_replace_boolean(JSON_Array *array, size_t i, int boolean);
+JSON_Status json_array_replace_null(JSON_Array *array, size_t i);
+
+/* Frees and removes all values from array */
+JSON_Status json_array_clear(JSON_Array *array);
+
+/* Appends new value at the end of array.
+ * json_array_append_value does not copy passed value so it shouldn't be freed afterwards. */
+JSON_Status json_array_append_value(JSON_Array *array, JSON_Value *value);
+JSON_Status json_array_append_string(JSON_Array *array, const char *string);
+JSON_Status json_array_append_number(JSON_Array *array, double number);
+JSON_Status json_array_append_boolean(JSON_Array *array, int boolean);
+JSON_Status json_array_append_null(JSON_Array *array);
+
+/*
+ *JSON Value
+ */
+JSON_Value * json_value_init_object (void);
+JSON_Value * json_value_init_array (void);
+JSON_Value * json_value_init_string (const char *string); /* copies passed string */
+JSON_Value * json_value_init_number (double number);
+JSON_Value * json_value_init_boolean(int boolean);
+JSON_Value * json_value_init_null (void);
+JSON_Value * json_value_deep_copy (const JSON_Value *value);
+void json_value_free (JSON_Value *value);
+
+JSON_Value_Type json_value_get_type (const JSON_Value *value);
+JSON_Object * json_value_get_object (const JSON_Value *value);
+JSON_Array * json_value_get_array (const JSON_Value *value);
+const char * json_value_get_string (const JSON_Value *value);
+double json_value_get_number (const JSON_Value *value);
+int json_value_get_boolean(const JSON_Value *value);
+
+/* Same as above, but shorter */
+JSON_Value_Type json_type (const JSON_Value *value);
+JSON_Object * json_object (const JSON_Value *value);
+JSON_Array * json_array (const JSON_Value *value);
+const char * json_string (const JSON_Value *value);
+double json_number (const JSON_Value *value);
+int json_boolean(const JSON_Value *value);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/util_pkt_logger/local_conf.json b/util_pkt_logger/local_conf.json
new file mode 100644
index 0000000..51fc7c2
--- /dev/null
+++ b/util_pkt_logger/local_conf.json
@@ -0,0 +1,5 @@
+{
+ "gateway_conf": {
+ "gateway_ID": "AA555A0000000101"
+ }
+}
diff --git a/util_pkt_logger/readme.md b/util_pkt_logger/readme.md
new file mode 100644
index 0000000..a980bd4
--- /dev/null
+++ b/util_pkt_logger/readme.md
@@ -0,0 +1,143 @@
+ / _____) _ | |
+ ( (____ _____ ____ _| |_ _____ ____| |__
+ \____ \| ___ | (_ _) ___ |/ ___) _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+ (______/|_____)_|_|_| \__)_____)\____)_| |_|
+ (C)2013 Semtech-Cycleo
+
+LoRa packet logger
+===================
+
+1. Introduction
+----------------
+
+This software is used to set up a LoRa concentrator using a JSON configuration
+file and then record all the packets received in a log file, indefinitely, until
+the user stops the application.
+No filtering is done and all packets that are LoRa packets with the correct RF
+parameters (frequency, datarate, bandwidth) should appear in the log.
+
+2. Dependencies
+----------------
+
+This program uses the Parson library (http://kgabis.github.com/parson/) by
+Krzysztof Gabis for JSON parsing.
+Many thanks to him for that very practical and well written library.
+
+This program is a typical example of LoRa concentrator HAL usage for receiving
+packets.
+
+Only high-level functions are used (the ones contained in loragw_hal) so there
+is no hardware dependencies assuming the HAL is matched with the proper version
+of the hardware.
+Data structures of the received packets are accessed by name (ie. not at a
+binary level) so new functionalities can be added to the API without affecting
+that program at all.
+
+It was tested with v1.3.0 of the libloragw library, and should be compatible
+with any later version of the library assuming the API is downward-compatible.
+
+3. Usage
+---------
+
+To stop the application, press Ctrl+C.
+
+The only optional parameter when launching the application is the log rotation
+time (in seconds).
+
+The way the program takes configuration files into account is the following:
+ * if there is a debug_conf.json parse it, others are ignored
+ * if there is a global_conf.json parse it and look for the next file
+ * if there is a local_conf.json parse it
+If some parameters are defined in both global and local configuration files, the
+local definition overwrites the global definition.
+
+The global configuration file should be exactly the same throughout your
+network, contain all global parameters (parameters for "sensor" radio channels)
+and preferably default "safe" values for parameters that are specific for each
+gateway (eg. specify a default MAC address).
+
+If you have build the libloragw library for a specific radio band (eg. ETSI
+868 MHz band) a ready-to-use global_conf.json file is generated by the Makefile
+with a set of channels typical for a 'LoRa MAC' network application.
+If you don't specify a radio band, an empty global_conf.json is generated and
+must be filled with the settings you need.
+
+The local configuration file should contain parameters that are specific to each
+gateway (eg. MAC address, frequency for backhaul radio channels).
+
+In each configuration file, the program looks for a JSON object named
+"SX1301_conf" that should contain the parameters for the LoRa concentrator board
+(RF channels definition, modem parameters, etc) and another JSON object called
+"gateway_conf" that should contain the gateway parameters (gateway MAC address,
+IP address of the LoRa MAC controller, network authentication parameters, etc).
+
+To learn more about the JSON configuration format, read the provided JSON files
+and the API documentation. A dedicated document will be available later on.
+
+The received packets are put in a CSV file whose name include the MAC address of
+the gateway in hexadecimal format and a UTC timestamp of log starting time in
+ISO 8601 recommended compact format:
+yyyymmddThhmmssZ (eg. 20131009T172345Z for October 9th, 2013 at 5:23:45PM UTC)
+
+To able continuous monitoring, the current log file is closed is closed and a
+new one is opened every hour (by default, rotation interval is settable by the
+user using -r command line option).
+No packet is lost during that rotation of log file.
+Every log file but the current one can then be modified, uploaded and/or deleted
+without any consequence for the program execution.
+
+4. License
+-----------
+
+Copyright (c) 2013, SEMTECH S.A.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+* Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+* Neither the name of the Semtech corporation nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL SEMTECH S.A. BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+5. License for Parson library
+------------------------------
+
+Parson ( http://kgabis.github.com/parson/ )
+Copyright (c) 2012 Krzysztof Gabis
+
+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.
+
+*EOF* \ No newline at end of file
diff --git a/util_pkt_logger/src/parson.c b/util_pkt_logger/src/parson.c
new file mode 100644
index 0000000..16bb158
--- /dev/null
+++ b/util_pkt_logger/src/parson.c
@@ -0,0 +1,1765 @@
+/*
+ Parson ( http://kgabis.github.com/parson/ )
+ Copyright (c) 2012 - 2016 Krzysztof Gabis
+
+ 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.
+*/
+#ifdef _MSC_VER
+#define _CRT_SECURE_NO_WARNINGS
+#endif
+
+#include "parson.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <math.h>
+
+#define STARTING_CAPACITY 15
+#define ARRAY_MAX_CAPACITY 122880 /* 15*(2^13) */
+#define OBJECT_MAX_CAPACITY 960 /* 15*(2^6) */
+#define MAX_NESTING 19
+#define DOUBLE_SERIALIZATION_FORMAT "%f"
+
+#define SIZEOF_TOKEN(a) (sizeof(a) - 1)
+#define SKIP_CHAR(str) ((*str)++)
+#define SKIP_WHITESPACES(str) while (isspace(**str)) { SKIP_CHAR(str); }
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+
+#undef malloc
+#undef free
+
+static JSON_Malloc_Function parson_malloc = malloc;
+static JSON_Free_Function parson_free = free;
+
+#define IS_CONT(b) (((unsigned char)(b) & 0xC0) == 0x80) /* is utf-8 continuation byte */
+
+/* Type definitions */
+typedef union json_value_value {
+ char *string;
+ double number;
+ JSON_Object *object;
+ JSON_Array *array;
+ int boolean;
+ int null;
+} JSON_Value_Value;
+
+struct json_value_t {
+ JSON_Value_Type type;
+ JSON_Value_Value value;
+};
+
+struct json_object_t {
+ char **names;
+ JSON_Value **values;
+ size_t count;
+ size_t capacity;
+};
+
+struct json_array_t {
+ JSON_Value **items;
+ size_t count;
+ size_t capacity;
+};
+
+/* Various */
+static char * read_file(const char *filename);
+static void remove_comments(char *string, const char *start_token, const char *end_token);
+static char * parson_strndup(const char *string, size_t n);
+static char * parson_strdup(const char *string);
+static int is_utf16_hex(const unsigned char *string);
+static int num_bytes_in_utf8_sequence(unsigned char c);
+static int verify_utf8_sequence(const unsigned char *string, int *len);
+static int is_valid_utf8(const char *string, size_t string_len);
+static int is_decimal(const char *string, size_t length);
+
+/* JSON Object */
+static JSON_Object * json_object_init(void);
+static JSON_Status json_object_add(JSON_Object *object, const char *name, JSON_Value *value);
+static JSON_Status json_object_resize(JSON_Object *object, size_t new_capacity);
+static JSON_Value * json_object_nget_value(const JSON_Object *object, const char *name, size_t n);
+static void json_object_free(JSON_Object *object);
+
+/* JSON Array */
+static JSON_Array * json_array_init(void);
+static JSON_Status json_array_add(JSON_Array *array, JSON_Value *value);
+static JSON_Status json_array_resize(JSON_Array *array, size_t new_capacity);
+static void json_array_free(JSON_Array *array);
+
+/* JSON Value */
+static JSON_Value * json_value_init_string_no_copy(char *string);
+
+/* Parser */
+static void skip_quotes(const char **string);
+static int parse_utf_16(const char **unprocessed, char **processed);
+static char * process_string(const char *input, size_t len);
+static char * get_quoted_string(const char **string);
+static JSON_Value * parse_object_value(const char **string, size_t nesting);
+static JSON_Value * parse_array_value(const char **string, size_t nesting);
+static JSON_Value * parse_string_value(const char **string);
+static JSON_Value * parse_boolean_value(const char **string);
+static JSON_Value * parse_number_value(const char **string);
+static JSON_Value * parse_null_value(const char **string);
+static JSON_Value * parse_value(const char **string, size_t nesting);
+
+/* Serialization */
+static int json_serialize_to_buffer_r(const JSON_Value *value, char *buf, int level, int is_pretty, char *num_buf);
+static int json_serialize_string(const char *string, char *buf);
+static int append_indent(char *buf, int level);
+static int append_string(char *buf, const char *string);
+
+/* Various */
+static char * parson_strndup(const char *string, size_t n) {
+ char *output_string = (char*)parson_malloc(n + 1);
+ if (!output_string)
+ return NULL;
+ output_string[n] = '\0';
+ strncpy(output_string, string, n);
+ return output_string;
+}
+
+static char * parson_strdup(const char *string) {
+ return parson_strndup(string, strlen(string));
+}
+
+static int is_utf16_hex(const unsigned char *s) {
+ return isxdigit(s[0]) && isxdigit(s[1]) && isxdigit(s[2]) && isxdigit(s[3]);
+}
+
+static int num_bytes_in_utf8_sequence(unsigned char c) {
+ if (c == 0xC0 || c == 0xC1 || c > 0xF4 || IS_CONT(c)) {
+ return 0;
+ } else if ((c & 0x80) == 0) { /* 0xxxxxxx */
+ return 1;
+ } else if ((c & 0xE0) == 0xC0) { /* 110xxxxx */
+ return 2;
+ } else if ((c & 0xF0) == 0xE0) { /* 1110xxxx */
+ return 3;
+ } else if ((c & 0xF8) == 0xF0) { /* 11110xxx */
+ return 4;
+ }
+ return 0; /* won't happen */
+}
+
+static int verify_utf8_sequence(const unsigned char *string, int *len) {
+ unsigned int cp = 0;
+ *len = num_bytes_in_utf8_sequence(string[0]);
+
+ if (*len == 1) {
+ cp = string[0];
+ } else if (*len == 2 && IS_CONT(string[1])) {
+ cp = string[0] & 0x1F;
+ cp = (cp << 6) | (string[1] & 0x3F);
+ } else if (*len == 3 && IS_CONT(string[1]) && IS_CONT(string[2])) {
+ cp = ((unsigned char)string[0]) & 0xF;
+ cp = (cp << 6) | (string[1] & 0x3F);
+ cp = (cp << 6) | (string[2] & 0x3F);
+ } else if (*len == 4 && IS_CONT(string[1]) && IS_CONT(string[2]) && IS_CONT(string[3])) {
+ cp = string[0] & 0x7;
+ cp = (cp << 6) | (string[1] & 0x3F);
+ cp = (cp << 6) | (string[2] & 0x3F);
+ cp = (cp << 6) | (string[3] & 0x3F);
+ } else {
+ return 0;
+ }
+
+ /* overlong encodings */
+ if ((cp < 0x80 && *len > 1) ||
+ (cp < 0x800 && *len > 2) ||
+ (cp < 0x10000 && *len > 3)) {
+ return 0;
+ }
+
+ /* invalid unicode */
+ if (cp > 0x10FFFF) {
+ return 0;
+ }
+
+ /* surrogate halves */
+ if (cp >= 0xD800 && cp <= 0xDFFF) {
+ return 0;
+ }
+
+ return 1;
+}
+
+static int is_valid_utf8(const char *string, size_t string_len) {
+ int len = 0;
+ const char *string_end = string + string_len;
+ while (string < string_end) {
+ if (!verify_utf8_sequence((const unsigned char*)string, &len)) {
+ return 0;
+ }
+ string += len;
+ }
+ return 1;
+}
+
+static int is_decimal(const char *string, size_t length) {
+ if (length > 1 && string[0] == '0' && string[1] != '.')
+ return 0;
+ if (length > 2 && !strncmp(string, "-0", 2) && string[2] != '.')
+ return 0;
+ while (length--)
+ if (strchr("xX", string[length]))
+ return 0;
+ return 1;
+}
+
+static char * read_file(const char * filename) {
+ FILE *fp = fopen(filename, "r");
+ size_t file_size;
+ long pos;
+ char *file_contents;
+ if (!fp)
+ return NULL;
+ fseek(fp, 0L, SEEK_END);
+ pos = ftell(fp);
+ if (pos < 0) {
+ fclose(fp);
+ return NULL;
+ }
+ file_size = pos;
+ rewind(fp);
+ file_contents = (char*)parson_malloc(sizeof(char) * (file_size + 1));
+ if (!file_contents) {
+ fclose(fp);
+ return NULL;
+ }
+ if (fread(file_contents, file_size, 1, fp) < 1) {
+ if (ferror(fp)) {
+ fclose(fp);
+ parson_free(file_contents);
+ return NULL;
+ }
+ }
+ fclose(fp);
+ file_contents[file_size] = '\0';
+ return file_contents;
+}
+
+static void remove_comments(char *string, const char *start_token, const char *end_token) {
+ int in_string = 0, escaped = 0;
+ size_t i;
+ char *ptr = NULL, current_char;
+ size_t start_token_len = strlen(start_token);
+ size_t end_token_len = strlen(end_token);
+ if (start_token_len == 0 || end_token_len == 0)
+ return;
+ while ((current_char = *string) != '\0') {
+ if (current_char == '\\' && !escaped) {
+ escaped = 1;
+ string++;
+ continue;
+ } else if (current_char == '\"' && !escaped) {
+ in_string = !in_string;
+ } else if (!in_string && strncmp(string, start_token, start_token_len) == 0) {
+ for(i = 0; i < start_token_len; i++)
+ string[i] = ' ';
+ string = string + start_token_len;
+ ptr = strstr(string, end_token);
+ if (!ptr)
+ return;
+ for (i = 0; i < (ptr - string) + end_token_len; i++)
+ string[i] = ' ';
+ string = ptr + end_token_len - 1;
+ }
+ escaped = 0;
+ string++;
+ }
+}
+
+/* JSON Object */
+static JSON_Object * json_object_init(void) {
+ JSON_Object *new_obj = (JSON_Object*)parson_malloc(sizeof(JSON_Object));
+ if (!new_obj)
+ return NULL;
+ new_obj->names = (char**)NULL;
+ new_obj->values = (JSON_Value**)NULL;
+ new_obj->capacity = 0;
+ new_obj->count = 0;
+ return new_obj;
+}
+
+static JSON_Status json_object_add(JSON_Object *object, const char *name, JSON_Value *value) {
+ size_t index = 0;
+ if (object == NULL || name == NULL || value == NULL) {
+ return JSONFailure;
+ }
+ if (object->count >= object->capacity) {
+ size_t new_capacity = MAX(object->capacity * 2, STARTING_CAPACITY);
+ if (new_capacity > OBJECT_MAX_CAPACITY)
+ return JSONFailure;
+ if (json_object_resize(object, new_capacity) == JSONFailure)
+ return JSONFailure;
+ }
+ if (json_object_get_value(object, name) != NULL)
+ return JSONFailure;
+ index = object->count;
+ object->names[index] = parson_strdup(name);
+ if (object->names[index] == NULL)
+ return JSONFailure;
+ object->values[index] = value;
+ object->count++;
+ return JSONSuccess;
+}
+
+static JSON_Status json_object_resize(JSON_Object *object, size_t new_capacity) {
+ char **temp_names = NULL;
+ JSON_Value **temp_values = NULL;
+
+ if ((object->names == NULL && object->values != NULL) ||
+ (object->names != NULL && object->values == NULL) ||
+ new_capacity == 0) {
+ return JSONFailure; /* Shouldn't happen */
+ }
+
+ temp_names = (char**)parson_malloc(new_capacity * sizeof(char*));
+ if (temp_names == NULL)
+ return JSONFailure;
+
+ temp_values = (JSON_Value**)parson_malloc(new_capacity * sizeof(JSON_Value*));
+ if (temp_values == NULL) {
+ parson_free(temp_names);
+ return JSONFailure;
+ }
+
+ if (object->names != NULL && object->values != NULL && object->count > 0) {
+ memcpy(temp_names, object->names, object->count * sizeof(char*));
+ memcpy(temp_values, object->values, object->count * sizeof(JSON_Value*));
+ }
+ parson_free(object->names);
+ parson_free(object->values);
+ object->names = temp_names;
+ object->values = temp_values;
+ object->capacity = new_capacity;
+ return JSONSuccess;
+}
+
+static JSON_Value * json_object_nget_value(const JSON_Object *object, const char *name, size_t n) {
+ size_t i, name_length;
+ for (i = 0; i < json_object_get_count(object); i++) {
+ name_length = strlen(object->names[i]);
+ if (name_length != n)
+ continue;
+ if (strncmp(object->names[i], name, n) == 0)
+ return object->values[i];
+ }
+ return NULL;
+}
+
+static void json_object_free(JSON_Object *object) {
+ while(object->count--) {
+ parson_free(object->names[object->count]);
+ json_value_free(object->values[object->count]);
+ }
+ parson_free(object->names);
+ parson_free(object->values);
+ parson_free(object);
+}
+
+/* JSON Array */
+static JSON_Array * json_array_init(void) {
+ JSON_Array *new_array = (JSON_Array*)parson_malloc(sizeof(JSON_Array));
+ if (!new_array)
+ return NULL;
+ new_array->items = (JSON_Value**)NULL;
+ new_array->capacity = 0;
+ new_array->count = 0;
+ return new_array;
+}
+
+static JSON_Status json_array_add(JSON_Array *array, JSON_Value *value) {
+ if (array->count >= array->capacity) {
+ size_t new_capacity = MAX(array->capacity * 2, STARTING_CAPACITY);
+ if (new_capacity > ARRAY_MAX_CAPACITY)
+ return JSONFailure;
+ if (json_array_resize(array, new_capacity) == JSONFailure)
+ return JSONFailure;
+ }
+ array->items[array->count] = value;
+ array->count++;
+ return JSONSuccess;
+}
+
+static JSON_Status json_array_resize(JSON_Array *array, size_t new_capacity) {
+ JSON_Value **new_items = NULL;
+ if (new_capacity == 0) {
+ return JSONFailure;
+ }
+ new_items = (JSON_Value**)parson_malloc(new_capacity * sizeof(JSON_Value*));
+ if (new_items == NULL) {
+ return JSONFailure;
+ }
+ if (array->items != NULL && array->count > 0) {
+ memcpy(new_items, array->items, array->count * sizeof(JSON_Value*));
+ }
+ parson_free(array->items);
+ array->items = new_items;
+ array->capacity = new_capacity;
+ return JSONSuccess;
+}
+
+static void json_array_free(JSON_Array *array) {
+ while (array->count--)
+ json_value_free(array->items[array->count]);
+ parson_free(array->items);
+ parson_free(array);
+}
+
+/* JSON Value */
+static JSON_Value * json_value_init_string_no_copy(char *string) {
+ JSON_Value *new_value = (JSON_Value*)parson_malloc(sizeof(JSON_Value));
+ if (!new_value)
+ return NULL;
+ new_value->type = JSONString;
+ new_value->value.string = string;
+ return new_value;
+}
+
+/* Parser */
+static void skip_quotes(const char **string) {
+ SKIP_CHAR(string);
+ while (**string != '\"') {
+ if (**string == '\0')
+ return;
+ if (**string == '\\') {
+ SKIP_CHAR(string);
+ if (**string == '\0')
+ return;
+ }
+ SKIP_CHAR(string);
+ }
+ SKIP_CHAR(string);
+}
+
+static int parse_utf_16(const char **unprocessed, char **processed) {
+ unsigned int cp, lead, trail;
+ char *processed_ptr = *processed;
+ const char *unprocessed_ptr = *unprocessed;
+ unprocessed_ptr++; /* skips u */
+ if (!is_utf16_hex((const unsigned char*)unprocessed_ptr) || sscanf(unprocessed_ptr, "%4x", &cp) == EOF)
+ return JSONFailure;
+ if (cp < 0x80) {
+ *processed_ptr = cp; /* 0xxxxxxx */
+ } else if (cp < 0x800) {
+ *processed_ptr++ = ((cp >> 6) & 0x1F) | 0xC0; /* 110xxxxx */
+ *processed_ptr = ((cp ) & 0x3F) | 0x80; /* 10xxxxxx */
+ } else if (cp < 0xD800 || cp > 0xDFFF) {
+ *processed_ptr++ = ((cp >> 12) & 0x0F) | 0xE0; /* 1110xxxx */
+ *processed_ptr++ = ((cp >> 6) & 0x3F) | 0x80; /* 10xxxxxx */
+ *processed_ptr = ((cp ) & 0x3F) | 0x80; /* 10xxxxxx */
+ } else if (cp >= 0xD800 && cp <= 0xDBFF) { /* lead surrogate (0xD800..0xDBFF) */
+ lead = cp;
+ unprocessed_ptr += 4; /* should always be within the buffer, otherwise previous sscanf would fail */
+ if (*unprocessed_ptr++ != '\\' || *unprocessed_ptr++ != 'u' || /* starts with \u? */
+ !is_utf16_hex((const unsigned char*)unprocessed_ptr) ||
+ sscanf(unprocessed_ptr, "%4x", &trail) == EOF ||
+ trail < 0xDC00 || trail > 0xDFFF) { /* valid trail surrogate? (0xDC00..0xDFFF) */
+ return JSONFailure;
+ }
+ cp = ((((lead-0xD800)&0x3FF)<<10)|((trail-0xDC00)&0x3FF))+0x010000;
+ *processed_ptr++ = (((cp >> 18) & 0x07) | 0xF0); /* 11110xxx */
+ *processed_ptr++ = (((cp >> 12) & 0x3F) | 0x80); /* 10xxxxxx */
+ *processed_ptr++ = (((cp >> 6) & 0x3F) | 0x80); /* 10xxxxxx */
+ *processed_ptr = (((cp ) & 0x3F) | 0x80); /* 10xxxxxx */
+ } else { /* trail surrogate before lead surrogate */
+ return JSONFailure;
+ }
+ unprocessed_ptr += 3;
+ *processed = processed_ptr;
+ *unprocessed = unprocessed_ptr;
+ return JSONSuccess;
+}
+
+
+/* Copies and processes passed string up to supplied length.
+Example: "\u006Corem ipsum" -> lorem ipsum */
+static char* process_string(const char *input, size_t len) {
+ const char *input_ptr = input;
+ size_t initial_size = (len + 1) * sizeof(char);
+ size_t final_size = 0;
+ char *output = (char*)parson_malloc(initial_size);
+ char *output_ptr = output;
+ char *resized_output = NULL;
+ while ((*input_ptr != '\0') && (size_t)(input_ptr - input) < len) {
+ if (*input_ptr == '\\') {
+ input_ptr++;
+ switch (*input_ptr) {
+ case '\"': *output_ptr = '\"'; break;
+ case '\\': *output_ptr = '\\'; break;
+ case '/': *output_ptr = '/'; break;
+ case 'b': *output_ptr = '\b'; break;
+ case 'f': *output_ptr = '\f'; break;
+ case 'n': *output_ptr = '\n'; break;
+ case 'r': *output_ptr = '\r'; break;
+ case 't': *output_ptr = '\t'; break;
+ case 'u':
+ if (parse_utf_16(&input_ptr, &output_ptr) == JSONFailure)
+ goto error;
+ break;
+ default:
+ goto error;
+ }
+ } else if ((unsigned char)*input_ptr < 0x20) {
+ goto error; /* 0x00-0x19 are invalid characters for json string (http://www.ietf.org/rfc/rfc4627.txt) */
+ } else {
+ *output_ptr = *input_ptr;
+ }
+ output_ptr++;
+ input_ptr++;
+ }
+ *output_ptr = '\0';
+ /* resize to new length */
+ final_size = (size_t)(output_ptr-output) + 1;
+ resized_output = (char*)parson_malloc(final_size);
+ if (resized_output == NULL)
+ goto error;
+ memcpy(resized_output, output, final_size);
+ parson_free(output);
+ return resized_output;
+error:
+ parson_free(output);
+ return NULL;
+}
+
+/* Return processed contents of a string between quotes and
+ skips passed argument to a matching quote. */
+static char * get_quoted_string(const char **string) {
+ const char *string_start = *string;
+ size_t string_len = 0;
+ skip_quotes(string);
+ if (**string == '\0')
+ return NULL;
+ string_len = *string - string_start - 2; /* length without quotes */
+ return process_string(string_start + 1, string_len);
+}
+
+static JSON_Value * parse_value(const char **string, size_t nesting) {
+ if (nesting > MAX_NESTING)
+ return NULL;
+ SKIP_WHITESPACES(string);
+ switch (**string) {
+ case '{':
+ return parse_object_value(string, nesting + 1);
+ case '[':
+ return parse_array_value(string, nesting + 1);
+ case '\"':
+ return parse_string_value(string);
+ case 'f': case 't':
+ return parse_boolean_value(string);
+ case '-':
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ return parse_number_value(string);
+ case 'n':
+ return parse_null_value(string);
+ default:
+ return NULL;
+ }
+}
+
+static JSON_Value * parse_object_value(const char **string, size_t nesting) {
+ JSON_Value *output_value = json_value_init_object(), *new_value = NULL;
+ JSON_Object *output_object = json_value_get_object(output_value);
+ char *new_key = NULL;
+ if (output_value == NULL)
+ return NULL;
+ SKIP_CHAR(string);
+ SKIP_WHITESPACES(string);
+ if (**string == '}') { /* empty object */
+ SKIP_CHAR(string);
+ return output_value;
+ }
+ while (**string != '\0') {
+ new_key = get_quoted_string(string);
+ SKIP_WHITESPACES(string);
+ if (new_key == NULL || **string != ':') {
+ json_value_free(output_value);
+ return NULL;
+ }
+ SKIP_CHAR(string);
+ new_value = parse_value(string, nesting);
+ if (new_value == NULL) {
+ parson_free(new_key);
+ json_value_free(output_value);
+ return NULL;
+ }
+ if(json_object_add(output_object, new_key, new_value) == JSONFailure) {
+ parson_free(new_key);
+ parson_free(new_value);
+ json_value_free(output_value);
+ return NULL;
+ }
+ parson_free(new_key);
+ SKIP_WHITESPACES(string);
+ if (**string != ',')
+ break;
+ SKIP_CHAR(string);
+ SKIP_WHITESPACES(string);
+ }
+ SKIP_WHITESPACES(string);
+ if (**string != '}' || /* Trim object after parsing is over */
+ json_object_resize(output_object, json_object_get_count(output_object)) == JSONFailure) {
+ json_value_free(output_value);
+ return NULL;
+ }
+ SKIP_CHAR(string);
+ return output_value;
+}
+
+static JSON_Value * parse_array_value(const char **string, size_t nesting) {
+ JSON_Value *output_value = json_value_init_array(), *new_array_value = NULL;
+ JSON_Array *output_array = json_value_get_array(output_value);
+ if (!output_value)
+ return NULL;
+ SKIP_CHAR(string);
+ SKIP_WHITESPACES(string);
+ if (**string == ']') { /* empty array */
+ SKIP_CHAR(string);
+ return output_value;
+ }
+ while (**string != '\0') {
+ new_array_value = parse_value(string, nesting);
+ if (!new_array_value) {
+ json_value_free(output_value);
+ return NULL;
+ }
+ if(json_array_add(output_array, new_array_value) == JSONFailure) {
+ parson_free(new_array_value);
+ json_value_free(output_value);
+ return NULL;
+ }
+ SKIP_WHITESPACES(string);
+ if (**string != ',')
+ break;
+ SKIP_CHAR(string);
+ SKIP_WHITESPACES(string);
+ }
+ SKIP_WHITESPACES(string);
+ if (**string != ']' || /* Trim array after parsing is over */
+ json_array_resize(output_array, json_array_get_count(output_array)) == JSONFailure) {
+ json_value_free(output_value);
+ return NULL;
+ }
+ SKIP_CHAR(string);
+ return output_value;
+}
+
+static JSON_Value * parse_string_value(const char **string) {
+ JSON_Value *value = NULL;
+ char *new_string = get_quoted_string(string);
+ if (new_string == NULL)
+ return NULL;
+ value = json_value_init_string_no_copy(new_string);
+ if (value == NULL) {
+ parson_free(new_string);
+ return NULL;
+ }
+ return value;
+}
+
+static JSON_Value * parse_boolean_value(const char **string) {
+ size_t true_token_size = SIZEOF_TOKEN("true");
+ size_t false_token_size = SIZEOF_TOKEN("false");
+ if (strncmp("true", *string, true_token_size) == 0) {
+ *string += true_token_size;
+ return json_value_init_boolean(1);
+ } else if (strncmp("false", *string, false_token_size) == 0) {
+ *string += false_token_size;
+ return json_value_init_boolean(0);
+ }
+ return NULL;
+}
+
+static JSON_Value * parse_number_value(const char **string) {
+ char *end;
+ double number = strtod(*string, &end);
+ JSON_Value *output_value;
+ if (is_decimal(*string, end - *string)) {
+ *string = end;
+ output_value = json_value_init_number(number);
+ } else {
+ output_value = NULL;
+ }
+ return output_value;
+}
+
+static JSON_Value * parse_null_value(const char **string) {
+ size_t token_size = SIZEOF_TOKEN("null");
+ if (strncmp("null", *string, token_size) == 0) {
+ *string += token_size;
+ return json_value_init_null();
+ }
+ return NULL;
+}
+
+/* Serialization */
+#define APPEND_STRING(str) do { written = append_string(buf, (str)); \
+ if (written < 0) { return -1; } \
+ if (buf != NULL) { buf += written; } \
+ written_total += written; } while(0)
+
+#define APPEND_INDENT(level) do { written = append_indent(buf, (level)); \
+ if (written < 0) { return -1; } \
+ if (buf != NULL) { buf += written; } \
+ written_total += written; } while(0)
+
+static int json_serialize_to_buffer_r(const JSON_Value *value, char *buf, int level, int is_pretty, char *num_buf)
+{
+ const char *key = NULL, *string = NULL;
+ JSON_Value *temp_value = NULL;
+ JSON_Array *array = NULL;
+ JSON_Object *object = NULL;
+ size_t i = 0, count = 0;
+ double num = 0.0;
+ int written = -1, written_total = 0;
+
+ switch (json_value_get_type(value)) {
+ case JSONArray:
+ array = json_value_get_array(value);
+ count = json_array_get_count(array);
+ APPEND_STRING("[");
+ if (count > 0 && is_pretty)
+ APPEND_STRING("\n");
+ for (i = 0; i < count; i++) {
+ if (is_pretty)
+ APPEND_INDENT(level+1);
+ temp_value = json_array_get_value(array, i);
+ written = json_serialize_to_buffer_r(temp_value, buf, level+1, is_pretty, num_buf);
+ if (written < 0)
+ return -1;
+ if (buf != NULL)
+ buf += written;
+ written_total += written;
+ if (i < (count - 1))
+ APPEND_STRING(",");
+ if (is_pretty)
+ APPEND_STRING("\n");
+ }
+ if (count > 0 && is_pretty)
+ APPEND_INDENT(level);
+ APPEND_STRING("]");
+ return written_total;
+ case JSONObject:
+ object = json_value_get_object(value);
+ count = json_object_get_count(object);
+ APPEND_STRING("{");
+ if (count > 0 && is_pretty)
+ APPEND_STRING("\n");
+ for (i = 0; i < count; i++) {
+ key = json_object_get_name(object, i);
+ if (is_pretty)
+ APPEND_INDENT(level+1);
+ written = json_serialize_string(key, buf);
+ if (written < 0)
+ return -1;
+ if (buf != NULL)
+ buf += written;
+ written_total += written;
+ APPEND_STRING(":");
+ if (is_pretty)
+ APPEND_STRING(" ");
+ temp_value = json_object_get_value(object, key);
+ written = json_serialize_to_buffer_r(temp_value, buf, level+1, is_pretty, num_buf);
+ if (written < 0)
+ return -1;
+ if (buf != NULL)
+ buf += written;
+ written_total += written;
+ if (i < (count - 1))
+ APPEND_STRING(",");
+ if (is_pretty)
+ APPEND_STRING("\n");
+ }
+ if (count > 0 && is_pretty)
+ APPEND_INDENT(level);
+ APPEND_STRING("}");
+ return written_total;
+ case JSONString:
+ string = json_value_get_string(value);
+ written = json_serialize_string(string, buf);
+ if (written < 0)
+ return -1;
+ if (buf != NULL)
+ buf += written;
+ written_total += written;
+ return written_total;
+ case JSONBoolean:
+ if (json_value_get_boolean(value))
+ APPEND_STRING("true");
+ else
+ APPEND_STRING("false");
+ return written_total;
+ case JSONNumber:
+ num = json_value_get_number(value);
+ if (buf != NULL)
+ num_buf = buf;
+ if (num == ((double)(int)num)) /* check if num is integer */
+ written = sprintf(num_buf, "%d", (int)num);
+ else
+ written = sprintf(num_buf, DOUBLE_SERIALIZATION_FORMAT, num);
+ if (written < 0)
+ return -1;
+ if (buf != NULL)
+ buf += written;
+ written_total += written;
+ return written_total;
+ case JSONNull:
+ APPEND_STRING("null");
+ return written_total;
+ case JSONError:
+ return -1;
+ default:
+ return -1;
+ }
+}
+
+static int json_serialize_string(const char *string, char *buf) {
+ size_t i = 0, len = strlen(string);
+ char c = '\0';
+ int written = -1, written_total = 0;
+ APPEND_STRING("\"");
+ for (i = 0; i < len; i++) {
+ c = string[i];
+ switch (c) {
+ case '\"': APPEND_STRING("\\\""); break;
+ case '\\': APPEND_STRING("\\\\"); break;
+ case '/': APPEND_STRING("\\/"); break; /* to make json embeddable in xml\/html */
+ case '\b': APPEND_STRING("\\b"); break;
+ case '\f': APPEND_STRING("\\f"); break;
+ case '\n': APPEND_STRING("\\n"); break;
+ case '\r': APPEND_STRING("\\r"); break;
+ case '\t': APPEND_STRING("\\t"); break;
+ default:
+ if (buf != NULL) {
+ buf[0] = c;
+ buf += 1;
+ }
+ written_total += 1;
+ break;
+ }
+ }
+ APPEND_STRING("\"");
+ return written_total;
+}
+
+static int append_indent(char *buf, int level) {
+ int i;
+ int written = -1, written_total = 0;
+ for (i = 0; i < level; i++) {
+ APPEND_STRING(" ");
+ }
+ return written_total;
+}
+
+static int append_string(char *buf, const char *string) {
+ if (buf == NULL) {
+ return (int)strlen(string);
+ }
+ return sprintf(buf, "%s", string);
+}
+
+#undef APPEND_STRING
+#undef APPEND_INDENT
+
+/* Parser API */
+JSON_Value * json_parse_file(const char *filename) {
+ char *file_contents = read_file(filename);
+ JSON_Value *output_value = NULL;
+ if (file_contents == NULL)
+ return NULL;
+ output_value = json_parse_string(file_contents);
+ parson_free(file_contents);
+ return output_value;
+}
+
+JSON_Value * json_parse_file_with_comments(const char *filename) {
+ char *file_contents = read_file(filename);
+ JSON_Value *output_value = NULL;
+ if (file_contents == NULL)
+ return NULL;
+ output_value = json_parse_string_with_comments(file_contents);
+ parson_free(file_contents);
+ return output_value;
+}
+
+JSON_Value * json_parse_string(const char *string) {
+ if (string == NULL)
+ return NULL;
+ SKIP_WHITESPACES(&string);
+ if (*string != '{' && *string != '[')
+ return NULL;
+ return parse_value((const char**)&string, 0);
+}
+
+JSON_Value * json_parse_string_with_comments(const char *string) {
+ JSON_Value *result = NULL;
+ char *string_mutable_copy = NULL, *string_mutable_copy_ptr = NULL;
+ string_mutable_copy = parson_strdup(string);
+ if (string_mutable_copy == NULL)
+ return NULL;
+ remove_comments(string_mutable_copy, "/*", "*/");
+ remove_comments(string_mutable_copy, "//", "\n");
+ string_mutable_copy_ptr = string_mutable_copy;
+ SKIP_WHITESPACES(&string_mutable_copy_ptr);
+ if (*string_mutable_copy_ptr != '{' && *string_mutable_copy_ptr != '[') {
+ parson_free(string_mutable_copy);
+ return NULL;
+ }
+ result = parse_value((const char**)&string_mutable_copy_ptr, 0);
+ parson_free(string_mutable_copy);
+ return result;
+}
+
+
+/* JSON Object API */
+
+JSON_Value * json_object_get_value(const JSON_Object *object, const char *name) {
+ if (object == NULL || name == NULL)
+ return NULL;
+ return json_object_nget_value(object, name, strlen(name));
+}
+
+const char * json_object_get_string(const JSON_Object *object, const char *name) {
+ return json_value_get_string(json_object_get_value(object, name));
+}
+
+double json_object_get_number(const JSON_Object *object, const char *name) {
+ return json_value_get_number(json_object_get_value(object, name));
+}
+
+JSON_Object * json_object_get_object(const JSON_Object *object, const char *name) {
+ return json_value_get_object(json_object_get_value(object, name));
+}
+
+JSON_Array * json_object_get_array(const JSON_Object *object, const char *name) {
+ return json_value_get_array(json_object_get_value(object, name));
+}
+
+int json_object_get_boolean(const JSON_Object *object, const char *name) {
+ return json_value_get_boolean(json_object_get_value(object, name));
+}
+
+JSON_Value * json_object_dotget_value(const JSON_Object *object, const char *name) {
+ const char *dot_position = strchr(name, '.');
+ if (!dot_position)
+ return json_object_get_value(object, name);
+ object = json_value_get_object(json_object_nget_value(object, name, dot_position - name));
+ return json_object_dotget_value(object, dot_position + 1);
+}
+
+const char * json_object_dotget_string(const JSON_Object *object, const char *name) {
+ return json_value_get_string(json_object_dotget_value(object, name));
+}
+
+double json_object_dotget_number(const JSON_Object *object, const char *name) {
+ return json_value_get_number(json_object_dotget_value(object, name));
+}
+
+JSON_Object * json_object_dotget_object(const JSON_Object *object, const char *name) {
+ return json_value_get_object(json_object_dotget_value(object, name));
+}
+
+JSON_Array * json_object_dotget_array(const JSON_Object *object, const char *name) {
+ return json_value_get_array(json_object_dotget_value(object, name));
+}
+
+int json_object_dotget_boolean(const JSON_Object *object, const char *name) {
+ return json_value_get_boolean(json_object_dotget_value(object, name));
+}
+
+size_t json_object_get_count(const JSON_Object *object) {
+ return object ? object->count : 0;
+}
+
+const char * json_object_get_name(const JSON_Object *object, size_t index) {
+ if (index >= json_object_get_count(object))
+ return NULL;
+ return object->names[index];
+}
+
+/* JSON Array API */
+JSON_Value * json_array_get_value(const JSON_Array *array, size_t index) {
+ if (index >= json_array_get_count(array))
+ return NULL;
+ return array->items[index];
+}
+
+const char * json_array_get_string(const JSON_Array *array, size_t index) {
+ return json_value_get_string(json_array_get_value(array, index));
+}
+
+double json_array_get_number(const JSON_Array *array, size_t index) {
+ return json_value_get_number(json_array_get_value(array, index));
+}
+
+JSON_Object * json_array_get_object(const JSON_Array *array, size_t index) {
+ return json_value_get_object(json_array_get_value(array, index));
+}
+
+JSON_Array * json_array_get_array(const JSON_Array *array, size_t index) {
+ return json_value_get_array(json_array_get_value(array, index));
+}
+
+int json_array_get_boolean(const JSON_Array *array, size_t index) {
+ return json_value_get_boolean(json_array_get_value(array, index));
+}
+
+size_t json_array_get_count(const JSON_Array *array) {
+ return array ? array->count : 0;
+}
+
+/* JSON Value API */
+JSON_Value_Type json_value_get_type(const JSON_Value *value) {
+ return value ? value->type : JSONError;
+}
+
+JSON_Object * json_value_get_object(const JSON_Value *value) {
+ return json_value_get_type(value) == JSONObject ? value->value.object : NULL;
+}
+
+JSON_Array * json_value_get_array(const JSON_Value *value) {
+ return json_value_get_type(value) == JSONArray ? value->value.array : NULL;
+}
+
+const char * json_value_get_string(const JSON_Value *value) {
+ return json_value_get_type(value) == JSONString ? value->value.string : NULL;
+}
+
+double json_value_get_number(const JSON_Value *value) {
+ return json_value_get_type(value) == JSONNumber ? value->value.number : 0;
+}
+
+int json_value_get_boolean(const JSON_Value *value) {
+ return json_value_get_type(value) == JSONBoolean ? value->value.boolean : -1;
+}
+
+void json_value_free(JSON_Value *value) {
+ switch (json_value_get_type(value)) {
+ case JSONObject:
+ json_object_free(value->value.object);
+ break;
+ case JSONString:
+ if (value->value.string) { parson_free(value->value.string); }
+ break;
+ case JSONArray:
+ json_array_free(value->value.array);
+ break;
+ default:
+ break;
+ }
+ parson_free(value);
+}
+
+JSON_Value * json_value_init_object(void) {
+ JSON_Value *new_value = (JSON_Value*)parson_malloc(sizeof(JSON_Value));
+ if (!new_value)
+ return NULL;
+ new_value->type = JSONObject;
+ new_value->value.object = json_object_init();
+ if (!new_value->value.object) {
+ parson_free(new_value);
+ return NULL;
+ }
+ return new_value;
+}
+
+JSON_Value * json_value_init_array(void) {
+ JSON_Value *new_value = (JSON_Value*)parson_malloc(sizeof(JSON_Value));
+ if (!new_value)
+ return NULL;
+ new_value->type = JSONArray;
+ new_value->value.array = json_array_init();
+ if (!new_value->value.array) {
+ parson_free(new_value);
+ return NULL;
+ }
+ return new_value;
+}
+
+JSON_Value * json_value_init_string(const char *string) {
+ char *copy = NULL;
+ JSON_Value *value;
+ size_t string_len = 0;
+ if (string == NULL)
+ return NULL;
+ string_len = strlen(string);
+ if (!is_valid_utf8(string, string_len))
+ return NULL;
+ copy = parson_strndup(string, string_len);
+ if (copy == NULL)
+ return NULL;
+ value = json_value_init_string_no_copy(copy);
+ if (value == NULL)
+ parson_free(copy);
+ return value;
+}
+
+JSON_Value * json_value_init_number(double number) {
+ JSON_Value *new_value = (JSON_Value*)parson_malloc(sizeof(JSON_Value));
+ if (!new_value)
+ return NULL;
+ new_value->type = JSONNumber;
+ new_value->value.number = number;
+ return new_value;
+}
+
+JSON_Value * json_value_init_boolean(int boolean) {
+ JSON_Value *new_value = (JSON_Value*)parson_malloc(sizeof(JSON_Value));
+ if (!new_value)
+ return NULL;
+ new_value->type = JSONBoolean;
+ new_value->value.boolean = boolean ? 1 : 0;
+ return new_value;
+}
+
+JSON_Value * json_value_init_null(void) {
+ JSON_Value *new_value = (JSON_Value*)parson_malloc(sizeof(JSON_Value));
+ if (!new_value)
+ return NULL;
+ new_value->type = JSONNull;
+ return new_value;
+}
+
+JSON_Value * json_value_deep_copy(const JSON_Value *value) {
+ size_t i = 0;
+ JSON_Value *return_value = NULL, *temp_value_copy = NULL, *temp_value = NULL;
+ const char *temp_string = NULL, *temp_key = NULL;
+ char *temp_string_copy = NULL;
+ JSON_Array *temp_array = NULL, *temp_array_copy = NULL;
+ JSON_Object *temp_object = NULL, *temp_object_copy = NULL;
+
+ switch (json_value_get_type(value)) {
+ case JSONArray:
+ temp_array = json_value_get_array(value);
+ return_value = json_value_init_array();
+ if (return_value == NULL)
+ return NULL;
+ temp_array_copy = json_value_get_array(return_value);
+ for (i = 0; i < json_array_get_count(temp_array); i++) {
+ temp_value = json_array_get_value(temp_array, i);
+ temp_value_copy = json_value_deep_copy(temp_value);
+ if (temp_value_copy == NULL) {
+ json_value_free(return_value);
+ return NULL;
+ }
+ if (json_array_add(temp_array_copy, temp_value_copy) == JSONFailure) {
+ json_value_free(return_value);
+ json_value_free(temp_value_copy);
+ return NULL;
+ }
+ }
+ return return_value;
+ case JSONObject:
+ temp_object = json_value_get_object(value);
+ return_value = json_value_init_object();
+ if (return_value == NULL)
+ return NULL;
+ temp_object_copy = json_value_get_object(return_value);
+ for (i = 0; i < json_object_get_count(temp_object); i++) {
+ temp_key = json_object_get_name(temp_object, i);
+ temp_value = json_object_get_value(temp_object, temp_key);
+ temp_value_copy = json_value_deep_copy(temp_value);
+ if (temp_value_copy == NULL) {
+ json_value_free(return_value);
+ return NULL;
+ }
+ if (json_object_add(temp_object_copy, temp_key, temp_value_copy) == JSONFailure) {
+ json_value_free(return_value);
+ json_value_free(temp_value_copy);
+ return NULL;
+ }
+ }
+ return return_value;
+ case JSONBoolean:
+ return json_value_init_boolean(json_value_get_boolean(value));
+ case JSONNumber:
+ return json_value_init_number(json_value_get_number(value));
+ case JSONString:
+ temp_string = json_value_get_string(value);
+ temp_string_copy = parson_strdup(temp_string);
+ if (temp_string_copy == NULL)
+ return NULL;
+ return_value = json_value_init_string_no_copy(temp_string_copy);
+ if (return_value == NULL)
+ parson_free(temp_string_copy);
+ return return_value;
+ case JSONNull:
+ return json_value_init_null();
+ case JSONError:
+ return NULL;
+ default:
+ return NULL;
+ }
+}
+
+size_t json_serialization_size(const JSON_Value *value) {
+ char num_buf[1100]; /* recursively allocating buffer on stack is a bad idea, so let's do it only once */
+ int res = json_serialize_to_buffer_r(value, NULL, 0, 0, num_buf);
+ return res < 0 ? 0 : (size_t)(res + 1);
+}
+
+JSON_Status json_serialize_to_buffer(const JSON_Value *value, char *buf, size_t buf_size_in_bytes) {
+ int written = -1;
+ size_t needed_size_in_bytes = json_serialization_size(value);
+ if (needed_size_in_bytes == 0 || buf_size_in_bytes < needed_size_in_bytes) {
+ return JSONFailure;
+ }
+ written = json_serialize_to_buffer_r(value, buf, 0, 0, NULL);
+ if (written < 0)
+ return JSONFailure;
+ return JSONSuccess;
+}
+
+JSON_Status json_serialize_to_file(const JSON_Value *value, const char *filename) {
+ JSON_Status return_code = JSONSuccess;
+ FILE *fp = NULL;
+ char *serialized_string = json_serialize_to_string(value);
+ if (serialized_string == NULL) {
+ return JSONFailure;
+ }
+ fp = fopen (filename, "w");
+ if (fp != NULL) {
+ if (fputs (serialized_string, fp) == EOF) {
+ return_code = JSONFailure;
+ }
+ if (fclose (fp) == EOF) {
+ return_code = JSONFailure;
+ }
+ }
+ json_free_serialized_string(serialized_string);
+ return return_code;
+}
+
+char * json_serialize_to_string(const JSON_Value *value) {
+ JSON_Status serialization_result = JSONFailure;
+ size_t buf_size_bytes = json_serialization_size(value);
+ char *buf = NULL;
+ if (buf_size_bytes == 0) {
+ return NULL;
+ }
+ buf = (char*)parson_malloc(buf_size_bytes);
+ if (buf == NULL)
+ return NULL;
+ serialization_result = json_serialize_to_buffer(value, buf, buf_size_bytes);
+ if (serialization_result == JSONFailure) {
+ json_free_serialized_string(buf);
+ return NULL;
+ }
+ return buf;
+}
+
+size_t json_serialization_size_pretty(const JSON_Value *value) {
+ char num_buf[1100]; /* recursively allocating buffer on stack is a bad idea, so let's do it only once */
+ int res = json_serialize_to_buffer_r(value, NULL, 0, 1, num_buf);
+ return res < 0 ? 0 : (size_t)(res + 1);
+}
+
+JSON_Status json_serialize_to_buffer_pretty(const JSON_Value *value, char *buf, size_t buf_size_in_bytes) {
+ int written = -1;
+ size_t needed_size_in_bytes = json_serialization_size_pretty(value);
+ if (needed_size_in_bytes == 0 || buf_size_in_bytes < needed_size_in_bytes)
+ return JSONFailure;
+ written = json_serialize_to_buffer_r(value, buf, 0, 1, NULL);
+ if (written < 0)
+ return JSONFailure;
+ return JSONSuccess;
+}
+
+JSON_Status json_serialize_to_file_pretty(const JSON_Value *value, const char *filename) {
+ JSON_Status return_code = JSONSuccess;
+ FILE *fp = NULL;
+ char *serialized_string = json_serialize_to_string_pretty(value);
+ if (serialized_string == NULL) {
+ return JSONFailure;
+ }
+ fp = fopen (filename, "w");
+ if (fp != NULL) {
+ if (fputs (serialized_string, fp) == EOF) {
+ return_code = JSONFailure;
+ }
+ if (fclose (fp) == EOF) {
+ return_code = JSONFailure;
+ }
+ }
+ json_free_serialized_string(serialized_string);
+ return return_code;
+}
+
+char * json_serialize_to_string_pretty(const JSON_Value *value) {
+ JSON_Status serialization_result = JSONFailure;
+ size_t buf_size_bytes = json_serialization_size_pretty(value);
+ char *buf = NULL;
+ if (buf_size_bytes == 0) {
+ return NULL;
+ }
+ buf = (char*)parson_malloc(buf_size_bytes);
+ if (buf == NULL)
+ return NULL;
+ serialization_result = json_serialize_to_buffer_pretty(value, buf, buf_size_bytes);
+ if (serialization_result == JSONFailure) {
+ json_free_serialized_string(buf);
+ return NULL;
+ }
+ return buf;
+}
+
+void json_free_serialized_string(char *string) {
+ parson_free(string);
+}
+
+JSON_Status json_array_remove(JSON_Array *array, size_t ix) {
+ JSON_Value *temp_value = NULL;
+ size_t last_element_ix = 0;
+ if (array == NULL || ix >= json_array_get_count(array)) {
+ return JSONFailure;
+ }
+ last_element_ix = json_array_get_count(array) - 1;
+ json_value_free(json_array_get_value(array, ix));
+ if (ix != last_element_ix) { /* Replace value with one from the end of array */
+ temp_value = json_array_get_value(array, last_element_ix);
+ if (temp_value == NULL) {
+ return JSONFailure;
+ }
+ array->items[ix] = temp_value;
+ }
+ array->count -= 1;
+ return JSONSuccess;
+}
+
+JSON_Status json_array_replace_value(JSON_Array *array, size_t ix, JSON_Value *value) {
+ if (array == NULL || value == NULL || ix >= json_array_get_count(array)) {
+ return JSONFailure;
+ }
+ json_value_free(json_array_get_value(array, ix));
+ array->items[ix] = value;
+ return JSONSuccess;
+}
+
+JSON_Status json_array_replace_string(JSON_Array *array, size_t i, const char* string) {
+ JSON_Value *value = json_value_init_string(string);
+ if (value == NULL)
+ return JSONFailure;
+ if (json_array_replace_value(array, i, value) == JSONFailure) {
+ json_value_free(value);
+ return JSONFailure;
+ }
+ return JSONSuccess;
+}
+
+JSON_Status json_array_replace_number(JSON_Array *array, size_t i, double number) {
+ JSON_Value *value = json_value_init_number(number);
+ if (value == NULL)
+ return JSONFailure;
+ if (json_array_replace_value(array, i, value) == JSONFailure) {
+ json_value_free(value);
+ return JSONFailure;
+ }
+ return JSONSuccess;
+}
+
+JSON_Status json_array_replace_boolean(JSON_Array *array, size_t i, int boolean) {
+ JSON_Value *value = json_value_init_boolean(boolean);
+ if (value == NULL)
+ return JSONFailure;
+ if (json_array_replace_value(array, i, value) == JSONFailure) {
+ json_value_free(value);
+ return JSONFailure;
+ }
+ return JSONSuccess;
+}
+
+JSON_Status json_array_replace_null(JSON_Array *array, size_t i) {
+ JSON_Value *value = json_value_init_null();
+ if (value == NULL)
+ return JSONFailure;
+ if (json_array_replace_value(array, i, value) == JSONFailure) {
+ json_value_free(value);
+ return JSONFailure;
+ }
+ return JSONSuccess;
+}
+
+JSON_Status json_array_clear(JSON_Array *array) {
+ size_t i = 0;
+ if (array == NULL)
+ return JSONFailure;
+ for (i = 0; i < json_array_get_count(array); i++) {
+ json_value_free(json_array_get_value(array, i));
+ }
+ array->count = 0;
+ return JSONSuccess;
+}
+
+JSON_Status json_array_append_value(JSON_Array *array, JSON_Value *value) {
+ if (array == NULL || value == NULL)
+ return JSONFailure;
+ return json_array_add(array, value);
+}
+
+JSON_Status json_array_append_string(JSON_Array *array, const char *string) {
+ JSON_Value *value = json_value_init_string(string);
+ if (value == NULL)
+ return JSONFailure;
+ if (json_array_append_value(array, value) == JSONFailure) {
+ json_value_free(value);
+ return JSONFailure;
+ }
+ return JSONSuccess;
+}
+
+JSON_Status json_array_append_number(JSON_Array *array, double number) {
+ JSON_Value *value = json_value_init_number(number);
+ if (value == NULL)
+ return JSONFailure;
+ if (json_array_append_value(array, value) == JSONFailure) {
+ json_value_free(value);
+ return JSONFailure;
+ }
+ return JSONSuccess;
+}
+
+JSON_Status json_array_append_boolean(JSON_Array *array, int boolean) {
+ JSON_Value *value = json_value_init_boolean(boolean);
+ if (value == NULL)
+ return JSONFailure;
+ if (json_array_append_value(array, value) == JSONFailure) {
+ json_value_free(value);
+ return JSONFailure;
+ }
+ return JSONSuccess;
+}
+
+JSON_Status json_array_append_null(JSON_Array *array) {
+ JSON_Value *value = json_value_init_null();
+ if (value == NULL)
+ return JSONFailure;
+ if (json_array_append_value(array, value) == JSONFailure) {
+ json_value_free(value);
+ return JSONFailure;
+ }
+ return JSONSuccess;
+}
+
+JSON_Status json_object_set_value(JSON_Object *object, const char *name, JSON_Value *value) {
+ size_t i = 0;
+ JSON_Value *old_value;
+ if (object == NULL || name == NULL || value == NULL)
+ return JSONFailure;
+ old_value = json_object_get_value(object, name);
+ if (old_value != NULL) { /* free and overwrite old value */
+ json_value_free(old_value);
+ for (i = 0; i < json_object_get_count(object); i++) {
+ if (strcmp(object->names[i], name) == 0) {
+ object->values[i] = value;
+ return JSONSuccess;
+ }
+ }
+ }
+ /* add new key value pair */
+ return json_object_add(object, name, value);
+}
+
+JSON_Status json_object_set_string(JSON_Object *object, const char *name, const char *string) {
+ return json_object_set_value(object, name, json_value_init_string(string));
+}
+
+JSON_Status json_object_set_number(JSON_Object *object, const char *name, double number) {
+ return json_object_set_value(object, name, json_value_init_number(number));
+}
+
+JSON_Status json_object_set_boolean(JSON_Object *object, const char *name, int boolean) {
+ return json_object_set_value(object, name, json_value_init_boolean(boolean));
+}
+
+JSON_Status json_object_set_null(JSON_Object *object, const char *name) {
+ return json_object_set_value(object, name, json_value_init_null());
+}
+
+JSON_Status json_object_dotset_value(JSON_Object *object, const char *name, JSON_Value *value) {
+ const char *dot_pos = NULL;
+ char *current_name = NULL;
+ JSON_Object *temp_obj = NULL;
+ JSON_Value *new_value = NULL;
+ if (value == NULL || name == NULL || value == NULL)
+ return JSONFailure;
+ dot_pos = strchr(name, '.');
+ if (dot_pos == NULL) {
+ return json_object_set_value(object, name, value);
+ } else {
+ current_name = parson_strndup(name, dot_pos - name);
+ temp_obj = json_object_get_object(object, current_name);
+ if (temp_obj == NULL) {
+ new_value = json_value_init_object();
+ if (new_value == NULL) {
+ parson_free(current_name);
+ return JSONFailure;
+ }
+ if (json_object_add(object, current_name, new_value) == JSONFailure) {
+ json_value_free(new_value);
+ parson_free(current_name);
+ return JSONFailure;
+ }
+ temp_obj = json_object_get_object(object, current_name);
+ }
+ parson_free(current_name);
+ return json_object_dotset_value(temp_obj, dot_pos + 1, value);
+ }
+}
+
+JSON_Status json_object_dotset_string(JSON_Object *object, const char *name, const char *string) {
+ JSON_Value *value = json_value_init_string(string);
+ if (value == NULL)
+ return JSONFailure;
+ if (json_object_dotset_value(object, name, value) == JSONFailure) {
+ json_value_free(value);
+ return JSONFailure;
+ }
+ return JSONSuccess;
+}
+
+JSON_Status json_object_dotset_number(JSON_Object *object, const char *name, double number) {
+ JSON_Value *value = json_value_init_number(number);
+ if (value == NULL)
+ return JSONFailure;
+ if (json_object_dotset_value(object, name, value) == JSONFailure) {
+ json_value_free(value);
+ return JSONFailure;
+ }
+ return JSONSuccess;
+}
+
+JSON_Status json_object_dotset_boolean(JSON_Object *object, const char *name, int boolean) {
+ JSON_Value *value = json_value_init_boolean(boolean);
+ if (value == NULL)
+ return JSONFailure;
+ if (json_object_dotset_value(object, name, value) == JSONFailure) {
+ json_value_free(value);
+ return JSONFailure;
+ }
+ return JSONSuccess;
+}
+
+JSON_Status json_object_dotset_null(JSON_Object *object, const char *name) {
+ JSON_Value *value = json_value_init_null();
+ if (value == NULL)
+ return JSONFailure;
+ if (json_object_dotset_value(object, name, value) == JSONFailure) {
+ json_value_free(value);
+ return JSONFailure;
+ }
+ return JSONSuccess;
+}
+
+JSON_Status json_object_remove(JSON_Object *object, const char *name) {
+ size_t i = 0, last_item_index = 0;
+ if (object == NULL || json_object_get_value(object, name) == NULL)
+ return JSONFailure;
+ last_item_index = json_object_get_count(object) - 1;
+ for (i = 0; i < json_object_get_count(object); i++) {
+ if (strcmp(object->names[i], name) == 0) {
+ parson_free(object->names[i]);
+ json_value_free(object->values[i]);
+ if (i != last_item_index) { /* Replace key value pair with one from the end */
+ object->names[i] = object->names[last_item_index];
+ object->values[i] = object->values[last_item_index];
+ }
+ object->count -= 1;
+ return JSONSuccess;
+ }
+ }
+ return JSONFailure; /* No execution path should end here */
+}
+
+JSON_Status json_object_dotremove(JSON_Object *object, const char *name) {
+ const char *dot_pos = strchr(name, '.');
+ char *current_name = NULL;
+ JSON_Object *temp_obj = NULL;
+ if (dot_pos == NULL) {
+ return json_object_remove(object, name);
+ } else {
+ current_name = parson_strndup(name, dot_pos - name);
+ temp_obj = json_object_get_object(object, current_name);
+ if (temp_obj == NULL) {
+ parson_free(current_name);
+ return JSONFailure;
+ }
+ parson_free(current_name);
+ return json_object_dotremove(temp_obj, dot_pos + 1);
+ }
+}
+
+JSON_Status json_object_clear(JSON_Object *object) {
+ size_t i = 0;
+ if (object == NULL) {
+ return JSONFailure;
+ }
+ for (i = 0; i < json_object_get_count(object); i++) {
+ parson_free(object->names[i]);
+ json_value_free(object->values[i]);
+ }
+ object->count = 0;
+ return JSONSuccess;
+}
+
+JSON_Status json_validate(const JSON_Value *schema, const JSON_Value *value) {
+ JSON_Value *temp_schema_value = NULL, *temp_value = NULL;
+ JSON_Array *schema_array = NULL, *value_array = NULL;
+ JSON_Object *schema_object = NULL, *value_object = NULL;
+ JSON_Value_Type schema_type = JSONError, value_type = JSONError;
+ const char *key = NULL;
+ size_t i = 0, count = 0;
+ if (schema == NULL || value == NULL)
+ return JSONFailure;
+ schema_type = json_value_get_type(schema);
+ value_type = json_value_get_type(value);
+ if (schema_type != value_type && schema_type != JSONNull) /* null represents all values */
+ return JSONFailure;
+ switch (schema_type) {
+ case JSONArray:
+ schema_array = json_value_get_array(schema);
+ value_array = json_value_get_array(value);
+ count = json_array_get_count(schema_array);
+ if (count == 0)
+ return JSONSuccess; /* Empty array allows all types */
+ /* Get first value from array, rest is ignored */
+ temp_schema_value = json_array_get_value(schema_array, 0);
+ for (i = 0; i < json_array_get_count(value_array); i++) {
+ temp_value = json_array_get_value(value_array, i);
+ if (json_validate(temp_schema_value, temp_value) == 0) {
+ return JSONFailure;
+ }
+ }
+ return JSONSuccess;
+ case JSONObject:
+ schema_object = json_value_get_object(schema);
+ value_object = json_value_get_object(value);
+ count = json_object_get_count(schema_object);
+ if (count == 0)
+ return JSONSuccess; /* Empty object allows all objects */
+ else if (json_object_get_count(value_object) < count)
+ return JSONFailure; /* Tested object mustn't have less name-value pairs than schema */
+ for (i = 0; i < count; i++) {
+ key = json_object_get_name(schema_object, i);
+ temp_schema_value = json_object_get_value(schema_object, key);
+ temp_value = json_object_get_value(value_object, key);
+ if (temp_value == NULL)
+ return JSONFailure;
+ if (json_validate(temp_schema_value, temp_value) == JSONFailure)
+ return JSONFailure;
+ }
+ return JSONSuccess;
+ case JSONString: case JSONNumber: case JSONBoolean: case JSONNull:
+ return JSONSuccess; /* equality already tested before switch */
+ case JSONError: default:
+ return JSONFailure;
+ }
+}
+
+JSON_Status json_value_equals(const JSON_Value *a, const JSON_Value *b) {
+ JSON_Object *a_object = NULL, *b_object = NULL;
+ JSON_Array *a_array = NULL, *b_array = NULL;
+ const char *a_string = NULL, *b_string = NULL;
+ const char *key = NULL;
+ size_t a_count = 0, b_count = 0, i = 0;
+ JSON_Value_Type a_type, b_type;
+ a_type = json_value_get_type(a);
+ b_type = json_value_get_type(b);
+ if (a_type != b_type) {
+ return 0;
+ }
+ switch (a_type) {
+ case JSONArray:
+ a_array = json_value_get_array(a);
+ b_array = json_value_get_array(b);
+ a_count = json_array_get_count(a_array);
+ b_count = json_array_get_count(b_array);
+ if (a_count != b_count) {
+ return 0;
+ }
+ for (i = 0; i < a_count; i++) {
+ if (!json_value_equals(json_array_get_value(a_array, i),
+ json_array_get_value(b_array, i))) {
+ return 0;
+ }
+ }
+ return 1;
+ case JSONObject:
+ a_object = json_value_get_object(a);
+ b_object = json_value_get_object(b);
+ a_count = json_object_get_count(a_object);
+ b_count = json_object_get_count(b_object);
+ if (a_count != b_count) {
+ return 0;
+ }
+ for (i = 0; i < a_count; i++) {
+ key = json_object_get_name(a_object, i);
+ if (!json_value_equals(json_object_get_value(a_object, key),
+ json_object_get_value(b_object, key))) {
+ return 0;
+ }
+ }
+ return 1;
+ case JSONString:
+ a_string = json_value_get_string(a);
+ b_string = json_value_get_string(b);
+ return strcmp(a_string, b_string) == 0;
+ case JSONBoolean:
+ return json_value_get_boolean(a) == json_value_get_boolean(b);
+ case JSONNumber:
+ return fabs(json_value_get_number(a) - json_value_get_number(b)) < 0.000001; /* EPSILON */
+ case JSONError:
+ return 1;
+ case JSONNull:
+ return 1;
+ default:
+ return 1;
+ }
+}
+
+JSON_Value_Type json_type(const JSON_Value *value) {
+ return json_value_get_type(value);
+}
+
+JSON_Object * json_object (const JSON_Value *value) {
+ return json_value_get_object(value);
+}
+
+JSON_Array * json_array (const JSON_Value *value) {
+ return json_value_get_array(value);
+}
+
+const char * json_string (const JSON_Value *value) {
+ return json_value_get_string(value);
+}
+
+double json_number (const JSON_Value *value) {
+ return json_value_get_number(value);
+}
+
+int json_boolean(const JSON_Value *value) {
+ return json_value_get_boolean(value);
+}
+
+void json_set_allocation_functions(JSON_Malloc_Function malloc_fun, JSON_Free_Function free_fun) {
+ parson_malloc = malloc_fun;
+ parson_free = free_fun;
+}
diff --git a/util_pkt_logger/src/util_pkt_logger.c b/util_pkt_logger/src/util_pkt_logger.c
new file mode 100644
index 0000000..38a50f7
--- /dev/null
+++ b/util_pkt_logger/src/util_pkt_logger.c
@@ -0,0 +1,626 @@
+/*
+ / _____) _ | |
+( (____ _____ ____ _| |_ _____ ____| |__
+ \____ \| ___ | (_ _) ___ |/ ___) _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+ (C)2013 Semtech-Cycleo
+
+Description:
+ Configure LoRa concentrator and record received packets in a log file
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+Maintainer: Sylvain Miermont
+*/
+
+
+/* -------------------------------------------------------------------------- */
+/* --- DEPENDANCIES --------------------------------------------------------- */
+
+/* fix an issue between POSIX and C99 */
+#if __STDC_VERSION__ >= 199901L
+ #define _XOPEN_SOURCE 600
+#else
+ #define _XOPEN_SOURCE 500
+#endif
+
+#include <stdint.h> /* C99 types */
+#include <stdbool.h> /* bool type */
+#include <stdio.h> /* printf fprintf sprintf fopen fputs */
+
+#include <string.h> /* memset */
+#include <signal.h> /* sigaction */
+#include <time.h> /* time clock_gettime strftime gmtime clock_nanosleep*/
+#include <unistd.h> /* getopt access */
+#include <stdlib.h> /* atoi */
+
+#include "parson.h"
+#include "loragw_hal.h"
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE MACROS ------------------------------------------------------- */
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+#define MSG(args...) fprintf(stderr,"loragw_pkt_logger: " args) /* message that is destined to the user */
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE VARIABLES (GLOBAL) ------------------------------------------- */
+
+/* signal handling variables */
+struct sigaction sigact; /* SIGQUIT&SIGINT&SIGTERM signal handling */
+static int exit_sig = 0; /* 1 -> application terminates cleanly (shut down hardware, close open files, etc) */
+static int quit_sig = 0; /* 1 -> application terminates without shutting down the hardware */
+
+/* configuration variables needed by the application */
+uint64_t lgwm = 0; /* LoRa gateway MAC address */
+char lgwm_str[17];
+
+/* clock and log file management */
+time_t now_time;
+time_t log_start_time;
+FILE * log_file = NULL;
+char log_file_name[64];
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE FUNCTIONS DECLARATION ---------------------------------------- */
+
+static void sig_handler(int sigio);
+
+int parse_SX1301_configuration(const char * conf_file);
+
+int parse_gateway_configuration(const char * conf_file);
+
+void open_log(void);
+
+void usage (void);
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE FUNCTIONS DEFINITION ----------------------------------------- */
+
+static void sig_handler(int sigio) {
+ if (sigio == SIGQUIT) {
+ quit_sig = 1;;
+ } else if ((sigio == SIGINT) || (sigio == SIGTERM)) {
+ exit_sig = 1;
+ }
+}
+
+int parse_SX1301_configuration(const char * conf_file) {
+ int i;
+ const char conf_obj[] = "SX1301_conf";
+ char param_name[32]; /* used to generate variable parameter names */
+ const char *str; /* used to store string value from JSON object */
+ struct lgw_conf_board_s boardconf;
+ struct lgw_conf_rxrf_s rfconf;
+ struct lgw_conf_rxif_s ifconf;
+ JSON_Value *root_val;
+ JSON_Object *root = NULL;
+ JSON_Object *conf = NULL;
+ JSON_Value *val;
+ uint32_t sf, bw;
+
+ /* try to parse JSON */
+ root_val = json_parse_file_with_comments(conf_file);
+ root = json_value_get_object(root_val);
+ if (root == NULL) {
+ MSG("ERROR: %s id not a valid JSON file\n", conf_file);
+ exit(EXIT_FAILURE);
+ }
+ conf = json_object_get_object(root, conf_obj);
+ if (conf == NULL) {
+ MSG("INFO: %s does not contain a JSON object named %s\n", conf_file, conf_obj);
+ return -1;
+ } else {
+ MSG("INFO: %s does contain a JSON object named %s, parsing SX1301 parameters\n", conf_file, conf_obj);
+ }
+
+ /* set board configuration */
+ memset(&boardconf, 0, sizeof boardconf); /* initialize configuration structure */
+ val = json_object_get_value(conf, "lorawan_public"); /* fetch value (if possible) */
+ if (json_value_get_type(val) == JSONBoolean) {
+ boardconf.lorawan_public = (bool)json_value_get_boolean(val);
+ } else {
+ MSG("WARNING: Data type for lorawan_public seems wrong, please check\n");
+ boardconf.lorawan_public = false;
+ }
+ val = json_object_get_value(conf, "clksrc"); /* fetch value (if possible) */
+ if (json_value_get_type(val) == JSONNumber) {
+ boardconf.clksrc = (uint8_t)json_value_get_number(val);
+ } else {
+ MSG("WARNING: Data type for clksrc seems wrong, please check\n");
+ boardconf.clksrc = 0;
+ }
+ MSG("INFO: lorawan_public %d, clksrc %d\n", boardconf.lorawan_public, boardconf.clksrc);
+ /* all parameters parsed, submitting configuration to the HAL */
+ if (lgw_board_setconf(boardconf) != LGW_HAL_SUCCESS) {
+ MSG("ERROR: Failed to configure board\n");
+ return -1;
+ }
+
+ /* set configuration for RF chains */
+ for (i = 0; i < LGW_RF_CHAIN_NB; ++i) {
+ memset(&rfconf, 0, sizeof(rfconf)); /* initialize configuration structure */
+ sprintf(param_name, "radio_%i", i); /* compose parameter path inside JSON structure */
+ val = json_object_get_value(conf, param_name); /* fetch value (if possible) */
+ if (json_value_get_type(val) != JSONObject) {
+ MSG("INFO: no configuration for radio %i\n", i);
+ continue;
+ }
+ /* there is an object to configure that radio, let's parse it */
+ sprintf(param_name, "radio_%i.enable", i);
+ val = json_object_dotget_value(conf, param_name);
+ if (json_value_get_type(val) == JSONBoolean) {
+ rfconf.enable = (bool)json_value_get_boolean(val);
+ } else {
+ rfconf.enable = false;
+ }
+ if (rfconf.enable == false) { /* radio disabled, nothing else to parse */
+ MSG("INFO: radio %i disabled\n", i);
+ } else { /* radio enabled, will parse the other parameters */
+ snprintf(param_name, sizeof param_name, "radio_%i.freq", i);
+ rfconf.freq_hz = (uint32_t)json_object_dotget_number(conf, param_name);
+ snprintf(param_name, sizeof param_name, "radio_%i.rssi_offset", i);
+ rfconf.rssi_offset = (float)json_object_dotget_number(conf, param_name);
+ snprintf(param_name, sizeof param_name, "radio_%i.type", i);
+ str = json_object_dotget_string(conf, param_name);
+ if (!strncmp(str, "SX1255", 6)) {
+ rfconf.type = LGW_RADIO_TYPE_SX1255;
+ } else if (!strncmp(str, "SX1257", 6)) {
+ rfconf.type = LGW_RADIO_TYPE_SX1257;
+ } else {
+ MSG("WARNING: invalid radio type: %s (should be SX1255 or SX1257)\n", str);
+ }
+ snprintf(param_name, sizeof param_name, "radio_%i.tx_enable", i);
+ val = json_object_dotget_value(conf, param_name);
+ if (json_value_get_type(val) == JSONBoolean) {
+ rfconf.tx_enable = (bool)json_value_get_boolean(val);
+ if (rfconf.tx_enable == true) {
+ /* tx notch filter frequency to be set */
+ snprintf(param_name, sizeof param_name, "radio_%i.tx_notch_freq", i);
+ rfconf.tx_notch_freq = (uint32_t)json_object_dotget_number(conf, param_name);
+ }
+ } else {
+ rfconf.tx_enable = false;
+ }
+ MSG("INFO: radio %i enabled (type %s), center frequency %u, RSSI offset %f, tx enabled %d, tx_notch_freq %u\n", i, str, rfconf.freq_hz, rfconf.rssi_offset, rfconf.tx_enable, rfconf.tx_notch_freq);
+ }
+ /* all parameters parsed, submitting configuration to the HAL */
+ if (lgw_rxrf_setconf(i, rfconf) != LGW_HAL_SUCCESS) {
+ MSG("ERROR: invalid configuration for radio %i\n", i);
+ return -1;
+ }
+ }
+
+ /* set configuration for LoRa multi-SF channels (bandwidth cannot be set) */
+ for (i = 0; i < LGW_MULTI_NB; ++i) {
+ memset(&ifconf, 0, sizeof(ifconf)); /* initialize configuration structure */
+ sprintf(param_name, "chan_multiSF_%i", i); /* compose parameter path inside JSON structure */
+ val = json_object_get_value(conf, param_name); /* fetch value (if possible) */
+ if (json_value_get_type(val) != JSONObject) {
+ MSG("INFO: no configuration for LoRa multi-SF channel %i\n", i);
+ continue;
+ }
+ /* there is an object to configure that LoRa multi-SF channel, let's parse it */
+ sprintf(param_name, "chan_multiSF_%i.enable", i);
+ val = json_object_dotget_value(conf, param_name);
+ if (json_value_get_type(val) == JSONBoolean) {
+ ifconf.enable = (bool)json_value_get_boolean(val);
+ } else {
+ ifconf.enable = false;
+ }
+ if (ifconf.enable == false) { /* LoRa multi-SF channel disabled, nothing else to parse */
+ MSG("INFO: LoRa multi-SF channel %i disabled\n", i);
+ } else { /* LoRa multi-SF channel enabled, will parse the other parameters */
+ sprintf(param_name, "chan_multiSF_%i.radio", i);
+ ifconf.rf_chain = (uint32_t)json_object_dotget_number(conf, param_name);
+ sprintf(param_name, "chan_multiSF_%i.if", i);
+ ifconf.freq_hz = (int32_t)json_object_dotget_number(conf, param_name);
+ // TODO: handle individual SF enabling and disabling (spread_factor)
+ MSG("INFO: LoRa multi-SF channel %i enabled, radio %i selected, IF %i Hz, 125 kHz bandwidth, SF 7 to 12\n", i, ifconf.rf_chain, ifconf.freq_hz);
+ }
+ /* all parameters parsed, submitting configuration to the HAL */
+ if (lgw_rxif_setconf(i, ifconf) != LGW_HAL_SUCCESS) {
+ MSG("ERROR: invalid configuration for Lora multi-SF channel %i\n", i);
+ return -1;
+ }
+ }
+
+ /* set configuration for LoRa standard channel */
+ memset(&ifconf, 0, sizeof(ifconf)); /* initialize configuration structure */
+ val = json_object_get_value(conf, "chan_Lora_std"); /* fetch value (if possible) */
+ if (json_value_get_type(val) != JSONObject) {
+ MSG("INFO: no configuration for LoRa standard channel\n");
+ } else {
+ val = json_object_dotget_value(conf, "chan_Lora_std.enable");
+ if (json_value_get_type(val) == JSONBoolean) {
+ ifconf.enable = (bool)json_value_get_boolean(val);
+ } else {
+ ifconf.enable = false;
+ }
+ if (ifconf.enable == false) {
+ MSG("INFO: LoRa standard channel %i disabled\n", i);
+ } else {
+ ifconf.rf_chain = (uint32_t)json_object_dotget_number(conf, "chan_Lora_std.radio");
+ ifconf.freq_hz = (int32_t)json_object_dotget_number(conf, "chan_Lora_std.if");
+ bw = (uint32_t)json_object_dotget_number(conf, "chan_Lora_std.bandwidth");
+ switch(bw) {
+ case 500000: ifconf.bandwidth = BW_500KHZ; break;
+ case 250000: ifconf.bandwidth = BW_250KHZ; break;
+ case 125000: ifconf.bandwidth = BW_125KHZ; break;
+ default: ifconf.bandwidth = BW_UNDEFINED;
+ }
+ sf = (uint32_t)json_object_dotget_number(conf, "chan_Lora_std.spread_factor");
+ switch(sf) {
+ case 7: ifconf.datarate = DR_LORA_SF7; break;
+ case 8: ifconf.datarate = DR_LORA_SF8; break;
+ case 9: ifconf.datarate = DR_LORA_SF9; break;
+ case 10: ifconf.datarate = DR_LORA_SF10; break;
+ case 11: ifconf.datarate = DR_LORA_SF11; break;
+ case 12: ifconf.datarate = DR_LORA_SF12; break;
+ default: ifconf.datarate = DR_UNDEFINED;
+ }
+ MSG("INFO: LoRa standard channel enabled, radio %i selected, IF %i Hz, %u Hz bandwidth, SF %u\n", ifconf.rf_chain, ifconf.freq_hz, bw, sf);
+ }
+ if (lgw_rxif_setconf(8, ifconf) != LGW_HAL_SUCCESS) {
+ MSG("ERROR: invalid configuration for Lora standard channel\n");
+ return -1;
+ }
+ }
+
+ /* set configuration for FSK channel */
+ memset(&ifconf, 0, sizeof(ifconf)); /* initialize configuration structure */
+ val = json_object_get_value(conf, "chan_FSK"); /* fetch value (if possible) */
+ if (json_value_get_type(val) != JSONObject) {
+ MSG("INFO: no configuration for FSK channel\n");
+ } else {
+ val = json_object_dotget_value(conf, "chan_FSK.enable");
+ if (json_value_get_type(val) == JSONBoolean) {
+ ifconf.enable = (bool)json_value_get_boolean(val);
+ } else {
+ ifconf.enable = false;
+ }
+ if (ifconf.enable == false) {
+ MSG("INFO: FSK channel %i disabled\n", i);
+ } else {
+ ifconf.rf_chain = (uint32_t)json_object_dotget_number(conf, "chan_FSK.radio");
+ ifconf.freq_hz = (int32_t)json_object_dotget_number(conf, "chan_FSK.if");
+ bw = (uint32_t)json_object_dotget_number(conf, "chan_FSK.bandwidth");
+ if (bw <= 7800) ifconf.bandwidth = BW_7K8HZ;
+ else if (bw <= 15600) ifconf.bandwidth = BW_15K6HZ;
+ else if (bw <= 31200) ifconf.bandwidth = BW_31K2HZ;
+ else if (bw <= 62500) ifconf.bandwidth = BW_62K5HZ;
+ else if (bw <= 125000) ifconf.bandwidth = BW_125KHZ;
+ else if (bw <= 250000) ifconf.bandwidth = BW_250KHZ;
+ else if (bw <= 500000) ifconf.bandwidth = BW_500KHZ;
+ else ifconf.bandwidth = BW_UNDEFINED;
+ ifconf.datarate = (uint32_t)json_object_dotget_number(conf, "chan_FSK.datarate");
+ MSG("INFO: FSK channel enabled, radio %i selected, IF %i Hz, %u Hz bandwidth, %u bps datarate\n", ifconf.rf_chain, ifconf.freq_hz, bw, ifconf.datarate);
+ }
+ if (lgw_rxif_setconf(9, ifconf) != LGW_HAL_SUCCESS) {
+ MSG("ERROR: invalid configuration for FSK channel\n");
+ return -1;
+ }
+ }
+ json_value_free(root_val);
+ return 0;
+}
+
+int parse_gateway_configuration(const char * conf_file) {
+ const char conf_obj[] = "gateway_conf";
+ JSON_Value *root_val;
+ JSON_Object *root = NULL;
+ JSON_Object *conf = NULL;
+ const char *str; /* pointer to sub-strings in the JSON data */
+ unsigned long long ull = 0;
+
+ /* try to parse JSON */
+ root_val = json_parse_file_with_comments(conf_file);
+ root = json_value_get_object(root_val);
+ if (root == NULL) {
+ MSG("ERROR: %s id not a valid JSON file\n", conf_file);
+ exit(EXIT_FAILURE);
+ }
+ conf = json_object_get_object(root, conf_obj);
+ if (conf == NULL) {
+ MSG("INFO: %s does not contain a JSON object named %s\n", conf_file, conf_obj);
+ return -1;
+ } else {
+ MSG("INFO: %s does contain a JSON object named %s, parsing gateway parameters\n", conf_file, conf_obj);
+ }
+
+ /* getting network parameters (only those necessary for the packet logger) */
+ str = json_object_get_string(conf, "gateway_ID");
+ if (str != NULL) {
+ sscanf(str, "%llx", &ull);
+ lgwm = ull;
+ MSG("INFO: gateway MAC address is configured to %016llX\n", ull);
+ }
+
+ json_value_free(root_val);
+ return 0;
+}
+
+void open_log(void) {
+ int i;
+ char iso_date[20];
+
+ strftime(iso_date,ARRAY_SIZE(iso_date),"%Y%m%dT%H%M%SZ",gmtime(&now_time)); /* format yyyymmddThhmmssZ */
+ log_start_time = now_time; /* keep track of when the log was started, for log rotation */
+
+ sprintf(log_file_name, "pktlog_%s_%s.csv", lgwm_str, iso_date);
+ log_file = fopen(log_file_name, "a"); /* create log file, append if file already exist */
+ if (log_file == NULL) {
+ MSG("ERROR: impossible to create log file %s\n", log_file_name);
+ exit(EXIT_FAILURE);
+ }
+
+ i = fprintf(log_file, "\"gateway ID\",\"node MAC\",\"UTC timestamp\",\"us count\",\"frequency\",\"RF chain\",\"RX chain\",\"status\",\"size\",\"modulation\",\"bandwidth\",\"datarate\",\"coderate\",\"RSSI\",\"SNR\",\"payload\"\n");
+ if (i < 0) {
+ MSG("ERROR: impossible to write to log file %s\n", log_file_name);
+ exit(EXIT_FAILURE);
+ }
+
+ MSG("INFO: Now writing to log file %s\n", log_file_name);
+ return;
+}
+
+/* describe command line options */
+void usage(void) {
+ printf("*** Library version information ***\n%s\n\n", lgw_version_info());
+ printf( "Available options:\n");
+ printf( " -h print this help\n");
+ printf( " -r <int> rotate log file every N seconds (-1 disable log rotation)\n");
+}
+
+/* -------------------------------------------------------------------------- */
+/* --- MAIN FUNCTION -------------------------------------------------------- */
+
+int main(int argc, char **argv)
+{
+ int i, j; /* loop and temporary variables */
+ struct timespec sleep_time = {0, 3000000}; /* 3 ms */
+
+ /* clock and log rotation management */
+ int log_rotate_interval = 3600; /* by default, rotation every hour */
+ int time_check = 0; /* variable used to limit the number of calls to time() function */
+ unsigned long pkt_in_log = 0; /* count the number of packet written in each log file */
+
+ /* configuration file related */
+ const char global_conf_fname[] = "global_conf.json"; /* contain global (typ. network-wide) configuration */
+ const char local_conf_fname[] = "local_conf.json"; /* contain node specific configuration, overwrite global parameters for parameters that are defined in both */
+ const char debug_conf_fname[] = "debug_conf.json"; /* if present, all other configuration files are ignored */
+
+ /* allocate memory for packet fetching and processing */
+ struct lgw_pkt_rx_s rxpkt[16]; /* array containing up to 16 inbound packets metadata */
+ struct lgw_pkt_rx_s *p; /* pointer on a RX packet */
+ int nb_pkt;
+
+ /* local timestamp variables until we get accurate GPS time */
+ struct timespec fetch_time;
+ char fetch_timestamp[30];
+ struct tm * x;
+
+ /* parse command line options */
+ while ((i = getopt (argc, argv, "hr:")) != -1) {
+ switch (i) {
+ case 'h':
+ usage();
+ return EXIT_FAILURE;
+ break;
+
+ case 'r':
+ log_rotate_interval = atoi(optarg);
+ if ((log_rotate_interval == 0) || (log_rotate_interval < -1)) {
+ MSG( "ERROR: Invalid argument for -r option\n");
+ return EXIT_FAILURE;
+ }
+ break;
+
+ default:
+ MSG("ERROR: argument parsing use -h option for help\n");
+ usage();
+ return EXIT_FAILURE;
+ }
+ }
+
+ /* configure signal handling */
+ sigemptyset(&sigact.sa_mask);
+ sigact.sa_flags = 0;
+ sigact.sa_handler = sig_handler;
+ sigaction(SIGQUIT, &sigact, NULL);
+ sigaction(SIGINT, &sigact, NULL);
+ sigaction(SIGTERM, &sigact, NULL);
+
+ /* configuration files management */
+ if (access(debug_conf_fname, R_OK) == 0) {
+ /* if there is a debug conf, parse only the debug conf */
+ MSG("INFO: found debug configuration file %s, other configuration files will be ignored\n", debug_conf_fname);
+ parse_SX1301_configuration(debug_conf_fname);
+ parse_gateway_configuration(debug_conf_fname);
+ } else if (access(global_conf_fname, R_OK) == 0) {
+ /* if there is a global conf, parse it and then try to parse local conf */
+ MSG("INFO: found global configuration file %s, trying to parse it\n", global_conf_fname);
+ parse_SX1301_configuration(global_conf_fname);
+ parse_gateway_configuration(global_conf_fname);
+ if (access(local_conf_fname, R_OK) == 0) {
+ MSG("INFO: found local configuration file %s, trying to parse it\n", local_conf_fname);
+ parse_SX1301_configuration(local_conf_fname);
+ parse_gateway_configuration(local_conf_fname);
+ }
+ } else if (access(local_conf_fname, R_OK) == 0) {
+ /* if there is only a local conf, parse it and that's all */
+ MSG("INFO: found local configuration file %s, trying to parse it\n", local_conf_fname);
+ parse_SX1301_configuration(local_conf_fname);
+ parse_gateway_configuration(local_conf_fname);
+ } else {
+ MSG("ERROR: failed to find any configuration file named %s, %s or %s\n", global_conf_fname, local_conf_fname, debug_conf_fname);
+ return EXIT_FAILURE;
+ }
+
+ /* starting the concentrator */
+ i = lgw_start();
+ if (i == LGW_HAL_SUCCESS) {
+ MSG("INFO: concentrator started, packet can now be received\n");
+ } else {
+ MSG("ERROR: failed to start the concentrator\n");
+ return EXIT_FAILURE;
+ }
+
+ /* transform the MAC address into a string */
+ sprintf(lgwm_str, "%08X%08X", (uint32_t)(lgwm >> 32), (uint32_t)(lgwm & 0xFFFFFFFF));
+
+ /* opening log file and writing CSV header*/
+ time(&now_time);
+ open_log();
+
+ /* main loop */
+ while ((quit_sig != 1) && (exit_sig != 1)) {
+ /* fetch packets */
+ nb_pkt = lgw_receive(ARRAY_SIZE(rxpkt), rxpkt);
+ if (nb_pkt == LGW_HAL_ERROR) {
+ MSG("ERROR: failed packet fetch, exiting\n");
+ return EXIT_FAILURE;
+ } else if (nb_pkt == 0) {
+ clock_nanosleep(CLOCK_MONOTONIC, 0, &sleep_time, NULL); /* wait a short time if no packets */
+ } else {
+ /* local timestamp generation until we get accurate GPS time */
+ clock_gettime(CLOCK_REALTIME, &fetch_time);
+ x = gmtime(&(fetch_time.tv_sec));
+ sprintf(fetch_timestamp,"%04i-%02i-%02i %02i:%02i:%02i.%03liZ",(x->tm_year)+1900,(x->tm_mon)+1,x->tm_mday,x->tm_hour,x->tm_min,x->tm_sec,(fetch_time.tv_nsec)/1000000); /* ISO 8601 format */
+ }
+
+ /* log packets */
+ for (i=0; i < nb_pkt; ++i) {
+ p = &rxpkt[i];
+
+ /* writing gateway ID */
+ fprintf(log_file, "\"%08X%08X\",", (uint32_t)(lgwm >> 32), (uint32_t)(lgwm & 0xFFFFFFFF));
+
+ /* writing node MAC address */
+ fputs("\"\",", log_file); // TODO: need to parse payload
+
+ /* writing UTC timestamp*/
+ fprintf(log_file, "\"%s\",", fetch_timestamp);
+ // TODO: replace with GPS time when available
+
+ /* writing internal clock */
+ fprintf(log_file, "%10u,", p->count_us);
+
+ /* writing RX frequency */
+ fprintf(log_file, "%10u,", p->freq_hz);
+
+ /* writing RF chain */
+ fprintf(log_file, "%u,", p->rf_chain);
+
+ /* writing RX modem/IF chain */
+ fprintf(log_file, "%2d,", p->if_chain);
+
+ /* writing status */
+ switch(p->status) {
+ case STAT_CRC_OK: fputs("\"CRC_OK\" ,", log_file); break;
+ case STAT_CRC_BAD: fputs("\"CRC_BAD\",", log_file); break;
+ case STAT_NO_CRC: fputs("\"NO_CRC\" ,", log_file); break;
+ case STAT_UNDEFINED: fputs("\"UNDEF\" ,", log_file); break;
+ default: fputs("\"ERR\" ,", log_file);
+ }
+
+ /* writing payload size */
+ fprintf(log_file, "%3u,", p->size);
+
+ /* writing modulation */
+ switch(p->modulation) {
+ case MOD_LORA: fputs("\"LORA\",", log_file); break;
+ case MOD_FSK: fputs("\"FSK\" ,", log_file); break;
+ default: fputs("\"ERR\" ,", log_file);
+ }
+
+ /* writing bandwidth */
+ switch(p->bandwidth) {
+ case BW_500KHZ: fputs("500000,", log_file); break;
+ case BW_250KHZ: fputs("250000,", log_file); break;
+ case BW_125KHZ: fputs("125000,", log_file); break;
+ case BW_62K5HZ: fputs("62500 ,", log_file); break;
+ case BW_31K2HZ: fputs("31200 ,", log_file); break;
+ case BW_15K6HZ: fputs("15600 ,", log_file); break;
+ case BW_7K8HZ: fputs("7800 ,", log_file); break;
+ case BW_UNDEFINED: fputs("0 ,", log_file); break;
+ default: fputs("-1 ,", log_file);
+ }
+
+ /* writing datarate */
+ if (p->modulation == MOD_LORA) {
+ switch (p->datarate) {
+ case DR_LORA_SF7: fputs("\"SF7\" ,", log_file); break;
+ case DR_LORA_SF8: fputs("\"SF8\" ,", log_file); break;
+ case DR_LORA_SF9: fputs("\"SF9\" ,", log_file); break;
+ case DR_LORA_SF10: fputs("\"SF10\" ,", log_file); break;
+ case DR_LORA_SF11: fputs("\"SF11\" ,", log_file); break;
+ case DR_LORA_SF12: fputs("\"SF12\" ,", log_file); break;
+ default: fputs("\"ERR\" ,", log_file);
+ }
+ } else if (p->modulation == MOD_FSK) {
+ fprintf(log_file, "\"%6u\",", p->datarate);
+ } else {
+ fputs("\"ERR\" ,", log_file);
+ }
+
+ /* writing coderate */
+ switch (p->coderate) {
+ case CR_LORA_4_5: fputs("\"4/5\",", log_file); break;
+ case CR_LORA_4_6: fputs("\"2/3\",", log_file); break;
+ case CR_LORA_4_7: fputs("\"4/7\",", log_file); break;
+ case CR_LORA_4_8: fputs("\"1/2\",", log_file); break;
+ case CR_UNDEFINED: fputs("\"\" ,", log_file); break;
+ default: fputs("\"ERR\",", log_file);
+ }
+
+ /* writing packet RSSI */
+ fprintf(log_file, "%+.0f,", p->rssi);
+
+ /* writing packet average SNR */
+ fprintf(log_file, "%+5.1f,", p->snr);
+
+ /* writing hex-encoded payload (bundled in 32-bit words) */
+ fputs("\"", log_file);
+ for (j = 0; j < p->size; ++j) {
+ if ((j > 0) && (j%4 == 0)) fputs("-", log_file);
+ fprintf(log_file, "%02X", p->payload[j]);
+ }
+
+ /* end of log file line */
+ fputs("\"\n", log_file);
+ fflush(log_file);
+ ++pkt_in_log;
+ }
+
+ /* check time and rotate log file if necessary */
+ ++time_check;
+ if (time_check >= 8) {
+ time_check = 0;
+ time(&now_time);
+ if (difftime(now_time, log_start_time) > log_rotate_interval) {
+ fclose(log_file);
+ MSG("INFO: log file %s closed, %lu packet(s) recorded\n", log_file_name, pkt_in_log);
+ pkt_in_log = 0;
+ open_log();
+ }
+ }
+ }
+
+ if (exit_sig == 1) {
+ /* clean up before leaving */
+ i = lgw_stop();
+ if (i == LGW_HAL_SUCCESS) {
+ MSG("INFO: concentrator stopped successfully\n");
+ } else {
+ MSG("WARNING: failed to stop concentrator successfully\n");
+ }
+ fclose(log_file);
+ MSG("INFO: log file %s closed, %lu packet(s) recorded\n", log_file_name, pkt_in_log);
+ }
+
+ MSG("INFO: Exiting packet logger program\n");
+ return EXIT_SUCCESS;
+}
+
+/* --- EOF ------------------------------------------------------------------ */
diff --git a/util_spectral_scan/Makefile b/util_spectral_scan/Makefile
new file mode 100644
index 0000000..35d625f
--- /dev/null
+++ b/util_spectral_scan/Makefile
@@ -0,0 +1,63 @@
+### Environment constants
+
+LGW_PATH ?= ../libloragw
+ARCH ?=
+CROSS_COMPILE ?=
+
+### External constant definitions
+
+include $(LGW_PATH)/library.cfg
+
+### Constant symbols
+
+CC = $(CROSS_COMPILE)gcc
+AR = $(CROSS_COMPILE)ar
+CFLAGS = -O2 -Wall -Wextra -std=c99 -I inc
+
+OBJDIR = obj
+INCLUDES = $(wildcard inc/*.h)
+
+### Constants for LoRa concentrator HAL library
+# List the library sub-modules that are used by the application
+
+LGW_INC = $(LGW_PATH)/inc/config.h
+LGW_INC += $(LGW_PATH)/inc/loragw_hal.h
+
+### Linking options
+
+LIBS := -lloragw -lrt
+
+### General build targets
+
+all: util_spectral_scan
+
+clean:
+ rm -f $(OBJDIR)/*.o
+ rm -f util_spectral_scan
+
+### HAL library (do no force multiple library rebuild even with 'make -B')
+
+$(LGW_PATH)/inc/config.h:
+ @if test ! -f $@; then \
+ $(MAKE) all -C $(LGW_PATH); \
+ fi
+
+$(LGW_PATH)/libloragw.a: $(LGW_INC)
+ @if test ! -f $@; then \
+ $(MAKE) all -C $(LGW_PATH); \
+ fi
+
+### Sub-modules compilation
+
+$(OBJDIR):
+ mkdir -p $(OBJDIR)
+
+$(OBJDIR)/%.o: src/%.c $(INCLUDES) | $(OBJDIR)
+ $(CC) -c $(CFLAGS) -I$(LGW_PATH)/inc $< -o $@
+
+### Main program assembly
+
+util_spectral_scan: $(OBJDIR)/util_spectral_scan.o
+ $(CC) -L$(LGW_PATH) $^ $(LIBS) -o $@
+
+### EOF
diff --git a/util_spectral_scan/readme.md b/util_spectral_scan/readme.md
new file mode 100644
index 0000000..6bcd33e
--- /dev/null
+++ b/util_spectral_scan/readme.md
@@ -0,0 +1,79 @@
+ ______ _
+ / _____) _ | |
+ ( (____ _____ ____ _| |_ _____ ____| |__
+ \____ \| ___ | (_ _) ___ |/ ___) _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+ (______/|_____)_|_|_| \__)_____)\____)_| |_|
+ (C)2014 Semtech-Cycleo
+
+Background Spectral Scan for LoRa gateway
+=========================================
+
+
+1. Introduction
+----------------
+
+This software is used to scan the spectral band where the LoRa gateway operates.
+It simply computes a RSSI histogram on several frequencies, that will help to
+detect occupied bands and get interferer profiles.
+It logs the histogram in a .csv file.
+
+This utility program is meant to run on the LoRa gateway reference design
+SX1301AP2 (with FPGA and additionnal SX127x).
+
+The background RSSI scan is a diagnostic tool and must be run on top of the
+gateway activity. Moreover the two SX1257 radios have to be configured in RX
+mode to optimize the matching impedance with SX127x. The 32MHz clock provided
+to the SX127x is available once SX1301 has enabled the two SX1257 radios, so
+the background RSSI scan must be launched after the packet forwarder.
+
+Note: if the FPGA running the spectral scan also supports Listen-Before-Talk
+feature (LBT), the LBT feature has to be enabled and running before launching
+util_spectral_scan. For example, if the lora_pkt_fwd runs in background, it has
+to use a global_conf.json file with "lbt_cfg.enable" set to true.
+
+2. Command line options
+------------------------
+
+`-h`
+will display a short help
+
+`-f start:step:stop`
+Frequency vector to scan in MHz: start:step:stop
+Valid range: start > 800, step > 0.005, stop < 1000
+
+`-b`
+Channel bandwidth to be used to configure the SX1272x radio for scanning in KHz
+Valid values: [25,50,100,125,200,250,500]
+
+`-n`
+Total number of RSSI points.
+Valid range: [1..65535]
+
+`-l`
+Log file name
+
+Note: For FPGA image that provides LBT support, the spectral scan gets less
+flexible. The following parameters have constraints:
+ - Frequency step: has to be multiple of 100KHz
+ - Channel bandwidth: hardcoded to 200KHz
+ - Number of RSSI points: 16641
+
+3. Usage
+---------
+
+The format of the log file is the following:
+Freq_1, RSSI_1, histo_1, ...., RSSI_128, histo_128
+Freq_2, RSSI_1, histo_1, ...., RSSI_128, histo_128
+...
+
+RSSI_n is the nth value of RSSI in dBm
+
+Default setup:
+- freq 863 : 0.2 : 870
+- 65535 RSSI points in total at 32kHz rate
+- 125KHz channel bandwidth
+
+Example with frequencies from 865 MHz to 870 MHz, by step of 100KHz, BW 200KHz
+10000 RSSI points processed at 10kHz rate, saved in "log.csv":
+./util_spectral_scan -f 865:0.1:870 -n 10000 -b 200 -l "log"
diff --git a/util_spectral_scan/src/util_spectral_scan.c b/util_spectral_scan/src/util_spectral_scan.c
new file mode 100644
index 0000000..d2aecda
--- /dev/null
+++ b/util_spectral_scan/src/util_spectral_scan.c
@@ -0,0 +1,403 @@
+/*
+ ______ _
+ / _____) _ | |
+( (____ _____ ____ _| |_ _____ ____| |__
+ \____ \| ___ | (_ _) ___ |/ ___) _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+ (C)2014 Semtech-Cycleo
+
+Description:
+ SX1301 spectral scan
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+Maintainer: Michael Coracin
+*/
+
+
+/* -------------------------------------------------------------------------- */
+/* --- DEPENDENCIES --------------------------------------------------------- */
+
+/* Fix an issue between POSIX and C99 */
+#if __STDC_VERSION__ >= 199901L
+ #define _XOPEN_SOURCE 600
+#else
+ #define _XOPEN_SOURCE 500
+#endif
+
+#include <stdint.h> /* C99 types */
+#include <stdio.h> /* NULL printf */
+#include <stdlib.h> /* EXIT atoi */
+#include <unistd.h> /* getopt */
+#include <string.h>
+
+#include "loragw_aux.h"
+#include "loragw_reg.h"
+#include "loragw_hal.h"
+#include "loragw_radio.h"
+#include "loragw_fpga.h"
+
+/* -------------------------------------------------------------------------- */
+/* --- MACROS & CONSTANTS --------------------------------------------------- */
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+
+#define DEFAULT_START_FREQ 863000000 /* start frequency, Hz */
+#define DEFAULT_STOP_FREQ 870000000 /* stop frequency, Hz */
+#define DEFAULT_STEP_FREQ 200000 /* frequency step, Hz */
+#define DEFAULT_RSSI_PTS 65535 /* number of RSSI reads */
+#define DEFAULT_CHAN_BW LGW_SX127X_RXBW_62K5_HZ /* channel bandwidth */
+#define DEFAULT_LOG_NAME "rssi_histogram"
+#define DEFAULT_SX127X_RSSI_OFFSET -4
+
+#define RSSI_RANGE 256
+
+#define MAX_FREQ 1000000000
+#define MIN_FREQ 800000000
+#define MIN_STEP_FREQ 5000
+
+#define FPGA_FEATURE_SPECTRAL_SCAN 1
+#define FPGA_FEATURE_LBT 2
+
+/* When FPGA supports LBT, there are few more constraints on above constants */
+#define LBT_DEFAULT_RSSI_PTS 129*129 /* number of RSSI reads, hard-coded in FPGA*/
+#define LBT_MIN_STEP_FREQ 100000
+
+/* -------------------------------------------------------------------------- */
+/* --- GLOBAL VARIABLES ----------------------------------------------------- */
+
+/* -------------------------------------------------------------------------- */
+/* --- MAIN FUNCTION -------------------------------------------------------- */
+
+int main( int argc, char ** argv )
+{
+ int i, j, k; /* loop and temporary variables */
+ int x; /* return code for functions */
+ int32_t reg_val;
+
+ /* Parameter parsing */
+ double arg_lf[3] = {0,0,0};
+ unsigned arg_u = 0;
+ int arg_i = 0;
+ char arg_s[64];
+
+ /* Application parameters */
+ uint32_t init_freq = DEFAULT_START_FREQ;
+ uint32_t start_freq = DEFAULT_START_FREQ;
+ uint32_t stop_freq = DEFAULT_STOP_FREQ;
+ uint32_t step_freq = DEFAULT_STEP_FREQ;
+ uint16_t rssi_pts = DEFAULT_RSSI_PTS;
+ int8_t rssi_offset = DEFAULT_SX127X_RSSI_OFFSET;
+ enum lgw_sx127x_rxbw_e channel_bw_khz = DEFAULT_CHAN_BW;
+ char log_file_name[64] = DEFAULT_LOG_NAME;
+ FILE * log_file = NULL;
+
+ /* Local var */
+ bool lbt_support = false;
+ int freq_idx;
+ int freq_nb;
+ uint64_t freq_reg;
+ uint32_t freq;
+ uint8_t read_burst[RSSI_RANGE*2];
+ uint16_t rssi_histo;
+ uint16_t rssi_cumu;
+ float rssi_thresh[] = {0.1,0.3,0.5,0.8,1};
+
+ /* Parse command line options */
+ while((i = getopt(argc, argv, "hf:n:b:l:o:")) != -1) {
+ switch (i) {
+ case 'h':
+ printf("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n");
+ printf(" -f <float>:<float>:<float> Frequency vector to scan in MHz (start:step:stop)\n");
+ printf(" start>%3.3f step>%1.3f stop<%3.3f\n", MIN_FREQ/1e6, MIN_STEP_FREQ/1e6, MAX_FREQ/1e6);
+ printf(" -b <uint> Channel bandwidth in KHz [25,50,100,125,200,250,500]\n");
+ printf(" -n <uint> Total number of RSSI points [1..65535]\n");
+ printf(" -o <int> Offset in dB to be applied to the SX127x RSSI [-128..127]\n");
+ printf(" -l <char> Log file name\n");
+ printf("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n");
+ return EXIT_SUCCESS;
+
+ case 'f': /* -f <float>:<float>:<float> Frequency vector to scan in MHz, start:step:stop */
+ j = sscanf(optarg, "%lf:%lf:%lf", &arg_lf[0], &arg_lf[1], &arg_lf[2]);
+ if ((j!=3) || (arg_lf[0] < MIN_FREQ/1e6) || (arg_lf[0] > MAX_FREQ/1e6) || (arg_lf[1] < MIN_STEP_FREQ/1e6) || (arg_lf[2] < MIN_FREQ/1e6) || (arg_lf[2] > MAX_FREQ/1e6)) {
+ printf("ERROR: argument parsing of -f argument. -h for help.\n");
+ return EXIT_FAILURE;
+ } else {
+ start_freq = (uint32_t)((arg_lf[0] * 1e6) + 0.5); /* .5 Hz offset to get rounding instead of truncating */
+ step_freq = (uint32_t)((arg_lf[1] * 1e6) + 0.5); /* .5 Hz offset to get rounding instead of truncating */
+ stop_freq = (uint32_t)((arg_lf[2] * 1e6) + 0.5); /* .5 Hz offset to get rounding instead of truncating */
+ }
+ break;
+
+ case 'b': /* -b <uint> Channel bandwidth in KHz [25,50,100,125,200,250,500] */
+ j = sscanf(optarg, "%u", &arg_u);
+ if (j != 1) {
+ printf("ERROR: argument parsing of -b argument. -h for help.\n");
+ return EXIT_FAILURE;
+ } else {
+ switch (arg_u) {
+ case 25:
+ channel_bw_khz = LGW_SX127X_RXBW_12K5_HZ;
+ break;
+ case 50:
+ channel_bw_khz = LGW_SX127X_RXBW_25K_HZ;
+ break;
+ case 100:
+ channel_bw_khz = LGW_SX127X_RXBW_50K_HZ;
+ break;
+ case 125:
+ channel_bw_khz = LGW_SX127X_RXBW_62K5_HZ;
+ break;
+ case 200:
+ channel_bw_khz = LGW_SX127X_RXBW_100K_HZ;
+ break;
+ case 250:
+ channel_bw_khz = LGW_SX127X_RXBW_125K_HZ;
+ break;
+ case 500:
+ channel_bw_khz = LGW_SX127X_RXBW_250K_HZ;
+ break;
+ default:
+ printf("ERROR: argument parsing of -b argument. -h for help.\n");
+ return EXIT_FAILURE;
+ }
+ }
+ break;
+
+ case 'n': /* -n <uint> Total number of RSSI points [1..65535] */
+ j = sscanf(optarg, "%u", &arg_u);
+ if ((j != 1) || (arg_u < 1) || (arg_u > 65535)) {
+ printf("ERROR: argument parsing of -n argument. -h for help.\n");
+ return EXIT_FAILURE;
+ } else {
+ rssi_pts = (uint16_t)arg_u;
+ }
+ break;
+
+ case 'o': /* -o <int> SX127x RSSI offset [-128..127] */
+ j = sscanf(optarg, "%i", &arg_i);
+ if ((j != 1) || (arg_i < -128) || (arg_i > 127)) {
+ printf("ERROR: argument parsing of -o argument. -h for help.\n");
+ return EXIT_FAILURE;
+ } else {
+ rssi_offset = (int8_t)arg_i;
+ }
+ break;
+
+ case 'l': /* -l <char> Log file name */
+ j = sscanf(optarg, "%s", arg_s);
+ if (j != 1) {
+ printf("ERROR: argument parsing of -l argument. -h for help.\n");
+ return EXIT_FAILURE;
+ } else {
+ sprintf(log_file_name, "%s", arg_s);
+ }
+ break;
+
+ default:
+ printf("ERROR: argument parsing options. -h for help.\n");
+ return EXIT_FAILURE;
+ }
+ }
+
+ /* Start message */
+ printf("+++ Start spectral scan of LoRa gateway channels +++\n");
+
+ x = lgw_connect(true, 0); /* SPI only, no FPGA reset/configure (for now) */
+ if(x != 0) {
+ printf("ERROR: Failed to connect to FPGA\n");
+ return EXIT_FAILURE;
+ }
+
+ /* Check if FPGA supports Spectral Scan */
+ lgw_fpga_reg_r(LGW_FPGA_FEATURE, &reg_val);
+ if (TAKE_N_BITS_FROM((uint8_t)reg_val, FPGA_FEATURE_SPECTRAL_SCAN, 1) != true) {
+ printf("ERROR: Spectral Scan is not supported (0x%x)\n", (uint8_t)reg_val);
+ return EXIT_FAILURE;
+ }
+
+ /* Check if FPGA supports LBT, in order to apply proper constraints on spectral scan parameters */
+ lgw_fpga_reg_r(LGW_FPGA_FEATURE, &reg_val);
+ if (TAKE_N_BITS_FROM((uint8_t)reg_val, FPGA_FEATURE_LBT, 1) == true) {
+ printf("WARNING: The FPGA supports LBT, so running spectral scan with specific constraints\n");
+ printf(" => Check the parameters summary below\n");
+ /* Get start frequency from FPGA */
+ lgw_fpga_reg_r(LGW_FPGA_LBT_INITIAL_FREQ, &reg_val);
+ switch (reg_val) {
+ case 0:
+ init_freq = 915000000;
+ break;
+ case 1:
+ init_freq = 863000000;
+ break;
+ default:
+ printf("ERROR: init frequency %d is not supported\n", reg_val);
+ return EXIT_FAILURE;
+ }
+
+ /* Check parameters based on LBT constraints */
+ if (start_freq < init_freq) {
+ printf("ERROR: start frequency %d is not supported, should be >=%d\n", start_freq, init_freq);
+ return EXIT_FAILURE;
+ }
+ if (stop_freq > (init_freq + 255*LBT_MIN_STEP_FREQ)) {
+ printf("ERROR: stop frequency %d is not supported, should be <%d\n", stop_freq, init_freq + 255*LBT_MIN_STEP_FREQ);
+ return EXIT_FAILURE;
+ }
+ if (step_freq < LBT_MIN_STEP_FREQ) {
+ printf("ERROR: step frequency %d is not supported, should be >=%d\n", step_freq, LBT_MIN_STEP_FREQ);
+ return EXIT_FAILURE;
+ } else {
+ /* Ensure the given step is a multiple of LBT_MIN_STEP_FREQ */
+ step_freq = (step_freq / LBT_MIN_STEP_FREQ) * LBT_MIN_STEP_FREQ;
+ }
+
+ /* Overload hard-coded spectral scan parameters */
+ rssi_pts = LBT_DEFAULT_RSSI_PTS;
+
+ /* Spectral scan sequence is slightly different depending if LBT is there or not */
+ lbt_support = true;
+ } else {
+ /* Reconnect to FPGA with sw reset and configure */
+ x = lgw_disconnect();
+ if(x != 0) {
+ printf("ERROR: Failed to disconnect from FPGA\n");
+ return EXIT_FAILURE;
+ }
+ x = lgw_connect(false, LGW_DEFAULT_NOTCH_FREQ); /* FPGA reset/configure */
+ if(x != 0) {
+ printf("ERROR: Failed to connect to FPGA\n");
+ return EXIT_FAILURE;
+ }
+ /* Some spectral scan options are only available when there is no LBT support */
+ x = lgw_fpga_reg_w(LGW_FPGA_HISTO_NB_READ, rssi_pts-1);
+ if( x != LGW_REG_SUCCESS )
+ {
+ printf( "ERROR: Failed to configure FPGA\n" );
+ return EXIT_FAILURE;
+ }
+
+ /* Initialize frequency */
+ freq_reg = ((uint64_t)start_freq << 19) / (uint64_t)32000000;
+ lgw_fpga_reg_w(LGW_FPGA_HISTO_SCAN_FREQ, (int32_t)freq_reg);
+ }
+
+ /* create log file */
+ strcat(log_file_name,".csv");
+ log_file = fopen(log_file_name, "w");
+ if (log_file == NULL) {
+ printf("ERROR: impossible to create log file %s\n", log_file_name);
+ return EXIT_FAILURE;
+ }
+ printf("Writing to file: %s\n", log_file_name);
+
+ /* Number of frequency steps */
+ freq_nb = (int)((stop_freq - start_freq) / step_freq) + 1;
+ printf("Scanning frequencies:\nstart: %d Hz\nstop : %d Hz\nstep : %d Hz\nnb : %d\n", start_freq, stop_freq, step_freq, freq_nb);
+
+ /* Main loop */
+ for(j = 0; j < freq_nb; j++) {
+ /* Current frequency */
+ freq = start_freq + j * step_freq;
+ printf("%d", freq);
+
+ if (lbt_support == false) {
+ /* Set SX127x */
+ x = lgw_setup_sx127x(freq, MOD_FSK, channel_bw_khz, rssi_offset);
+ if( x != 0 )
+ {
+ printf( "ERROR: SX127x setup failed\n" );
+ return EXIT_FAILURE;
+ }
+
+ /* Start FPGA state machine for spectral scal */
+ lgw_fpga_reg_w(LGW_FPGA_CTRL_FEATURE_START, 1);
+ } else {
+ /* Do Nothing */
+ /* LBT setup has already done the necessary */
+ }
+
+ /* Clean histogram */
+ lgw_fpga_reg_w(LGW_FPGA_CTRL_CLEAR_HISTO_MEM, 1);
+
+ /* Wait for histogram clean to start */
+ do {
+ wait_ms(10);
+ lgw_fpga_reg_r(LGW_FPGA_STATUS, &reg_val);
+ }
+ while((TAKE_N_BITS_FROM((uint8_t)reg_val, 0, 5)) != 1); /* Clear has started */
+
+ /* Set scan frequency during clear process */
+ if (lbt_support == false) {
+ /* We can directly set the scan frequency */
+ freq_reg = ((uint64_t)freq << 19) / (uint64_t)32000000;
+ lgw_fpga_reg_w(LGW_FPGA_HISTO_SCAN_FREQ, (int32_t)freq_reg);
+ } else {
+ /* The possible scan frequencies are hard-coded in FPGA, we give an offset from init_freq */
+ freq_idx = (freq - init_freq) / LBT_MIN_STEP_FREQ;
+ printf(" (idx=%i) ", freq_idx);
+ lgw_fpga_reg_w(LGW_FPGA_SCAN_FREQ_OFFSET, freq_idx);
+ }
+
+ /* Release FPGA state machine */
+ lgw_fpga_reg_w(LGW_FPGA_CTRL_CLEAR_HISTO_MEM, 0);
+
+ /* Wait for histogram ready */
+ do {
+ wait_ms(1000);
+ lgw_fpga_reg_r(LGW_FPGA_STATUS, &reg_val);
+ }
+ while((TAKE_N_BITS_FROM((uint8_t)reg_val, 5, 1)) != 1);
+
+ if (lbt_support == false) {
+ /* Stop FPGA state machine for spectral scan */
+ lgw_fpga_reg_w(LGW_FPGA_CTRL_FEATURE_START, 0);
+ } else {
+ /* Do Nothing */
+ /* LBT is running */
+ }
+
+ /* Read histogram */
+ lgw_fpga_reg_w(LGW_FPGA_CTRL_ACCESS_HISTO_MEM, 1); /* HOST gets access to FPGA RAM */
+ lgw_fpga_reg_w(LGW_FPGA_HISTO_RAM_ADDR, 0);
+ lgw_fpga_reg_rb(LGW_FPGA_HISTO_RAM_DATA, read_burst, RSSI_RANGE*2);
+ lgw_fpga_reg_w(LGW_FPGA_CTRL_ACCESS_HISTO_MEM, 0); /* FPGA gets access to RAM back */
+
+ /* Write data to CSV */
+ fprintf(log_file, "%d", freq);
+ rssi_cumu = 0;
+ k = 0;
+ for (i = 0; i < RSSI_RANGE; i++) {
+ rssi_histo = (uint16_t)read_burst[2*i] | ((uint16_t)read_burst[2*i+1] << 8);
+ fprintf(log_file, ",%.1f,%d", -i/2.0, rssi_histo);
+ rssi_cumu += rssi_histo;
+ if (rssi_cumu > rssi_pts) {
+ printf(" - WARNING: number of RSSI points higher than expected (%u,%u)", rssi_cumu, rssi_pts);
+ rssi_cumu = rssi_pts;
+ }
+ if (rssi_cumu > rssi_thresh[k]*rssi_pts) {
+ printf(" %d%%<%.1f", (uint16_t)(rssi_thresh[k]*100), -i/2.0);
+ k++;
+ }
+ }
+ fprintf(log_file, "\n");
+ printf("\n");
+ }
+ fclose(log_file);
+
+ /* Close SPI */
+ x = lgw_disconnect();
+ if(x != 0) {
+ printf("ERROR: Failed to disconnect FPGA\n");
+ return EXIT_FAILURE;
+ }
+
+ printf("+++ Exiting Spectral scan program +++\n");
+
+ return EXIT_SUCCESS;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+/* --- EOF ------------------------------------------------------------------ */
+
diff --git a/util_spi_stress/Makefile b/util_spi_stress/Makefile
new file mode 100644
index 0000000..23e3c88
--- /dev/null
+++ b/util_spi_stress/Makefile
@@ -0,0 +1,66 @@
+### Application-specific constants
+
+APP_NAME := util_spi_stress
+
+### Environment constants
+
+LGW_PATH ?= ../libloragw
+ARCH ?=
+CROSS_COMPILE ?=
+
+### External constant definitions
+# must get library build option to know if mpsse must be linked or not
+
+include $(LGW_PATH)/library.cfg
+
+### Constant symbols
+
+CC := $(CROSS_COMPILE)gcc
+AR := $(CROSS_COMPILE)ar
+
+CFLAGS=-O2 -Wall -Wextra -std=c99 -Iinc -I.
+
+OBJDIR = obj
+
+### Constants for LoRa concentrator HAL library
+# List the library sub-modules that are used by the application
+
+LGW_INC = $(LGW_PATH)/inc/config.h
+LGW_INC += $(LGW_PATH)/inc/loragw_reg.h
+
+### Linking options
+
+LIBS := -lloragw -lrt -lm
+
+### General build targets
+
+all: $(APP_NAME)
+
+clean:
+ rm -f $(OBJDIR)/*.o
+ rm -f $(APP_NAME)
+
+### HAL library (do no force multiple library rebuild even with 'make -B')
+
+$(LGW_PATH)/inc/config.h:
+ @if test ! -f $@; then \
+ $(MAKE) all -C $(LGW_PATH); \
+ fi
+
+$(LGW_PATH)/libloragw.a: $(LGW_INC)
+ @if test ! -f $@; then \
+ $(MAKE) all -C $(LGW_PATH); \
+ fi
+
+### Main program compilation and assembly
+
+$(OBJDIR):
+ mkdir -p $(OBJDIR)
+
+$(OBJDIR)/$(APP_NAME).o: src/$(APP_NAME).c $(LGW_INC) | $(OBJDIR)
+ $(CC) -c $(CFLAGS) -I$(LGW_PATH)/inc $< -o $@
+
+$(APP_NAME): $(OBJDIR)/$(APP_NAME).o $(LGW_PATH)/libloragw.a
+ $(CC) -L$(LGW_PATH) $< -o $@ $(LIBS)
+
+### EOF
diff --git a/util_spi_stress/readme.md b/util_spi_stress/readme.md
new file mode 100644
index 0000000..7848b0f
--- /dev/null
+++ b/util_spi_stress/readme.md
@@ -0,0 +1,93 @@
+ / _____) _ | |
+ ( (____ _____ ____ _| |_ _____ ____| |__
+ \____ \| ___ | (_ _) ___ |/ ___) _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+ (______/|_____)_|_|_| \__)_____)\____)_| |_|
+ (C)2013 Semtech-Cycleo
+
+LoRa concentrator SPI stress test
+==================================
+
+1. Introduction
+----------------
+
+This software is used to check the reliability of the link between the host
+platform (on which the program is run) and the LoRa concentrator register file
+that is the interface through which all interaction with the LoRa concentrator
+happens.
+
+2. Dependencies
+----------------
+
+This program only access the LoRa concentrator HAL library through its
+loragw_reg "named registers" access sub-module.
+
+It was tested with v1.3.0 of the libloragw library, and should be compatible
+with any later version of the library and the hardware, assuming the registers
+used for the tests are still present.
+
+The registers used are:
+ * LGW_VERSION
+ * LGW_IMPLICIT_PAYLOAD_LENGHT
+ * LGW_FSK_REF_PATTERN_LSB
+ * LGW_RX_DATA_BUF_ADDR
+ * LGW_RX_DATA_BUF_DATA
+
+A data buffer accessible through the 2 registers above must be implemented.
+
+3. Usage
+---------
+
+The tests run forever or until an error is detected.
+Press Ctrl+C to stop the application.
+
+When an error is detected, diagnosis information are displayed. Please refer to
+the source code for more details on what is displayed for diagnosis.
+
+All tests use pseudo-random data generated by the rand() function. The random
+generator is not seeded, and the same sequence of data will be use each time the
+program is launched.
+
+Basically, some random data is written, read back and then compared to the
+initial written data. Some "useless" read on others registers might be inserted
+to be sure that the data read back is coming from the hardware, and not from the
+internal buffer(s) of the software driver(s).
+
+Test 1 > R/W on a simple 8-bit register
+
+Test 2 > R/W on a simple 8-bit register with interstitial reads on VERSION
+
+Test 3 > R/W on a 32-bit register (short SPI bursts access)
+
+Test 4 > data buffer R/W (long SPI bursts access)
+
+4. License
+-----------
+
+Copyright (c) 2013, SEMTECH S.A.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+* Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+* Neither the name of the Semtech corporation nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL SEMTECH S.A. BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*EOF* \ No newline at end of file
diff --git a/util_spi_stress/src/util_spi_stress.c b/util_spi_stress/src/util_spi_stress.c
new file mode 100644
index 0000000..6cc5f04
--- /dev/null
+++ b/util_spi_stress/src/util_spi_stress.c
@@ -0,0 +1,292 @@
+/*
+ / _____) _ | |
+( (____ _____ ____ _| |_ _____ ____| |__
+ \____ \| ___ | (_ _) ___ |/ ___) _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+ (C)2013 Semtech-Cycleo
+
+Description:
+ SPI stress test
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+Maintainer: Sylvain Miermont
+*/
+
+
+/* -------------------------------------------------------------------------- */
+/* --- DEPENDANCIES --------------------------------------------------------- */
+
+/* fix an issue between POSIX and C99 */
+#if __STDC_VERSION__ >= 199901L
+ #define _XOPEN_SOURCE 600
+#else
+ #define _XOPEN_SOURCE 500
+#endif
+
+#include <stdint.h> /* C99 types */
+#include <stdbool.h> /* bool type */
+#include <stdio.h> /* printf fprintf sprintf fopen fputs */
+
+#include <signal.h> /* sigaction */
+#include <unistd.h> /* getopt access */
+#include <stdlib.h> /* rand */
+
+#include "loragw_reg.h"
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE MACROS ------------------------------------------------------- */
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+#define MSG(args...) fprintf(stderr, args) /* message that is destined to the user */
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE CONSTANTS ---------------------------------------------------- */
+
+#define VERS 103
+#define READS_WHEN_ERROR 16 /* number of times a read is repeated if there is a read error */
+#define BUFF_SIZE 1024 /* maximum number of bytes that we can write in sx1301 RX data buffer */
+#define DEFAULT_TX_NOTCH_FREQ 129E3
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE VARIABLES (GLOBAL) ------------------------------------------- */
+
+/* signal handling variables */
+struct sigaction sigact; /* SIGQUIT&SIGINT&SIGTERM signal handling */
+static int exit_sig = 0; /* 1 -> application terminates cleanly (shut down hardware, close open files, etc) */
+static int quit_sig = 0; /* 1 -> application terminates without shutting down the hardware */
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE FUNCTIONS DECLARATION ---------------------------------------- */
+
+static void sig_handler(int sigio);
+
+void usage (void);
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE FUNCTIONS DEFINITION ----------------------------------------- */
+
+static void sig_handler(int sigio) {
+ if (sigio == SIGQUIT) {
+ quit_sig = 1;;
+ } else if ((sigio == SIGINT) || (sigio == SIGTERM)) {
+ exit_sig = 1;
+ }
+}
+
+/* describe command line options */
+void usage(void) {
+ MSG( "Available options:\n");
+ MSG( " -h print this help\n");
+ MSG( " -t <int> specify which test you want to run (1-4)\n");
+}
+
+/* -------------------------------------------------------------------------- */
+/* --- MAIN FUNCTION -------------------------------------------------------- */
+
+int main(int argc, char **argv)
+{
+ int i;
+ int xi = 0;
+
+ /* application option */
+ int test_number = 1;
+ int cycle_number = 0;
+ int repeats_per_cycle = 1000;
+ bool error = false;
+
+ /* in/out variables */
+ int32_t test_value;
+ int32_t read_value;
+ int32_t rb1, rb2, rb3; /* interstitial readbacks, to flush buffers if needed */
+
+ /* data buffer */
+ int32_t test_addr;
+ uint8_t test_buff[BUFF_SIZE];
+ uint8_t read_buff[BUFF_SIZE];
+
+ /* parse command line options */
+ while ((i = getopt (argc, argv, "ht:")) != -1) {
+ switch (i) {
+ case 'h':
+ usage();
+ return EXIT_FAILURE;
+ break;
+
+ case 't':
+ i = sscanf(optarg, "%i", &xi);
+ if ((i != 1) || (xi < 1) || (xi > 4)) {
+ MSG("ERROR: invalid test number\n");
+ return EXIT_FAILURE;
+ } else {
+ test_number = xi;
+ }
+ break;
+
+ default:
+ MSG("ERROR: argument parsing use -h option for help\n");
+ usage();
+ return EXIT_FAILURE;
+ }
+ }
+ MSG("INFO: Starting LoRa concentrator SPI stress-test number %i\n", test_number);
+
+ /* configure signal handling */
+ sigemptyset(&sigact.sa_mask);
+ sigact.sa_flags = 0;
+ sigact.sa_handler = sig_handler;
+ sigaction(SIGQUIT, &sigact, NULL);
+ sigaction(SIGINT, &sigact, NULL);
+ sigaction(SIGTERM, &sigact, NULL);
+
+ /* start SPI link */
+ i = lgw_connect(false, DEFAULT_TX_NOTCH_FREQ);
+ if (i != LGW_REG_SUCCESS) {
+ MSG("ERROR: lgw_connect() did not return SUCCESS");
+ return EXIT_FAILURE;
+ }
+
+ if (test_number == 1) {
+ /* single 8b register R/W stress test */
+ while ((quit_sig != 1) && (exit_sig != 1)) {
+ printf("Cycle %i > ", cycle_number);
+ for (i=0; i<repeats_per_cycle; ++i) {
+ test_value = (rand() % 256);
+ lgw_reg_w(LGW_IMPLICIT_PAYLOAD_LENGHT, test_value);
+ lgw_reg_r(LGW_IMPLICIT_PAYLOAD_LENGHT, &read_value);
+ if (read_value != test_value) {
+ error = true;
+ break;
+ }
+ }
+ if (error) {
+ printf("error during the %ith iteration: write 0x%02X, read 0x%02X\n", i+1, test_value, read_value);
+ printf("Repeat read of target register:");
+ for (i=0; i<READS_WHEN_ERROR; ++i) {
+ lgw_reg_r(LGW_IMPLICIT_PAYLOAD_LENGHT, &read_value);
+ printf(" 0x%02X", read_value);
+ }
+ printf("\n");
+ return EXIT_FAILURE;
+ } else {
+ printf("did %i R/W on an 8 bits reg with no error\n", repeats_per_cycle);
+ ++cycle_number;
+ }
+ }
+ } else if (test_number == 2) {
+ /* single 8b register R/W with interstitial VERSION check stress test */
+ while ((quit_sig != 1) && (exit_sig != 1)) {
+ printf("Cycle %i > ", cycle_number);
+ for (i=0; i<repeats_per_cycle; ++i) {
+ test_value = (rand() % 256);
+ lgw_reg_r(LGW_VERSION, &rb1);
+ lgw_reg_w(LGW_IMPLICIT_PAYLOAD_LENGHT, test_value);
+ lgw_reg_r(LGW_VERSION, &rb2);
+ lgw_reg_r(LGW_IMPLICIT_PAYLOAD_LENGHT, &read_value);
+ lgw_reg_r(LGW_VERSION, &rb3);
+ if ((rb1 != VERS) || (rb2 != VERS) || (rb3 != VERS) || (read_value != test_value)) {
+ error = true;
+ break;
+ }
+ }
+ if (error) {
+ printf("error during the %ith iteration: write %02X, read %02X, version (%i, %i, %i)\n", i+1, test_value, read_value, rb1, rb2, rb3);
+ printf("Repeat read of target register:");
+ for (i=0; i<READS_WHEN_ERROR; ++i) {
+ lgw_reg_r(LGW_IMPLICIT_PAYLOAD_LENGHT, &read_value);
+ printf(" 0x%02X", read_value);
+ }
+ printf("\n");
+ return EXIT_FAILURE;
+ } else {
+ printf("did %i R/W on an 8 bits reg with no error\n", repeats_per_cycle);
+ ++cycle_number;
+ }
+ }
+ } else if (test_number == 3) {
+ /* 32b register R/W stress test */
+ while ((quit_sig != 1) && (exit_sig != 1)) {
+ printf("Cycle %i > ", cycle_number);
+ for (i=0; i<repeats_per_cycle; ++i) {
+ test_value = (rand() & 0x0000FFFF);
+ test_value += (int32_t)(rand() & 0x0000FFFF) << 16;
+ lgw_reg_w(LGW_FSK_REF_PATTERN_LSB, test_value);
+ lgw_reg_r(LGW_FSK_REF_PATTERN_LSB, &read_value);
+ if (read_value != test_value) {
+ error = true;
+ break;
+ }
+ }
+ if (error) {
+ printf("error during the %ith iteration: write 0x%08X, read 0x%08X\n", i+1, test_value, read_value);
+ printf("Repeat read of target register:");
+ for (i=0; i<READS_WHEN_ERROR; ++i) {
+ lgw_reg_r(LGW_FSK_REF_PATTERN_LSB, &read_value);
+ printf(" 0x%08X", read_value);
+ }
+ printf("\n");
+ return EXIT_FAILURE;
+ } else {
+ printf("did %i R/W on a 32 bits reg with no error\n", repeats_per_cycle);
+ ++cycle_number;
+ }
+ }
+ } else if (test_number == 4) {
+ /* databuffer R/W stress test */
+ while ((quit_sig != 1) && (exit_sig != 1)) {
+ for (i=0; i<BUFF_SIZE; ++i) {
+ test_buff[i] = rand() & 0xFF;
+ }
+ printf("Cycle %i > ", cycle_number);
+ test_addr = rand() & 0xFFFF;
+ lgw_reg_w(LGW_RX_DATA_BUF_ADDR, test_addr); /* write at random offset in memory */
+ lgw_reg_wb(LGW_RX_DATA_BUF_DATA, test_buff, BUFF_SIZE);
+ lgw_reg_w(LGW_RX_DATA_BUF_ADDR, test_addr); /* go back to start of segment */
+ lgw_reg_rb(LGW_RX_DATA_BUF_DATA, read_buff, BUFF_SIZE);
+ for (i=0; ((i<BUFF_SIZE) && (test_buff[i] == read_buff[i])); ++i);
+ if (i != BUFF_SIZE) {
+ printf("error during the buffer comparison\n");
+ printf("Written values:\n");
+ for (i=0; i<BUFF_SIZE; ++i) {
+ printf(" %02X ", test_buff[i]);
+ if (i%16 == 15) printf("\n");
+ }
+ printf("\n");
+ printf("Read values:\n");
+ for (i=0; i<BUFF_SIZE; ++i) {
+ printf(" %02X ", read_buff[i]);
+ if (i%16 == 15) printf("\n");
+ }
+ printf("\n");
+ lgw_reg_w(LGW_RX_DATA_BUF_ADDR, test_addr); /* go back to start of segment */
+ lgw_reg_rb(LGW_RX_DATA_BUF_DATA, read_buff, BUFF_SIZE);
+ printf("Re-read values:\n");
+ for (i=0; i<BUFF_SIZE; ++i) {
+ printf(" %02X ", read_buff[i]);
+ if (i%16 == 15) printf("\n");
+ }
+ printf("\n");
+ return EXIT_FAILURE;
+ } else {
+ printf("did a %i-byte R/W on a data buffer with no error\n", BUFF_SIZE);
+ ++cycle_number;
+ }
+ }
+ } else {
+ MSG("ERROR: invalid test number");
+ usage();
+ }
+
+ /* close SPI link */
+ i = lgw_disconnect();
+ if (i != LGW_REG_SUCCESS) {
+ MSG("ERROR: lgw_disconnect() did not return SUCCESS");
+ return EXIT_FAILURE;
+ }
+
+ MSG("INFO: Exiting LoRa concentrator SPI stress-test program\n");
+ return EXIT_SUCCESS;
+}
+
+/* --- EOF ------------------------------------------------------------------ */
+
diff --git a/util_tx_continuous/Makefile b/util_tx_continuous/Makefile
new file mode 100644
index 0000000..b07419b
--- /dev/null
+++ b/util_tx_continuous/Makefile
@@ -0,0 +1,68 @@
+### Application-specific constants
+
+APP_NAME := util_tx_continuous
+
+### Environment constants
+
+LGW_PATH ?= ../libloragw
+ARCH ?=
+CROSS_COMPILE ?=
+
+### External constant definitions
+# must get library build option to know if mpsse must be linked or not
+
+include $(LGW_PATH)/library.cfg
+
+### Constant symbols
+
+CC := $(CROSS_COMPILE)gcc
+AR := $(CROSS_COMPILE)ar
+
+CFLAGS=-O2 -Wall -Wextra -std=c99 -Iinc -I.
+
+OBJDIR = obj
+
+### Constants for LoRa concentrator HAL library
+# List the library sub-modules that are used by the application
+
+LGW_INC = $(LGW_PATH)/inc/config.h
+LGW_INC += $(LGW_PATH)/inc/loragw_hal.h
+LGW_INC += $(LGW_PATH)/inc/loragw_reg.h
+LGW_INC += $(LGW_PATH)/inc/loragw_aux.h
+
+### Linking options
+
+LIBS := -lloragw -lrt -lm
+
+### General build targets
+
+all: $(APP_NAME)
+
+clean:
+ rm -f $(OBJDIR)/*.o
+ rm -f $(APP_NAME)
+
+### HAL library (do no force multiple library rebuild even with 'make -B')
+
+$(LGW_PATH)/inc/config.h:
+ @if test ! -f $@; then \
+ $(MAKE) all -C $(LGW_PATH); \
+ fi
+
+$(LGW_PATH)/libloragw.a: $(LGW_INC)
+ @if test ! -f $@; then \
+ $(MAKE) all -C $(LGW_PATH); \
+ fi
+
+### Main program compilation and assembly
+
+$(OBJDIR):
+ mkdir -p $(OBJDIR)
+
+$(OBJDIR)/$(APP_NAME).o: src/$(APP_NAME).c $(LGW_INC) | $(OBJDIR)
+ $(CC) -c $(CFLAGS) -I$(LGW_PATH)/inc $< -o $@
+
+$(APP_NAME): $(OBJDIR)/$(APP_NAME).o $(LGW_PATH)/libloragw.a
+ $(CC) -L$(LGW_PATH) $< -o $@ $(LIBS)
+
+### EOF
diff --git a/util_tx_continuous/readme.md b/util_tx_continuous/readme.md
new file mode 100644
index 0000000..70a75ba
--- /dev/null
+++ b/util_tx_continuous/readme.md
@@ -0,0 +1,62 @@
+ ______ _
+ / _____) _ | |
+ ( (____ _____ ____ _| |_ _____ ____| |__
+ \____ \| ___ | (_ _) ___ |/ ___) _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+ (______/|_____)_|_|_| \__)_____)\____)_| |_|
+ (C)2014 Semtech-Cycleo
+
+Tx continuous program for LoRa concentrator
+===========================================
+
+
+1. Introduction
+----------------
+
+This software is used to set LoRa concentrator in Tx continuous mode, for
+spectral measurement.
+The user can set the modulation type, the modulation parameters, and the
+multiple gains of the Tx chain.
+The program runs indefinitely, until the user stops the application.
+
+
+2. Usage
+--------
+
+See command line help to get the list of all available options:
+./util_tx_continuous -h
+
+Example:
+./util_tx_continuous -f 868 -r 1257 --dig 0 --mix 14 --pa 3 --mod "LORA" --sf 7 --bw 125
+
+
+4. License
+-----------
+
+Copyright (c) 2013, SEMTECH S.A.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+* Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+* Neither the name of the Semtech corporation nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL SEMTECH S.A. BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*EOF*
diff --git a/util_tx_continuous/src/util_tx_continuous.c b/util_tx_continuous/src/util_tx_continuous.c
new file mode 100644
index 0000000..b081cce
--- /dev/null
+++ b/util_tx_continuous/src/util_tx_continuous.c
@@ -0,0 +1,454 @@
+/*
+ ______ _
+ / _____) _ | |
+( (____ _____ ____ _| |_ _____ ____| |__
+ \____ \| ___ | (_ _) ___ |/ ___) _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+ (C)2014 Semtech-Cycleo
+
+Description:
+ SX1301 tx continuous utility
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+Maintainer: Matthieu Leurent
+*/
+
+
+/* -------------------------------------------------------------------------- */
+/* --- DEPENDENCIES --------------------------------------------------------- */
+
+/* Fix an issue between POSIX and C99 */
+#if __STDC_VERSION__ >= 199901L
+ #define _XOPEN_SOURCE 600
+#else
+ #define _XOPEN_SOURCE 500
+#endif
+
+#include <stdint.h> /* C99 types */
+#include <stdbool.h> /* bool type */
+#include <stdio.h> /* printf fprintf sprintf fopen fputs */
+#include <string.h> /* memset */
+#include <signal.h> /* sigaction */
+#include <unistd.h> /* getopt access */
+#include <stdlib.h> /* exit codes */
+#include <getopt.h> /* getopt_long */
+
+#include "loragw_hal.h"
+#include "loragw_reg.h"
+#include "loragw_aux.h"
+
+/* -------------------------------------------------------------------------- */
+/* --- MACROS & CONSTANTS --------------------------------------------------- */
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+#define MSG(args...) fprintf(stderr, args) /* message that is destined to the user */
+
+#define TX_RF_CHAIN 0 /* TX only supported on radio A */
+#define DEFAULT_RSSI_OFFSET 0.0
+
+#define DEFAULT_FREQ_HZ 868e6
+#define DEFAULT_DIGITAL_GAIN 0
+#define DEFAULT_DAC_GAIN 3
+#define DEFAULT_MIXER_GAIN 14
+#define DEFAULT_PA_GAIN 3
+#define DEFAULT_MODULATION "LORA"
+#define DEFAULT_SF 7
+#define DEFAULT_BW_KHZ 125
+#define DEFAULT_BR_KBPS 50
+#define DEFAULT_FDEV_KHZ 25
+#define DEFAULT_BT 2
+#define DEFAULT_NOTCH_FREQ 129000U
+
+/* -------------------------------------------------------------------------- */
+/* --- GLOBAL VARIABLES ----------------------------------------------------- */
+
+/* Signal handling variables */
+static int exit_sig = 0; /* 1 -> application terminates cleanly (shut down hardware, close open files, etc) */
+static int quit_sig = 0; /* 1 -> application terminates without shutting down the hardware */
+
+/* -------------------------------------------------------------------------- */
+/* --- SUBFUNCTIONS DECLARATION --------------------------------------------- */
+
+static void sig_handler(int sigio);
+
+/* -------------------------------------------------------------------------- */
+/* --- MAIN FUNCTION -------------------------------------------------------- */
+
+int main(int argc, char **argv)
+{
+ static struct sigaction sigact; /* SIGQUIT&SIGINT&SIGTERM signal handling */
+
+ int i; /* loop and temporary variables */
+
+ /* Parameter parsing */
+ int option_index = 0;
+ static struct option long_options[] = {
+ {"dig", 1, 0, 0},
+ {"dac", 1, 0, 0},
+ {"mix", 1, 0, 0},
+ {"pa", 1, 0, 0},
+ {"mod", 1, 0, 0},
+ {"sf", 1, 0, 0},
+ {"bw", 1, 0, 0},
+ {"br", 1, 0, 0},
+ {"fdev", 1, 0, 0},
+ {"bt", 1, 0, 0},
+ {"notch", 1, 0, 0},
+ {0, 0, 0, 0}
+ };
+ unsigned int arg_u;
+ float arg_f;
+ char arg_s[64];
+
+ /* Application parameters */
+ uint32_t freq_hz = DEFAULT_FREQ_HZ;
+ uint8_t g_dig = DEFAULT_DIGITAL_GAIN;
+ uint8_t g_dac = DEFAULT_DAC_GAIN;
+ uint8_t g_mix = DEFAULT_MIXER_GAIN;
+ uint8_t g_pa = DEFAULT_PA_GAIN;
+ char mod[64] = DEFAULT_MODULATION;
+ uint8_t sf = DEFAULT_SF;
+ unsigned int bw_khz = DEFAULT_BW_KHZ;
+ float br_kbps = DEFAULT_BR_KBPS;
+ uint8_t fdev_khz = DEFAULT_FDEV_KHZ;
+ uint8_t bt = DEFAULT_BT;
+ uint32_t tx_notch_freq = DEFAULT_NOTCH_FREQ;
+
+ int32_t offset_i, offset_q;
+
+ /* RF configuration (TX fail if RF chain is not enabled) */
+ enum lgw_radio_type_e radio_type = LGW_RADIO_TYPE_SX1257;
+ struct lgw_conf_board_s boardconf;
+ struct lgw_conf_rxrf_s rfconf;
+ struct lgw_tx_gain_lut_s txlut;
+ struct lgw_pkt_tx_s txpkt;
+
+
+ /* Parse command line options */
+ while ((i = getopt_long (argc, argv, "hud::f:r:", long_options, &option_index)) != -1) {
+ switch (i) {
+ case 'h':
+ printf("~~~ Library version string~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n");
+ printf(" %s\n", lgw_version_info());
+ printf("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n");
+ printf(" -f <float> Tx RF frequency in MHz [800:1000]\n");
+ printf(" -r <int> Radio type (SX1255:1255, SX1257:1257)\n");
+ printf(" --notch <uint> Tx notch filter frequency in KhZ [126..250]\n");
+ printf(" --dig <uint> Digital gain trim, [0:3]\n");
+ printf(" 0:1, 1:7/8, 2:3/4, 3:1/2\n");
+ printf(" --mix <uint> Radio Tx mixer gain trim, [0:15]\n");
+ printf(" 15 corresponds to maximum gain, 1 LSB corresponds to 2dB step\n");
+ printf(" --pa <uint> PA gain trim, [0:3]\n");
+ printf(" --mod <char> Modulation type ['LORA','FSK','CW']\n");
+ printf(" --sf <uint> LoRa Spreading Factor, [7:12]\n");
+ printf(" --bw <uint> LoRa bandwidth in kHz, [125,250,500]\n");
+ printf(" --br <float> FSK bitrate in kbps, [0.5:250]\n");
+ printf(" --fdev <uint> FSK frequency deviation in kHz, [1:250]\n");
+ printf(" --bt <uint> FSK gaussian filter BT trim, [0:3]\n");
+ printf("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n");
+ return EXIT_SUCCESS;
+ break;
+
+ case 0:
+ if (strcmp(long_options[option_index].name,"dig") == 0) {
+ i = sscanf(optarg, "%u", &arg_u);
+ if ((i != 1) || (arg_u > 3)) {
+ printf("ERROR: argument parsing of --dig argument. Use -h to print help\n");
+ return EXIT_FAILURE;
+ }
+ else
+ {
+ g_dig = (uint8_t)arg_u;
+ }
+ }
+ else if (strcmp(long_options[option_index].name,"dac") == 0) {
+ i = sscanf(optarg, "%u", &arg_u);
+ if ((i != 1) || (arg_u > 3)) {
+ printf("ERROR: argument parsing of --dac argument. Use -h to print help\n");
+ return EXIT_FAILURE;
+ }
+ else {
+ g_dac = (uint8_t)arg_u;
+ }
+ }
+ else if (strcmp(long_options[option_index].name,"mix") == 0) {
+ i = sscanf(optarg, "%u", &arg_u);
+ if ((i != 1) || (arg_u > 15)) {
+ printf("ERROR: argument parsing of --mix argument. Use -h to print help\n");
+ return EXIT_FAILURE;
+ }
+ else {
+ g_mix = (uint8_t)arg_u;
+ }
+ }
+ else if (strcmp(long_options[option_index].name,"pa") == 0) {
+ i = sscanf(optarg, "%u", &arg_u);
+ if ((i != 1) || (arg_u > 3)) {
+ printf("ERROR: argument parsing of --pa argument. Use -h to print help\n");
+ return EXIT_FAILURE;
+ }
+ else {
+ g_pa = arg_u;
+ }
+ }
+ else if (strcmp(long_options[option_index].name,"mod") == 0) {
+ i = sscanf(optarg, "%s", arg_s);
+ if ((i != 1) || ((strcmp(arg_s,"LORA") != 0) && (strcmp(arg_s,"FSK") != 0) && (strcmp(arg_s,"CW") != 0))) {
+ printf("ERROR: argument parsing of --mod argument. Use -h to print help\n");
+ return EXIT_FAILURE;
+ }
+ else {
+ sprintf(mod, "%s", arg_s);
+ }
+ }
+ else if (strcmp(long_options[option_index].name,"sf") == 0) {
+ i = sscanf(optarg, "%u", &arg_u);
+ if ((i != 1) || (arg_u < 7) || (arg_u > 12)) {
+ printf("ERROR: argument parsing of --sf argument. Use -h to print help\n");
+ return EXIT_FAILURE;
+ }
+ else {
+ sf = (uint8_t)arg_u;
+ }
+ }
+ else if (strcmp(long_options[option_index].name,"bw") == 0) {
+ i = sscanf(optarg, "%u", &arg_u);
+ if ((i != 1) || ((arg_u != 125) && (arg_u != 250) && (arg_u != 500))) {
+ printf("ERROR: argument parsing of --bw argument. Use -h to print help\n");
+ return EXIT_FAILURE;
+ }
+ else {
+ bw_khz = arg_u;
+ }
+ }
+ else if (strcmp(long_options[option_index].name,"br") == 0) {
+ i = sscanf(optarg, "%f", &arg_f);
+ if ((i != 1) || (arg_f < 0.5) || (arg_f > 250)) {
+ printf("ERROR: argument parsing of --br argument. Use -h to print help\n");
+ return EXIT_FAILURE;
+ }
+ else {
+ br_kbps = arg_f;
+ }
+ }
+ else if (strcmp(long_options[option_index].name,"fdev") == 0) {
+ i = sscanf(optarg, "%u", &arg_u);
+ if ((i != 1) || (arg_u < 1) || (arg_u > 250)) {
+ printf("ERROR: argument parsing of --fdev argument. Use -h to print help\n");
+ return EXIT_FAILURE;
+ }
+ else {
+ fdev_khz = (uint8_t)arg_u;
+ }
+ }
+ else if (strcmp(long_options[option_index].name,"bt") == 0) {
+ i = sscanf(optarg, "%u", &arg_u);
+ if ((i != 1) || (arg_u > 3)) {
+ printf("ERROR: argument parsing of --bt argument. Use -h to print help\n");
+ return EXIT_FAILURE;
+ }
+ else {
+ bt = (uint8_t)arg_u;
+ }
+ }
+ else if (strcmp(long_options[option_index].name,"notch") == 0) {
+ i = sscanf(optarg, "%u", &arg_u);
+ if ((i != 1) || ((arg_u < 126) || (arg_u > 250))) {
+ printf("ERROR: argument parsing of --notch argument. Use -h to print help\n");
+ return EXIT_FAILURE;
+ }
+ else {
+ tx_notch_freq = (uint32_t)arg_u * 1000U;
+ }
+ }
+ else {
+ printf("ERROR: argument parsing options. Use -h to print help\n");
+ return EXIT_FAILURE;
+ }
+ break;
+
+ case 'f':
+ i = sscanf(optarg, "%f", &arg_f);
+ if ((i != 1) || (arg_f < 1)) {
+ printf("ERROR: argument parsing of -f argument. Use -h to print help\n");
+ return EXIT_FAILURE;
+ }
+ else {
+ freq_hz = (uint32_t)((arg_f * 1e6) + 0.5);
+ }
+ break;
+
+ case 'r':
+ i = sscanf(optarg, "%u", &arg_u);
+ switch (arg_u) {
+ case 1255:
+ radio_type = LGW_RADIO_TYPE_SX1255;
+ break;
+ case 1257:
+ radio_type = LGW_RADIO_TYPE_SX1257;
+ break;
+ default:
+ printf("ERROR: argument parsing of -r argument. Use -h to print help\n");
+ return EXIT_FAILURE;
+ }
+ break;
+
+ default:
+ printf("ERROR: argument parsing options. Use -h to print help\n");
+ return EXIT_FAILURE;
+ }
+ }
+
+ /* Configure signal handling */
+ sigemptyset( &sigact.sa_mask );
+ sigact.sa_flags = 0;
+ sigact.sa_handler = sig_handler;
+ sigaction( SIGQUIT, &sigact, NULL );
+ sigaction( SIGINT, &sigact, NULL );
+ sigaction( SIGTERM, &sigact, NULL );
+
+ /* Board config */
+ memset(&boardconf, 0, sizeof(boardconf));
+ boardconf.lorawan_public = true;
+ boardconf.clksrc = 1; /* Radio B is source by default */
+ lgw_board_setconf(boardconf);
+
+ /* RF config */
+ memset(&rfconf, 0, sizeof(rfconf));
+ rfconf.enable = true;
+ rfconf.freq_hz = freq_hz;
+ rfconf.rssi_offset = DEFAULT_RSSI_OFFSET;
+ rfconf.type = radio_type;
+ rfconf.tx_enable = true;
+ rfconf.tx_notch_freq = tx_notch_freq;
+ lgw_rxrf_setconf(TX_RF_CHAIN, rfconf);
+
+ /* Tx gain LUT */
+ memset(&txlut, 0, sizeof txlut);
+ txlut.size = 1;
+ txlut.lut[0].dig_gain = g_dig;
+ txlut.lut[0].pa_gain = g_pa;
+ txlut.lut[0].dac_gain = g_dac;
+ txlut.lut[0].mix_gain = g_mix;
+ txlut.lut[0].rf_power = 0;
+ lgw_txgain_setconf(&txlut);
+
+ /* Start the concentrator */
+ i = lgw_start();
+ if (i == LGW_HAL_SUCCESS) {
+ MSG("INFO: concentrator started, packet can be sent\n");
+ } else {
+ MSG("ERROR: failed to start the concentrator\n");
+ return EXIT_FAILURE;
+ }
+
+ /* fill-up payload and parameters */
+ memset(&txpkt, 0, sizeof(txpkt));
+ txpkt.freq_hz = freq_hz;
+ txpkt.tx_mode = IMMEDIATE;
+ txpkt.rf_chain = TX_RF_CHAIN;
+ txpkt.rf_power = 0;
+ if (strcmp(mod, "FSK") == 0) {
+ txpkt.modulation = MOD_FSK;
+ txpkt.datarate = br_kbps * 1e3;
+ } else {
+ txpkt.modulation = MOD_LORA;
+ switch (bw_khz) {
+ case 125: txpkt.bandwidth = BW_125KHZ; break;
+ case 250: txpkt.bandwidth = BW_250KHZ; break;
+ case 500: txpkt.bandwidth = BW_500KHZ; break;
+ default:
+ MSG("ERROR: invalid 'bw' variable\n");
+ return EXIT_FAILURE;
+ }
+ switch (sf) {
+ case 7: txpkt.datarate = DR_LORA_SF7; break;
+ case 8: txpkt.datarate = DR_LORA_SF8; break;
+ case 9: txpkt.datarate = DR_LORA_SF9; break;
+ case 10: txpkt.datarate = DR_LORA_SF10; break;
+ case 11: txpkt.datarate = DR_LORA_SF11; break;
+ case 12: txpkt.datarate = DR_LORA_SF12; break;
+ default:
+ MSG("ERROR: invalid 'sf' variable\n");
+ return EXIT_FAILURE;
+ }
+ }
+ txpkt.coderate = CR_LORA_4_5;
+ txpkt.f_dev = fdev_khz;
+ txpkt.preamble = 65535;
+ txpkt.invert_pol = false;
+ txpkt.no_crc = true;
+ txpkt.no_header = true;
+ txpkt.size = 1;
+ txpkt.payload[0] = 0;
+
+ /* Overwrite settings */
+ lgw_reg_w(LGW_TX_MODE, 1); /* Tx continuous */
+ lgw_reg_w(LGW_FSK_TX_GAUSSIAN_SELECT_BT, bt);
+ if (strcmp(mod, "CW") == 0) {
+ /* Enable signal generator with DC */
+ lgw_reg_w(LGW_SIG_GEN_FREQ, 0);
+ lgw_reg_w(LGW_SIG_GEN_EN, 1);
+ lgw_reg_w(LGW_TX_OFFSET_I, 0);
+ lgw_reg_w(LGW_TX_OFFSET_Q, 0);
+ }
+
+ /* Send packet */
+ i = lgw_send(txpkt);
+
+ /* Recap all settings */
+ printf("SX1301 library version: %s\n", lgw_version_info());
+ if (strcmp(mod, "LORA") == 0) {
+ printf("Modulation: LORA SF:%d BW:%d kHz\n", sf, bw_khz);
+ }
+ else if (strcmp(mod, "FSK") == 0) {
+ printf("Modulation: FSK BR:%3.3f kbps FDEV:%d kHz BT:%d\n", br_kbps, fdev_khz, bt);
+ }
+ else if (strcmp(mod, "CW") == 0) {
+ printf("Modulation: CW\n");
+ }
+ switch(rfconf.type) {
+ case LGW_RADIO_TYPE_SX1255:
+ printf("Radio Type: SX1255\n");
+ break;
+ case LGW_RADIO_TYPE_SX1257:
+ printf("Radio Type: SX1257\n");
+ break;
+ default:
+ printf("ERROR: undefined radio type\n");
+ break;
+ }
+ printf("Frequency: %4.3f MHz\n", freq_hz/1e6);
+ printf("TX Gains: Digital:%d DAC:%d Mixer:%d PA:%d\n", g_dig, g_dac, g_mix, g_pa);
+ if (strcmp(mod, "CW") != 0) {
+ lgw_reg_r(LGW_TX_OFFSET_I, &offset_i);
+ lgw_reg_r(LGW_TX_OFFSET_Q, &offset_q);
+ printf("Calibrated DC offsets: I:%d Q:%d\n", offset_i, offset_q);
+ }
+
+ /* waiting for user input */
+ while ((quit_sig != 1) && (exit_sig != 1)) {
+ wait_ms(100);
+ }
+
+ /* clean up before leaving */
+ lgw_stop();
+
+ return 0;
+}
+
+/* -------------------------------------------------------------------------- */
+/* --- SUBFUNCTIONS DEFINITION ---------------------------------------------- */
+
+static void sig_handler(int sigio)
+{
+ if (sigio == SIGQUIT) {
+ quit_sig = 1;
+ }
+ else if((sigio == SIGINT) || (sigio == SIGTERM)) {
+ exit_sig = 1;
+ }
+}
+
+/* --- EOF ------------------------------------------------------------------ */
diff --git a/util_tx_test/Makefile b/util_tx_test/Makefile
new file mode 100644
index 0000000..8c35229
--- /dev/null
+++ b/util_tx_test/Makefile
@@ -0,0 +1,67 @@
+### Application-specific constants
+
+APP_NAME := util_tx_test
+
+### Environment constants
+
+LGW_PATH ?= ../libloragw
+ARCH ?=
+CROSS_COMPILE ?=
+
+### External constant definitions
+# must get library build option to know if mpsse must be linked or not
+
+include $(LGW_PATH)/library.cfg
+
+### Constant symbols
+
+CC := $(CROSS_COMPILE)gcc
+AR := $(CROSS_COMPILE)ar
+
+CFLAGS=-O2 -Wall -Wextra -std=c99 -Iinc -I.
+
+OBJDIR = obj
+
+### Constants for LoRa concentrator HAL library
+# List the library sub-modules that are used by the application
+
+LGW_INC = $(LGW_PATH)/inc/config.h
+LGW_INC += $(LGW_PATH)/inc/loragw_hal.h
+LGW_INC += $(LGW_PATH)/inc/loragw_aux.h
+
+### Linking options
+
+LIBS := -lloragw -lrt -lm
+
+### General build targets
+
+all: $(APP_NAME)
+
+clean:
+ rm -f $(OBJDIR)/*.o
+ rm -f $(APP_NAME)
+
+### HAL library (do no force multiple library rebuild even with 'make -B')
+
+$(LGW_PATH)/inc/config.h:
+ @if test ! -f $@; then \
+ $(MAKE) all -C $(LGW_PATH); \
+ fi
+
+$(LGW_PATH)/libloragw.a: $(LGW_INC)
+ @if test ! -f $@; then \
+ $(MAKE) all -C $(LGW_PATH); \
+ fi
+
+### Main program compilation and assembly
+
+$(OBJDIR):
+ mkdir -p $(OBJDIR)
+
+$(OBJDIR)/$(APP_NAME).o: src/$(APP_NAME).c $(LGW_INC) | $(OBJDIR)
+ $(CC) -c $(CFLAGS) -I$(LGW_PATH)/inc $< -o $@
+
+$(APP_NAME): $(OBJDIR)/$(APP_NAME).o $(LGW_PATH)/libloragw.a
+ $(CC) -L$(LGW_PATH) $< -o $@ $(LIBS)
+
+### EOF
diff --git a/util_tx_test/readme.md b/util_tx_test/readme.md
new file mode 100644
index 0000000..c46badf
--- /dev/null
+++ b/util_tx_test/readme.md
@@ -0,0 +1,75 @@
+ / _____) _ | |
+ ( (____ _____ ____ _| |_ _____ ____| |__
+ \____ \| ___ | (_ _) ___ |/ ___) _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+ (______/|_____)_|_|_| \__)_____)\____)_| |_|
+ (C)2013 Semtech-Cycleo
+
+LoRa concentrator packet sender
+================================
+
+1. Introduction
+----------------
+
+This software is used to send test packets with a LoRa concentrator. The packets
+contain little information, on no protocol (ie. MAC address) information but
+can be used to assess the functionality of a gateway downlink using other
+gateways as receivers.
+
+2. Dependencies
+----------------
+
+This program is a typical example of LoRa concentrator HAL usage for sending
+packets.
+
+Only high-level functions are used (the ones contained in loragw_hal) so there
+is no hardware dependencies assuming the HAL is matched with the proper version
+of the hardware.
+Data structures of the sent packets are accessed by name (ie. not at a
+binary level) so new functionalities can be added to the API without affecting
+that program at all.
+
+3. Usage
+---------
+
+The application runs until the specified number of packets have been sent.
+Press Ctrl+C to stop the application before that.
+
+Use the -h to get help and details about available options.
+
+The payload content is:
+[T][E][S][T][packet counter MSB][packet counter LSB] followed by ASCII padding.
+
+All LoRa data is scrambled and whitened, so the padding has no influence
+whatsoever on the packet error rate.
+
+4. License
+-----------
+
+Copyright (c) 2013, SEMTECH S.A.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+* Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+* Neither the name of the Semtech corporation nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL SEMTECH S.A. BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*EOF*
diff --git a/util_tx_test/src/util_tx_test.c b/util_tx_test/src/util_tx_test.c
new file mode 100644
index 0000000..74c163f
--- /dev/null
+++ b/util_tx_test/src/util_tx_test.c
@@ -0,0 +1,661 @@
+/*
+ / _____) _ | |
+( (____ _____ ____ _| |_ _____ ____| |__
+ \____ \| ___ | (_ _) ___ |/ ___) _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+ (C)2013 Semtech-Cycleo
+
+Description:
+ Send a bunch of packets on a settable frequency
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+Maintainer: Sylvain Miermont
+*/
+
+
+/* -------------------------------------------------------------------------- */
+/* --- DEPENDANCIES --------------------------------------------------------- */
+
+/* fix an issue between POSIX and C99 */
+#if __STDC_VERSION__ >= 199901L
+ #define _XOPEN_SOURCE 600
+#else
+ #define _XOPEN_SOURCE 500
+#endif
+
+#include <stdint.h> /* C99 types */
+#include <stdbool.h> /* bool type */
+#include <stdio.h> /* printf fprintf sprintf fopen fputs */
+
+#include <string.h> /* memset */
+#include <signal.h> /* sigaction */
+#include <unistd.h> /* getopt access */
+#include <stdlib.h> /* exit codes */
+#include <getopt.h> /* getopt_long */
+
+#include "loragw_hal.h"
+#include "loragw_reg.h"
+#include "loragw_aux.h"
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE MACROS ------------------------------------------------------- */
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+#define MSG(args...) fprintf(stderr, args) /* message that is destined to the user */
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE CONSTANTS ---------------------------------------------------- */
+
+#define TX_RF_CHAIN 0 /* TX only supported on radio A */
+#define DEFAULT_RSSI_OFFSET 0.0
+#define DEFAULT_MODULATION "LORA"
+#define DEFAULT_BR_KBPS 50
+#define DEFAULT_FDEV_KHZ 25
+#define DEFAULT_NOTCH_FREQ 129000U /* 129 kHz */
+#define DEFAULT_SX127X_RSSI_OFFSET -4 /* dB */
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE VARIABLES (GLOBAL) ------------------------------------------- */
+
+/* signal handling variables */
+struct sigaction sigact; /* SIGQUIT&SIGINT&SIGTERM signal handling */
+static int exit_sig = 0; /* 1 -> application terminates cleanly (shut down hardware, close open files, etc) */
+static int quit_sig = 0; /* 1 -> application terminates without shutting down the hardware */
+
+/* TX gain LUT table */
+static struct lgw_tx_gain_lut_s txgain_lut = {
+ .size = 5,
+ .lut[0] = {
+ .dig_gain = 0,
+ .pa_gain = 0,
+ .dac_gain = 3,
+ .mix_gain = 12,
+ .rf_power = 0
+ },
+ .lut[1] = {
+ .dig_gain = 0,
+ .pa_gain = 1,
+ .dac_gain = 3,
+ .mix_gain = 12,
+ .rf_power = 10
+ },
+ .lut[2] = {
+ .dig_gain = 0,
+ .pa_gain = 2,
+ .dac_gain = 3,
+ .mix_gain = 10,
+ .rf_power = 14
+ },
+ .lut[3] = {
+ .dig_gain = 0,
+ .pa_gain = 3,
+ .dac_gain = 3,
+ .mix_gain = 9,
+ .rf_power = 20
+ },
+ .lut[4] = {
+ .dig_gain = 0,
+ .pa_gain = 3,
+ .dac_gain = 3,
+ .mix_gain = 14,
+ .rf_power = 27
+ }};
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE FUNCTIONS DECLARATION ---------------------------------------- */
+
+static void sig_handler(int sigio);
+
+void usage (void);
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE FUNCTIONS DEFINITION ----------------------------------------- */
+
+static void sig_handler(int sigio) {
+ if (sigio == SIGQUIT) {
+ quit_sig = 1;;
+ } else if ((sigio == SIGINT) || (sigio == SIGTERM)) {
+ exit_sig = 1;
+ }
+}
+
+/* describe command line options */
+void usage(void) {
+ int i;
+
+ printf("*** Library version information ***\n%s\n\n", lgw_version_info());
+ printf("Available options:\n");
+ printf(" -h print this help\n");
+ printf(" -r <int> radio type (SX1255:1255, SX1257:1257)\n");
+ printf(" -n <uint> TX notch filter frequency in kHz [126..250]\n");
+ printf(" -f <float> target frequency in MHz\n");
+ printf(" -k <uint> concentrator clock source (0:Radio A, 1:Radio B)\n");
+ printf(" -m <str> modulation type ['LORA', 'FSK']\n");
+ printf(" -b <uint> LoRa bandwidth in kHz [125, 250, 500]\n");
+ printf(" -s <uint> LoRa Spreading Factor [7-12]\n");
+ printf(" -c <uint> LoRa Coding Rate [1-4]\n");
+ printf(" -d <uint> FSK frequency deviation in kHz [1:250]\n");
+ printf(" -q <float> FSK bitrate in kbps [0.5:250]\n");
+ printf(" -p <int> RF power (dBm) [ ");
+ for (i = 0; i < txgain_lut.size; i++) {
+ printf("%ddBm ", txgain_lut.lut[i].rf_power);
+ }
+ printf("]\n");
+ printf(" -l <uint> LoRa preamble length (symbols)\n");
+ printf(" -z <uint> payload size (bytes, <256)\n");
+ printf(" -i send packet using inverted modulation polarity\n");
+ printf(" -t <uint> pause between packets (ms)\n");
+ printf(" -x <int> nb of times the sequence is repeated (-1 loop until stopped)\n");
+ printf(" --lbt-freq <float> lbt first channel frequency in MHz\n");
+ printf(" --lbt-nbch <uint> lbt number of channels [1..8]\n");
+ printf(" --lbt-sctm <uint> lbt scan time in usec to be applied to all channels [128, 5000]\n");
+ printf(" --lbt-rssi <int> lbt rssi target in dBm [-128..0]\n");
+ printf(" --lbt-rssi-offset <int> rssi offset in dB to be applied to SX127x RSSI [-128..127]\n");
+}
+
+/* -------------------------------------------------------------------------- */
+/* --- MAIN FUNCTION -------------------------------------------------------- */
+
+int main(int argc, char **argv)
+{
+ int i;
+ uint8_t status_var;
+
+ /* user entry parameters */
+ int xi = 0;
+ unsigned int xu = 0;
+ double xd = 0.0;
+ float xf = 0.0;
+ char arg_s[64];
+
+ /* application parameters */
+ char mod[64] = DEFAULT_MODULATION;
+ uint32_t f_target = 0; /* target frequency - invalid default value, has to be specified by user */
+ int sf = 10; /* SF10 by default */
+ int cr = 1; /* CR1 aka 4/5 by default */
+ int bw = 125; /* 125kHz bandwidth by default */
+ int pow = 14; /* 14 dBm by default */
+ int preamb = 8; /* 8 symbol preamble by default */
+ int pl_size = 16; /* 16 bytes payload by default */
+ int delay = 1000; /* 1 second between packets by default */
+ int repeat = -1; /* by default, repeat until stopped */
+ bool invert = false;
+ float br_kbps = DEFAULT_BR_KBPS;
+ uint8_t fdev_khz = DEFAULT_FDEV_KHZ;
+ bool lbt_enable = false;
+ uint32_t lbt_f_target = 0;
+ uint32_t lbt_sc_time = 5000;
+ int8_t lbt_rssi_target_dBm = -80;
+ int8_t lbt_rssi_offset_dB = DEFAULT_SX127X_RSSI_OFFSET;
+ uint8_t lbt_nb_channel = 1;
+ uint32_t sx1301_count_us;
+ uint32_t tx_notch_freq = DEFAULT_NOTCH_FREQ;
+
+ /* RF configuration (TX fail if RF chain is not enabled) */
+ enum lgw_radio_type_e radio_type = LGW_RADIO_TYPE_NONE;
+ uint8_t clocksource = 1; /* Radio B is source by default */
+ struct lgw_conf_board_s boardconf;
+ struct lgw_conf_lbt_s lbtconf;
+ struct lgw_conf_rxrf_s rfconf;
+
+ /* allocate memory for packet sending */
+ struct lgw_pkt_tx_s txpkt; /* array containing 1 outbound packet + metadata */
+
+ /* loop variables (also use as counters in the packet payload) */
+ uint16_t cycle_count = 0;
+
+ /* Parameter parsing */
+ int option_index = 0;
+ static struct option long_options[] = {
+ {"lbt-freq", required_argument, 0, 0},
+ {"lbt-sctm", required_argument, 0, 0},
+ {"lbt-rssi", required_argument, 0, 0},
+ {"lbt-nbch", required_argument, 0, 0},
+ {"lbt-rssi-offset", required_argument, 0, 0},
+ {0, 0, 0, 0}
+ };
+
+ /* parse command line options */
+ while ((i = getopt_long (argc, argv, "hif:n:m:b:s:c:p:l:z:t:x:r:k:d:q:", long_options, &option_index)) != -1) {
+ switch (i) {
+ case 'h':
+ usage();
+ return EXIT_FAILURE;
+ break;
+
+ case 'f': /* <float> Target frequency in MHz */
+ i = sscanf(optarg, "%lf", &xd);
+ if ((i != 1) || (xd < 30.0) || (xd > 3000.0)) {
+ MSG("ERROR: invalid TX frequency\n");
+ usage();
+ return EXIT_FAILURE;
+ } else {
+ f_target = (uint32_t)((xd*1e6) + 0.5); /* .5 Hz offset to get rounding instead of truncating */
+ }
+ break;
+
+ case 'n': /* <uint> TX notch filter frequency in kHz */
+ i = sscanf(optarg, "%i", &xi);
+ if ((i != 1) || ((xi < 126) || (xi > 250))) {
+ MSG("ERROR: invalid TX notch filter frequency\n");
+ usage();
+ return EXIT_FAILURE;
+ } else {
+ tx_notch_freq = xi*1000;
+ }
+ break;
+
+ case 'm': /* <str> Modulation type */
+ i = sscanf(optarg, "%s", arg_s);
+ if ((i != 1) || ((strcmp(arg_s,"LORA") != 0) && (strcmp(arg_s,"FSK")))) {
+ MSG("ERROR: invalid modulation type\n");
+ usage();
+ return EXIT_FAILURE;
+ } else {
+ sprintf(mod, "%s", arg_s);
+ }
+ break;
+
+ case 'b': /* <int> Modulation bandwidth in kHz */
+ i = sscanf(optarg, "%i", &xi);
+ if ((i != 1) || ((xi != 125) && (xi != 250) && (xi != 500))) {
+ MSG("ERROR: invalid LoRa bandwidth\n");
+ usage();
+ return EXIT_FAILURE;
+ } else {
+ bw = xi;
+ }
+ break;
+
+ case 's': /* <int> Spreading Factor */
+ i = sscanf(optarg, "%i", &xi);
+ if ((i != 1) || (xi < 7) || (xi > 12)) {
+ MSG("ERROR: invalid spreading factor\n");
+ usage();
+ return EXIT_FAILURE;
+ } else {
+ sf = xi;
+ }
+ break;
+
+ case 'c': /* <int> Coding Rate */
+ i = sscanf(optarg, "%i", &xi);
+ if ((i != 1) || (xi < 1) || (xi > 4)) {
+ MSG("ERROR: invalid coding rate\n");
+ usage();
+ return EXIT_FAILURE;
+ } else {
+ cr = xi;
+ }
+ break;
+
+ case 'p': /* <int> RF power */
+ i = sscanf(optarg, "%i", &xi);
+ if ((i != 1) || (xi < -60) || (xi > 60)) {
+ MSG("ERROR: invalid RF power\n");
+ usage();
+ return EXIT_FAILURE;
+ } else {
+ pow = xi;
+ }
+ break;
+
+ case 'd': /* <uint> FSK frequency deviation */
+ i = sscanf(optarg, "%u", &xu);
+ if ((i != 1) || (xu < 1) || (xu > 250)) {
+ MSG("ERROR: invalid FSK frequency deviation\n");
+ usage();
+ return EXIT_FAILURE;
+ } else {
+ fdev_khz = (uint8_t)xu;
+ }
+ break;
+
+ case 'q': /* <float> FSK bitrate */
+ i = sscanf(optarg, "%f", &xf);
+ if ((i != 1) || (xf < 0.5) || (xf > 250)) {
+ MSG("ERROR: invalid FSK bitrate\n");
+ usage();
+ return EXIT_FAILURE;
+ } else {
+ br_kbps = xf;
+ }
+ break;
+
+ case 'l': /* <uint> preamble length (symbols) */
+ i = sscanf(optarg, "%i", &xi);
+ if ((i != 1) || (xi < 6)) {
+ MSG("ERROR: preamble length must be >6 symbols \n");
+ usage();
+ return EXIT_FAILURE;
+ } else {
+ preamb = xi;
+ }
+ break;
+
+ case 'z': /* <uint> payload length (bytes) */
+ i = sscanf(optarg, "%i", &xi);
+ if ((i != 1) || (xi <= 0)) {
+ MSG("ERROR: invalid payload size\n");
+ usage();
+ return EXIT_FAILURE;
+ } else {
+ pl_size = xi;
+ }
+ break;
+
+ case 't': /* <int> pause between packets (ms) */
+ i = sscanf(optarg, "%i", &xi);
+ if ((i != 1) || (xi < 0)) {
+ MSG("ERROR: invalid time between packets\n");
+ usage();
+ return EXIT_FAILURE;
+ } else {
+ delay = xi;
+ }
+ break;
+
+ case 'x': /* <int> numbers of times the sequence is repeated */
+ i = sscanf(optarg, "%i", &xi);
+ if ((i != 1) || (xi < -1)) {
+ MSG("ERROR: invalid number of repeats\n");
+ usage();
+ return EXIT_FAILURE;
+ } else {
+ repeat = xi;
+ }
+ break;
+
+ case 'r': /* <int> Radio type (1255, 1257) */
+ sscanf(optarg, "%i", &xi);
+ switch (xi) {
+ case 1255:
+ radio_type = LGW_RADIO_TYPE_SX1255;
+ break;
+ case 1257:
+ radio_type = LGW_RADIO_TYPE_SX1257;
+ break;
+ default:
+ printf("ERROR: invalid radio type\n");
+ usage();
+ return EXIT_FAILURE;
+ }
+ break;
+
+ case 'i': /* Send packet using inverted modulation polarity */
+ invert = true;
+ break;
+
+ case 'k': /* <int> Concentrator clock source (Radio A or Radio B) */
+ i = sscanf(optarg, "%i", &xi);
+ if ((i != 1) || ((xi != 0) && (xi != 1))) {
+ MSG("ERROR: invalid clock source\n");
+ usage();
+ return EXIT_FAILURE;
+ } else {
+ clocksource = (uint8_t)xi;
+ }
+ break;
+
+ case 0:
+ if( strcmp(long_options[option_index].name, "lbt-freq") == 0 ) { /* <float> LBT first channel frequency in MHz */
+ i = sscanf(optarg, "%lf", &xd);
+ if ((i != 1) || (xd < 30.0) || (xd > 3000.0)) {
+ MSG("ERROR: invalid LBT start frequency\n");
+ usage();
+ return EXIT_FAILURE;
+ } else {
+ lbt_f_target = (uint32_t)((xd*1e6) + 0.5); /* .5 Hz offset to get rounding instead of truncating */
+ lbt_enable = true;
+ }
+ } else if( strcmp(long_options[option_index].name, "lbt-sctm") == 0 ) { /* <int> LBT scan time in usec */
+ if (lbt_enable == true) {
+ i = sscanf(optarg, "%i", &xi);
+ if ((i != 1) || (xi < 0)) {
+ MSG("ERROR: invalid LBT scan time\n");
+ usage();
+ return EXIT_FAILURE;
+ } else {
+ lbt_sc_time = xi;
+ }
+ } else {
+ MSG("ERROR: invalid parameter, LBT start frequency must be set\n");
+ usage();
+ return EXIT_FAILURE;
+ }
+ } else if( strcmp(long_options[option_index].name, "lbt-rssi") == 0 ) { /* <int> LBT RSSI target */
+ if (lbt_enable == true) {
+ i = sscanf(optarg, "%i", &xi);
+ if ((i != 1) || ((xi < -128) && (xi > 0))) {
+ MSG("ERROR: invalid LBT RSSI target\n");
+ usage();
+ return EXIT_FAILURE;
+ } else {
+ lbt_rssi_target_dBm = xi;
+ }
+ } else {
+ MSG("ERROR: invalid parameter, LBT start frequency must be set\n");
+ usage();
+ return EXIT_FAILURE;
+ }
+ } else if( strcmp(long_options[option_index].name, "lbt-rssi-offset") == 0 ) { /* <int> LBT RSSI offset */
+ if (lbt_enable == true) {
+ i = sscanf(optarg, "%i", &xi);
+ if ((i != 1) || ((xi < -128) && (xi > 127))) {
+ MSG("ERROR: invalid LBT RSSI offset\n");
+ usage();
+ return EXIT_FAILURE;
+ } else {
+ lbt_rssi_offset_dB = xi;
+ }
+ } else {
+ MSG("ERROR: invalid parameter, LBT start frequency must be set\n");
+ usage();
+ return EXIT_FAILURE;
+ }
+ } else if( strcmp(long_options[option_index].name, "lbt-nbch") == 0 ) { /* <int> LBT number of channels */
+ if (lbt_enable == true) {
+ i = sscanf(optarg, "%i", &xi);
+ if ((i != 1) || (xi < 0)) {
+ MSG("ERROR: invalid LBT number of channels\n");
+ usage();
+ return EXIT_FAILURE;
+ } else {
+ lbt_nb_channel = xi;
+ }
+ } else {
+ MSG("ERROR: invalid parameter, LBT start frequency must be set\n");
+ usage();
+ return EXIT_FAILURE;
+ }
+ }
+ break;
+ default:
+ MSG("ERROR: argument parsing\n");
+ usage();
+ return EXIT_FAILURE;
+ }
+ }
+
+ /* check parameter sanity */
+ if (f_target == 0) {
+ MSG("ERROR: frequency parameter not set, please use -f option to specify it.\n");
+ return EXIT_FAILURE;
+ }
+ if (radio_type == LGW_RADIO_TYPE_NONE) {
+ MSG("ERROR: radio type parameter not properly set, please use -r option to specify it.\n");
+ return EXIT_FAILURE;
+ }
+
+ /* Summary of packet parameters */
+ if (strcmp(mod, "FSK") == 0) {
+ printf("Sending %i FSK packets on %u Hz (FDev %u kHz, Bitrate %.2f, %i bytes payload, %i symbols preamble) at %i dBm, with %i ms between each\n", repeat, f_target, fdev_khz, br_kbps, pl_size, preamb, pow, delay);
+ } else {
+ printf("Sending %i LoRa packets on %u Hz (BW %i kHz, SF %i, CR %i, %i bytes payload, %i symbols preamble) at %i dBm, with %i ms between each\n", repeat, f_target, bw, sf, cr, pl_size, preamb, pow, delay);
+ }
+
+ /* configure signal handling */
+ sigemptyset(&sigact.sa_mask);
+ sigact.sa_flags = 0;
+ sigact.sa_handler = sig_handler;
+ sigaction(SIGQUIT, &sigact, NULL);
+ sigaction(SIGINT, &sigact, NULL);
+ sigaction(SIGTERM, &sigact, NULL);
+
+ /* starting the concentrator */
+ /* board config */
+ memset(&boardconf, 0, sizeof(boardconf));
+ boardconf.lorawan_public = true;
+ boardconf.clksrc = clocksource;
+ lgw_board_setconf(boardconf);
+
+ /* LBT config */
+ if (lbt_enable) {
+ memset(&lbtconf, 0, sizeof(lbtconf));
+ lbtconf.enable = true;
+ lbtconf.nb_channel = lbt_nb_channel;
+ lbtconf.rssi_target = lbt_rssi_target_dBm;
+ lbtconf.rssi_offset = lbt_rssi_offset_dB;
+ lbtconf.channels[0].freq_hz = lbt_f_target;
+ lbtconf.channels[0].scan_time_us = lbt_sc_time;
+ for (i=1; i<lbt_nb_channel; i++) {
+ lbtconf.channels[i].freq_hz = lbtconf.channels[i-1].freq_hz + 200E3; /* 200kHz offset for all channels */
+ lbtconf.channels[i].scan_time_us = lbt_sc_time;
+ }
+ lgw_lbt_setconf(lbtconf);
+ }
+
+ /* RF config */
+ memset(&rfconf, 0, sizeof(rfconf));
+ rfconf.enable = true;
+ rfconf.freq_hz = f_target;
+ rfconf.rssi_offset = DEFAULT_RSSI_OFFSET;
+ rfconf.type = radio_type;
+ for (i = 0; i < LGW_RF_CHAIN_NB; i++) {
+ if (i == TX_RF_CHAIN) {
+ rfconf.tx_enable = true;
+ rfconf.tx_notch_freq = tx_notch_freq;
+ } else {
+ rfconf.tx_enable = false;
+ }
+ lgw_rxrf_setconf(i, rfconf);
+ }
+
+ /* TX gain config */
+ lgw_txgain_setconf(&txgain_lut);
+
+ /* Start concentrator */
+ i = lgw_start();
+ if (i == LGW_HAL_SUCCESS) {
+ MSG("INFO: concentrator started, packet can be sent\n");
+ } else {
+ MSG("ERROR: failed to start the concentrator\n");
+ return EXIT_FAILURE;
+ }
+
+ /* fill-up payload and parameters */
+ memset(&txpkt, 0, sizeof(txpkt));
+ txpkt.freq_hz = f_target;
+ if (lbt_enable == true) {
+ txpkt.tx_mode = TIMESTAMPED;
+ } else {
+ txpkt.tx_mode = IMMEDIATE;
+ }
+ txpkt.rf_chain = TX_RF_CHAIN;
+ txpkt.rf_power = pow;
+ if( strcmp( mod, "FSK" ) == 0 ) {
+ txpkt.modulation = MOD_FSK;
+ txpkt.datarate = br_kbps * 1e3;
+ txpkt.f_dev = fdev_khz;
+ } else {
+ txpkt.modulation = MOD_LORA;
+ switch (bw) {
+ case 125: txpkt.bandwidth = BW_125KHZ; break;
+ case 250: txpkt.bandwidth = BW_250KHZ; break;
+ case 500: txpkt.bandwidth = BW_500KHZ; break;
+ default:
+ MSG("ERROR: invalid 'bw' variable\n");
+ return EXIT_FAILURE;
+ }
+ switch (sf) {
+ case 7: txpkt.datarate = DR_LORA_SF7; break;
+ case 8: txpkt.datarate = DR_LORA_SF8; break;
+ case 9: txpkt.datarate = DR_LORA_SF9; break;
+ case 10: txpkt.datarate = DR_LORA_SF10; break;
+ case 11: txpkt.datarate = DR_LORA_SF11; break;
+ case 12: txpkt.datarate = DR_LORA_SF12; break;
+ default:
+ MSG("ERROR: invalid 'sf' variable\n");
+ return EXIT_FAILURE;
+ }
+ switch (cr) {
+ case 1: txpkt.coderate = CR_LORA_4_5; break;
+ case 2: txpkt.coderate = CR_LORA_4_6; break;
+ case 3: txpkt.coderate = CR_LORA_4_7; break;
+ case 4: txpkt.coderate = CR_LORA_4_8; break;
+ default:
+ MSG("ERROR: invalid 'cr' variable\n");
+ return EXIT_FAILURE;
+ }
+ }
+ txpkt.invert_pol = invert;
+ txpkt.preamble = preamb;
+ txpkt.size = pl_size;
+ strcpy((char *)txpkt.payload, "TEST**abcdefghijklmnopqrstuvwxyz#0123456789#ABCDEFGHIJKLMNOPQRSTUVWXYZ#0123456789#abcdefghijklmnopqrstuvwxyz#0123456789#ABCDEFGHIJKLMNOPQRSTUVWXYZ#0123456789#abcdefghijklmnopqrstuvwxyz#0123456789#ABCDEFGHIJKLMNOPQRSTUVWXYZ#0123456789#abcdefghijklmnopqrs#" ); /* abc.. is for padding */
+
+ /* main loop */
+ cycle_count = 0;
+ while ((repeat == -1) || (cycle_count < repeat)) {
+ ++cycle_count;
+
+ /* refresh counters in payload (big endian, for readability) */
+ txpkt.payload[4] = (uint8_t)(cycle_count >> 8); /* MSB */
+ txpkt.payload[5] = (uint8_t)(cycle_count & 0x00FF); /* LSB */
+
+ /* When LBT is enabled, immediate send is not allowed, so we need
+ to set a timestamp to the packet */
+ if (lbt_enable == true) {
+ /* Get the current SX1301 time */
+ lgw_reg_w(LGW_GPS_EN, 0);
+ lgw_get_trigcnt(&sx1301_count_us);
+ lgw_reg_w(LGW_GPS_EN, 1);
+
+ /* Set packet timestamp to current time + few milliseconds */
+ txpkt.count_us = sx1301_count_us + 50E3;
+ }
+
+ /* send packet */
+ printf("Sending packet number %u ...", cycle_count);
+ i = lgw_send(txpkt); /* non-blocking scheduling of TX packet */
+ if (i == LGW_HAL_ERROR) {
+ printf("ERROR\n");
+ return EXIT_FAILURE;
+ } else if (i == LGW_LBT_ISSUE ) {
+ printf("Failed: Not allowed (LBT)\n");
+ } else {
+ /* wait for packet to finish sending */
+ do {
+ wait_ms(5);
+ lgw_status(TX_STATUS, &status_var); /* get TX status */
+ } while (status_var != TX_FREE);
+ printf("OK\n");
+ }
+
+ /* wait inter-packet delay */
+ wait_ms(delay);
+
+ /* exit loop on user signals */
+ if ((quit_sig == 1) || (exit_sig == 1)) {
+ break;
+ }
+ }
+
+ /* clean up before leaving */
+ lgw_stop();
+
+ printf("Exiting LoRa concentrator TX test program\n");
+ return EXIT_SUCCESS;
+}
+
+/* --- EOF ------------------------------------------------------------------ */