Host driver/HAL to build a LoRa Picocell Gateway which communicates through USB with a concentrator board based on Semtech SX1308 multi-channel modem and SX1257/SX1255 RF transceivers.

Files at this revision

API Documentation at this revision

Comitter:
dgabino
Date:
Wed Apr 11 14:38:42 2018 +0000
Commit message:
Initial commit

Changed in this revision

LICENSE Show annotated file Show diff for this revision Revisions of this file
Makefile Show annotated file Show diff for this revision Revisions of this file
VERSION Show annotated file Show diff for this revision Revisions of this file
libloragw/Makefile Show annotated file Show diff for this revision Revisions of this file
libloragw/inc/loragw_aux.h Show annotated file Show diff for this revision Revisions of this file
libloragw/inc/loragw_com.h Show annotated file Show diff for this revision Revisions of this file
libloragw/inc/loragw_com_linux.h Show annotated file Show diff for this revision Revisions of this file
libloragw/inc/loragw_hal.h Show annotated file Show diff for this revision Revisions of this file
libloragw/inc/loragw_mcu.h Show annotated file Show diff for this revision Revisions of this file
libloragw/inc/loragw_radio.h Show annotated file Show diff for this revision Revisions of this file
libloragw/inc/loragw_reg.h Show annotated file Show diff for this revision Revisions of this file
libloragw/inc/loragw_sx125x.h Show annotated file Show diff for this revision Revisions of this file
libloragw/library.cfg Show annotated file Show diff for this revision Revisions of this file
libloragw/readme.md Show annotated file Show diff for this revision Revisions of this file
libloragw/src/agc_fw.var Show annotated file Show diff for this revision Revisions of this file
libloragw/src/arb_fw.var Show annotated file Show diff for this revision Revisions of this file
libloragw/src/cal_fw.var Show annotated file Show diff for this revision Revisions of this file
libloragw/src/cal_fw5-12.var Show annotated file Show diff for this revision Revisions of this file
libloragw/src/loragw_aux.c Show annotated file Show diff for this revision Revisions of this file
libloragw/src/loragw_com.c Show annotated file Show diff for this revision Revisions of this file
libloragw/src/loragw_com_linux.c Show annotated file Show diff for this revision Revisions of this file
libloragw/src/loragw_hal.c Show annotated file Show diff for this revision Revisions of this file
libloragw/src/loragw_mcu.c Show annotated file Show diff for this revision Revisions of this file
libloragw/src/loragw_radio.c Show annotated file Show diff for this revision Revisions of this file
libloragw/src/loragw_reg.c Show annotated file Show diff for this revision Revisions of this file
libloragw/tst/test_loragw_cal.c Show annotated file Show diff for this revision Revisions of this file
libloragw/tst/test_loragw_hal.c Show annotated file Show diff for this revision Revisions of this file
libloragw/tst/test_loragw_reg.c Show annotated file Show diff for this revision Revisions of this file
lora_indent.sh Show annotated file Show diff for this revision Revisions of this file
readme.md Show annotated file Show diff for this revision Revisions of this file
util_boot/Makefile Show annotated file Show diff for this revision Revisions of this file
util_boot/readme.md Show annotated file Show diff for this revision Revisions of this file
util_boot/src/util_boot.c Show annotated file Show diff for this revision Revisions of this file
util_chip_id/Makefile Show annotated file Show diff for this revision Revisions of this file
util_chip_id/readme.md Show annotated file Show diff for this revision Revisions of this file
util_chip_id/src/util_chip_id.c Show annotated file Show diff for this revision Revisions of this file
util_com_stress/Makefile Show annotated file Show diff for this revision Revisions of this file
util_com_stress/readme.md Show annotated file Show diff for this revision Revisions of this file
util_com_stress/src/util_com_stress.c Show annotated file Show diff for this revision Revisions of this file
util_pkt_logger/Makefile Show annotated file Show diff for this revision Revisions of this file
util_pkt_logger/global_conf.json Show annotated file Show diff for this revision Revisions of this file
util_pkt_logger/inc/parson.h Show annotated file Show diff for this revision Revisions of this file
util_pkt_logger/local_conf.json Show annotated file Show diff for this revision Revisions of this file
util_pkt_logger/readme.md Show annotated file Show diff for this revision Revisions of this file
util_pkt_logger/src/parson.c Show annotated file Show diff for this revision Revisions of this file
util_pkt_logger/src/util_pkt_logger.c Show annotated file Show diff for this revision Revisions of this file
util_tx_continuous/Makefile Show annotated file Show diff for this revision Revisions of this file
util_tx_continuous/readme.md Show annotated file Show diff for this revision Revisions of this file
util_tx_continuous/src/util_tx_continuous.c Show annotated file Show diff for this revision Revisions of this file
util_tx_test/Makefile Show annotated file Show diff for this revision Revisions of this file
util_tx_test/readme.md Show annotated file Show diff for this revision Revisions of this file
util_tx_test/src/util_tx_test.c Show annotated file Show diff for this revision Revisions of this file
diff -r 000000000000 -r 102b50f941d0 LICENSE
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/LICENSE	Wed Apr 11 14:38:42 2018 +0000
@@ -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 -r 000000000000 -r 102b50f941d0 Makefile
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Makefile	Wed Apr 11 14:38:42 2018 +0000
@@ -0,0 +1,27 @@
+### Environment constants 
+
+ARCH ?=
+CROSS_COMPILE ?=
+export
+
+### general build targets
+
+all:
+	$(MAKE) all -e -C libloragw
+	$(MAKE) all -e -C util_boot
+	$(MAKE) all -e -C util_chip_id
+	$(MAKE) all -e -C util_pkt_logger
+	$(MAKE) all -e -C util_com_stress
+	$(MAKE) all -e -C util_tx_test
+	$(MAKE) all -e -C util_tx_continuous
+
+clean:
+	$(MAKE) clean -e -C libloragw
+	$(MAKE) clean -e -C util_boot
+	$(MAKE) clean -e -C util_chip_id
+	$(MAKE) clean -e -C util_pkt_logger
+	$(MAKE) clean -e -C util_com_stress
+	$(MAKE) clean -e -C util_tx_test
+	$(MAKE) clean -e -C util_tx_continuous
+
+### EOF
diff -r 000000000000 -r 102b50f941d0 VERSION
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/VERSION	Wed Apr 11 14:38:42 2018 +0000
@@ -0,0 +1,1 @@
+0.2.2
diff -r 000000000000 -r 102b50f941d0 libloragw/Makefile
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libloragw/Makefile	Wed Apr 11 14:38:42 2018 +0000
@@ -0,0 +1,95 @@
+### 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_reg test_loragw_hal 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_COM	$(DEBUG_COM)" >> $@
+	@echo "	#define DEBUG_REG	$(DEBUG_REG)" >> $@
+	@echo "	#define DEBUG_MCU	$(DEBUG_MCU)" >> $@
+	@echo "	#define DEBUG_HAL	$(DEBUG_HAL)" >> $@
+	# 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_com_linux.o: src/loragw_com_linux.c $(INCLUDES) inc/config.h | $(OBJDIR)
+	$(CC) -c $(CFLAGS) $< -o $@ 
+
+$(OBJDIR)/loragw_com.o: src/loragw_com.c $(INCLUDES) inc/config.h | $(OBJDIR)
+	$(CC) -c $(CFLAGS) $< -o $@
+
+$(OBJDIR)/loragw_mcu.o: src/loragw_mcu.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_mcu.o $(OBJDIR)/loragw_reg.o $(OBJDIR)/loragw_com.o $(OBJDIR)/loragw_com_linux.o $(OBJDIR)/loragw_aux.o $(OBJDIR)/loragw_radio.o
+	$(AR) rcs $@ $^
+
+### test programs
+
+test_loragw_com: tst/test_loragw_com.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 -r 000000000000 -r 102b50f941d0 libloragw/inc/loragw_aux.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libloragw/inc/loragw_aux.h	Wed Apr 11 14:38:42 2018 +0000
@@ -0,0 +1,51 @@
+/*
+ / _____)             _              | |
+( (____  _____ ____ _| |_ _____  ____| |__
+ \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+  (C)2017 Semtech-Cycleo
+
+Description:
+    LoRa concentrator HAL common auxiliary functions
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+
+*/
+
+
+#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_linux(unsigned long t);
+void wait_ns_linux(unsigned long t);
+void wait_ms(unsigned long t);
+void wait_ns(unsigned long t);
+
+#endif
+
+/* --- EOF ------------------------------------------------------------------ */
diff -r 000000000000 -r 102b50f941d0 libloragw/inc/loragw_com.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libloragw/inc/loragw_com.h	Wed Apr 11 14:38:42 2018 +0000
@@ -0,0 +1,182 @@
+/*
+ / _____)             _              | |
+( (____  _____ ____ _| |_ _____  ____| |__
+ \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+  (C)2017 Semtech-Cycleo
+
+Description:
+  A communication bridge layer to abstract linux/windows OS or others.
+  The current project support only linux os
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+
+*/
+
+#ifndef _LORAGW_COM_H
+#define _LORAGW_COM_H
+
+/* -------------------------------------------------------------------------- */
+/* --- DEPENDANCIES --------------------------------------------------------- */
+
+#include <stdint.h>     /* C99 types*/
+
+#include "config.h"     /* library configuration options (dynamically generated) */
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC CONSTANTS ----------------------------------------------------- */
+
+#define LGW_COM_SUCCESS     0
+#define LGW_COM_ERROR       -1
+#define LGW_BURST_CHUNK     1024
+#define LGW_COM_MUX_MODE0   0x0     /* No FPGA */
+#define LGW_COM_MUX_TARGET_SX1301   0x0
+
+#define ATOMICTX 600
+#define ATOMICRX 900
+
+#define CMD_HEADER_TX_SIZE 4 /* id + len_msb + len_lsb + address */
+#define CMD_HEADER_RX_SIZE 4 /* id + len_msb + len_lsb + status */
+
+#define CMD_DATA_TX_SIZE ATOMICTX
+#define CMD_DATA_RX_SIZE (1024 + 16 * 44) /* MAX_FIFO + 16 * METADATA_SIZE_ALIGNED */
+
+#define ACK_OK 1
+#define ACK_KO 0
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC TYPES --------------------------------------------------------- */
+
+/**
+@struct lgw_com_cmd_t
+@brief structure for host to mcu commands
+*/
+/********************************************************/
+/*   cmd name   |      description                      */
+/*------------------------------------------------------*/
+/*  r           |Read register                          */
+/*  s           |Read long burst First packet           */
+/*  t           |Read long burst Middle packet          */
+/*  u           |Read long burst End packet             */
+/*  p           |Read atomic burst packet               */
+/*  w           |Write register                         */
+/*  x           |Write long burst First packet          */
+/*  y           |Write long burst Middle packet         */
+/*  z           |Write long burst End packet            */
+/*  a           |Write atomic burst packet              */
+/*------------------------------------------------------*/
+/*  b           |lgw_receive cmd                        */
+/*  c           |lgw_rxrf_setconf cmd                   */
+/*  d           |int lgw_rxif_setconf_cmd               */
+/*  f           |int lgw_send cmd                       */
+/*  h           |lgw_txgain_setconf                     */
+/*  q           |lgw_trigger                            */
+/*  i           |lgw_board_setconf                      */
+/*  j           |lgw_calibration_snapshot               */
+/*  l           |lgw_check_fw_version                   */
+/*  m           |Reset STM32                            */
+/*  n           |Go to bootloader                       */
+/********************************************************/
+
+typedef struct {
+    char id;                            /*!> command ID */
+    uint8_t len_msb;                    /*!> command length MSB */
+    uint8_t len_lsb;                    /*!> command length LSB */
+    uint8_t address;                    /*!> register address for register read/write commands */
+    uint8_t cmd_data[CMD_DATA_TX_SIZE]; /*!> raw data to be transfered */
+} lgw_com_cmd_t;
+
+/**
+@struct lgw_com_ans_t
+@brief structure for mcu to host command answers
+*/
+typedef struct {
+    char id;                            /*!> command ID */
+    uint8_t len_msb;                    /*!> command length MSB */
+    uint8_t len_lsb;                    /*!> command length LSB */
+    uint8_t status;                     /*!> command acknoledge */
+    uint8_t ans_data[CMD_DATA_RX_SIZE]; /*!> raw answer data */
+} lgw_com_ans_t;
+
+/**
+@brief Generic file handle for communication bridge
+*/
+#ifdef _WIN32
+    typedef HANDLE lgw_handle_t;
+    #define LGW_GET_HANDLE(x) ((lgw_handle_t *)x)
+#elif __linux__
+    typedef int lgw_handle_t;
+    #define LGW_GET_HANDLE(x) (*(lgw_handle_t *)x)
+#endif
+
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC FUNCTIONS PROTOTYPES ------------------------------------------ */
+
+/**
+@brief LoRa concentrator USB setup
+@param com_target_ptr pointer on a generic pointer to USB target
+@return status of register operation (LGW_COM_SUCCESS/LGW_COM_ERROR)
+*/
+
+int lgw_com_open(void **com_target_ptr, const char *com_path);
+
+/**
+@brief LoRa concentrator USB close
+@param com_target generic pointer to USB target
+@return status of register operation (LGW_COM_SUCCESS/LGW_COM_ERROR)
+*/
+
+int lgw_com_close(void *com_target);
+
+/**
+@brief LoRa usb bridge to spi sx1308 concentrator single-byte write
+@param com_target generic pointer to USB target
+@param address 7-bit register address
+@param data data byte to write
+@return status of register operation (LGW_COM_SUCCESS/LGW_COM_ERROR)
+*/
+int lgw_com_w(void *com_target, uint8_t com_mux_mode, uint8_t com_mux_target, uint8_t address, uint8_t data);
+
+/**
+@brief  LoRa usb bridge to spi sx1308 concentrator single-byte read
+@param com_target generic pointer to USB target
+@param address 7-bit register address
+@param data data byte to write
+@return status of register operation (LGW_COM_SUCCESS/LGW_COM_ERROR)
+*/
+int lgw_com_r(void *com_target, uint8_t com_mux_mode, uint8_t com_mux_target, uint8_t address, uint8_t *data);
+
+/**
+@brief LoRa usb bridge to spi sx1308 concentrator  burst (multiple-byte) write
+@param com_target generic pointer to USB target
+@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_COM_SUCCESS/LGW_COM_ERROR)
+*/
+int lgw_com_wb(void *com_target, uint8_t com_mux_mode, uint8_t com_mux_target, uint8_t address, uint8_t *data, uint16_t size);
+
+/**
+@brief LoRa usb bridge to spi sx1308 concentrator burst (multiple-byte) read
+@param com_target generic pointer to USB target
+@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_COM_SUCCESS/LGW_COM_ERROR)
+*/
+int lgw_com_rb(void *com_target, uint8_t com_mux_mode, uint8_t com_mux_target, uint8_t address, uint8_t *data, uint16_t size);
+
+/**
+@brief Send command to concentrator through MCU, and wait for answer
+@param com_target generic pointer to USB target
+@param cmd command to be sent to the concentrator
+@param ans answer received from the concentrator
+@return status of operation (LGW_COM_SUCCESS/LGW_COM_ERROR)
+*/
+int lgw_com_send_command(void *com_target, lgw_com_cmd_t cmd, lgw_com_ans_t *ans);
+
+#endif
+
+/* --- EOF ------------------------------------------------------------------ */
diff -r 000000000000 -r 102b50f941d0 libloragw/inc/loragw_com_linux.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libloragw/inc/loragw_com_linux.h	Wed Apr 11 14:38:42 2018 +0000
@@ -0,0 +1,106 @@
+/*
+ / _____)             _              | |
+( (____  _____ ____ _| |_ _____  ____| |__
+ \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+  (C)2017 Semtech-Cycleo
+
+Description:
+this file contains the USB cmd to configure and communicate with
+the Sx1308 LoRA concentrator.
+An USB CDC drivers is required to establish the connection with the picogateway board.
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+*/
+
+
+#ifndef _LORAGW_com_linux_H
+#define _LORAGW_com_linux_H
+
+/* -------------------------------------------------------------------------- */
+/* --- DEPENDANCIES --------------------------------------------------------- */
+
+#include <stdint.h>     /* C99 types*/
+
+#include "config.h"     /* library configuration options _linux(dynamically generated) */
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC CONSTANTS ----------------------------------------------------- */
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC FUNCTIONS PROTOTYPES ------------------------------------------ */
+
+/**
+@brief LoRa concentrator COM setup (configure I/O and peripherals)
+@param com_target_ptr pointer on a generic pointer to COM target
+@return status of register operation (LGW_COM_SUCCESS/LGW_COM_ERROR)
+*/
+
+int lgw_com_open_linux(void **com_target_ptr, const char *com_path);
+
+/**
+@brief LoRa concentrator COM close
+@param com_target generic pointer to COM target
+@return status of register operation (LGW_COM_SUCCESS/LGW_COM_ERROR)
+*/
+
+int lgw_com_close_linux(void *com_target);
+
+/**
+@brief LoRa concentrator COM single-byte write
+@param com_target generic pointer to COM target
+@param address 7-bit register address
+@param data data byte to write
+@return status of register operation (LGW_COM_SUCCESS/LGW_COM_ERROR)
+*/
+int lgw_com_w_linux(void *com_target, uint8_t com_mux_mode, uint8_t com_mux_target, uint8_t address, uint8_t data);
+
+/**
+@brief LoRa concentrator COM single-byte read
+@param com_target generic pointer to COM target
+@param address 7-bit register address
+@param data data byte to write
+@return status of register operation (LGW_COM_SUCCESS/LGW_COM_ERROR)
+*/
+int lgw_com_r_linux(void *com_target, uint8_t com_mux_mode, uint8_t com_mux_target, uint8_t address, uint8_t *data);
+
+/**
+@brief LoRa concentrator COM burst (multiple-byte) write
+@param com_target generic pointer to COM target
+@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_COM_SUCCESS/LGW_COM_ERROR)
+*/
+int lgw_com_wb_linux(void *com_target, uint8_t com_mux_mode, uint8_t com_mux_target, uint8_t address, uint8_t *data, uint16_t size);
+
+/**
+@brief LoRa concentrator COM burst (multiple-byte) read
+@param com_target generic pointer to COM target
+@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_COM_SUCCESS/LGW_COM_ERROR)
+*/
+int lgw_com_rb_linux(void *com_target, uint8_t com_mux_mode, uint8_t com_mux_target, uint8_t address, uint8_t *data, uint16_t size);
+
+/**
+@brief Send command to LoRa concentrator through COM interface
+@param cmd command to be sent to the concentrator
+@param handle COM bridge handle
+@return status of operation (LGW_COM_SUCCESS/LGW_COM_ERROR)
+*/
+int lgw_com_send_cmd_linux(lgw_com_cmd_t cmd, lgw_handle_t handle);
+
+/**
+@brief Receive answer to the previously sent command from the LoRa concentrator through COM interface
+@param ans answer received from to the concentrator
+@param handle COM bridge handle
+@return status of operation (LGW_COM_SUCCESS/LGW_COM_ERROR)
+*/
+int lgw_com_receive_ans_linux(lgw_com_ans_t *ans, lgw_handle_t handle);
+
+#endif
+
+/* --- EOF ------------------------------------------------------------------ */
diff -r 000000000000 -r 102b50f941d0 libloragw/inc/loragw_hal.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libloragw/inc/loragw_hal.h	Wed Apr 11 14:38:42 2018 +0000
@@ -0,0 +1,392 @@
+/*
+ / _____)             _              | |
+( (____  _____ ____ _| |_ _____  ____| |__
+ \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+  (C)2017 Semtech-Cycleo
+
+Description:
+    LoRa concentrator Hardware Abstraction Layer
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+
+*/
+
+
+#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
+
+/* 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
+
+/* -------------------------------------------------------------------------- */
+/* --- 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_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 */
+};
+
+/**
+@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 */
+};
+#define LGW_PKT_RX_METADATA_SIZE_ALIGNED 44
+/* ---------- WARNING -------------
+This metadata size is used to convert the byte array received from the MCU to a
+lgw_pkt_rx_s structure. Structure members are 64-bits aligned in the byte array.
+Any modification of this structure has to be done with caution!
+--------------WARNING ------------- */
+#define LGW_PKT_RX_STRUCT_SIZE_ALIGNED (256 + LGW_PKT_RX_METADATA_SIZE_ALIGNED)
+
+/**
+@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 */
+};
+#define LGW_PKT_TX_METADATA_SIZE_ALIGNED 30
+/* ---------- WARNING -------------
+This metadata size is used to convert a lgw_pkt_tx_s structure to the byte array
+sent to the MCU to. The structure members are 64-bits aligned in the byte array.
+Any modification of this structure has to be done with caution!
+--------------WARNING ------------- */
+#define LGW_PKT_TX_STRUCT_SIZE_ALIGNED (256 + LGW_PKT_TX_METADATA_SIZE_ALIGNED)
+
+/**
+@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 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 1.5 ms delay for the analog circuitry to start and be stable (TX_START_DELAY).
+In 'timestamp' mode, this is transparent: the modem is started 1.5ms 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 TX_START_DELAY, then the packet is emitted.
+In 'triggered' mode (aka PPS/GPS mode), the packet, typically a beacon, is emitted 1.5ms 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 Allow user to check the version of the concentrator MCU firmware
+@return An integer value representing the firmware version
+*/
+int lgw_mcu_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 -r 000000000000 -r 102b50f941d0 libloragw/inc/loragw_mcu.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libloragw/inc/loragw_mcu.h	Wed Apr 11 14:38:42 2018 +0000
@@ -0,0 +1,118 @@
+/*
+ / _____)             _              | |
+( (____  _____ ____ _| |_ _____  ____| |__
+ \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+  (C)2017 Semtech-Cycleo
+
+Description:
+ Wrapper to call MCU's HAL functions
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+*/
+
+#ifndef _LORAGW_MCU_H
+#define _LORAGW_MCU_H
+
+/* -------------------------------------------------------------------------- */
+/* --- DEPENDANCIES --------------------------------------------------------- */
+
+#include <stdint.h>     /* C99 types*/
+
+#include "config.h"     /* library configuration options (dynamically generated) */
+
+#include "loragw_hal.h"
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC CONSTANTS ----------------------------------------------------- */
+
+#define LGW_MCU_SUCCESS 0
+#define LGW_MCU_ERROR   -1
+
+#define STM32FWVERSION 0x010a0006 /* increment LSB for new version */
+
+#define MCU_DELAY_COM_INIT 1000
+#define MCU_DELAY_RESET 200
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC TYPES --------------------------------------------------------- */
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC FUNCTIONS PROTOTYPES ------------------------------------------ */
+
+/**
+@brief Command to configure the board of the LoRa concentrator through MCU
+@param conf board configuration structure to be sent to MCU
+@return status of operation (LGW_MCU_SUCCESS/LGW_MCU_ERROR)
+*/
+int lgw_mcu_board_setconf(struct lgw_conf_board_s conf);
+
+/**
+@brief Command to configure an RF chain through MCU
+@param rfchain index of the RF chain to configure
+@param conf RF chain configuration structure to be sent to MCU
+@return status of operation (LGW_MCU_SUCCESS/LGW_MCU_ERROR)
+*/
+int lgw_mcu_rxrf_setconf(uint8_t rfchain, struct lgw_conf_rxrf_s conf);
+
+/**
+@brief Command to configure an IF chain through MCU
+@param ifchain index of the IF chain to configure
+@param conf IF chain configuration structure to be sent to MCU
+@return status of operation (LGW_MCU_SUCCESS/LGW_MCU_ERROR)
+*/
+int lgw_mcu_rxif_setconf(uint8_t ifchain, struct lgw_conf_rxif_s conf);
+
+/**
+@brief Command to configure the Tx gain LUT through MCU
+@param conf TX LUT gain table configuration structure to be sent to MCU
+@return status of operation (LGW_MCU_SUCCESS/LGW_MCU_ERROR)
+*/
+int lgw_mcu_txgain_setconf(struct lgw_tx_gain_lut_s *conf);
+
+/**
+@brief Command to receive packet from the concentrator through MCU
+@param max_pkt maximum number of received packets
+@param pkt_data array of packets received
+@return number of received packets
+*/
+int lgw_mcu_receive(uint8_t max_pkt, struct lgw_pkt_rx_s *pkt_data);
+
+/**
+@brief Command to send a packet to the concentrator through MCU
+@param pkt_data packet data to be sent to MCU
+@return status of operation (LGW_MCU_SUCCESS/LGW_MCU_ERROR)
+*/
+int lgw_mcu_send(struct lgw_pkt_tx_s pkt_data);
+
+/**
+@brief Command to get the value of the internal counter of the concentrator through MCU
+@param data pointer to byte array that will be read from the concentrator
+@return status of operation (LGW_MCU_SUCCESS/LGW_MCU_ERROR)
+*/
+int lgw_mcu_get_trigcnt(uint32_t *data);
+
+/**
+@brief Command to store radio calibration parameters to the concentrator through MCU
+@param idx_start start index in the MCU calibration offset table where to store the given offsets
+@param idx_nb the number of calibration offsets to be stored in the MCU table
+@return status of operation (LGW_MCU_SUCCESS/LGW_MCU_ERROR)
+*/
+int lgw_mcu_commit_radio_calibration(uint8_t idx_start, uint8_t idx_nb);
+
+/**
+@brief Command to reset the MCU
+@return status of operation (LGW_MCU_SUCCESS/LGW_MCU_ERROR)
+*/
+int lgw_mcu_reset(void);
+
+/**
+@brief Command to get the MCU's unique ID
+@return status of operation (LGW_MCU_SUCCESS/LGW_MCU_ERROR)
+*/
+int lgw_mcu_get_unique_id(uint8_t *uid);
+
+#endif
+
+/* --- EOF ------------------------------------------------------------------ */
diff -r 000000000000 -r 102b50f941d0 libloragw/inc/loragw_radio.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libloragw/inc/loragw_radio.h	Wed Apr 11 14:38:42 2018 +0000
@@ -0,0 +1,42 @@
+/*
+ / _____)             _              | |
+( (____  _____ ____ _| |_ _____  ____| |__
+ \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+  (C)2017 Semtech-Cycleo
+
+Description:
+    Functions used to handle LoRa concentrator radios.
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+
+*/
+
+#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 ----------------------------------------------------- */
+
+/* -------------------------------------------------------------------------- */
+/* --- 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);
+
+#endif
+/* --- EOF ------------------------------------------------------------------ */
diff -r 000000000000 -r 102b50f941d0 libloragw/inc/loragw_reg.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libloragw/inc/loragw_reg.h	Wed Apr 11 14:38:42 2018 +0000
@@ -0,0 +1,455 @@
+/*
+ / _____)             _              | |
+( (____  _____ ____ _| |_ _____  ____| |__
+ \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+  (C)2017 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
+
+*/
+
+#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 *com_target, uint8_t com_mux_mode, uint8_t com_mux_target, struct lgw_reg_s r, int32_t reg_value);
+int reg_r_align32(void *com_target, uint8_t com_mux_mode, uint8_t com_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 communication link
+@return status of register operation (LGW_REG_SUCCESS/LGW_REG_ERROR)
+*/
+int lgw_connect(const char *com_path);
+
+/**
+@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 -r 000000000000 -r 102b50f941d0 libloragw/inc/loragw_sx125x.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libloragw/inc/loragw_sx125x.h	Wed Apr 11 14:38:42 2018 +0000
@@ -0,0 +1,49 @@
+/*
+ / _____)             _              | |
+( (____  _____ ____ _| |_ _____  ____| |__
+ \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+    (C)2017 Semtech
+
+Description: SX125x radio registers and constant definitions
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+
+
+*/
+#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 -r 000000000000 -r 102b50f941d0 libloragw/library.cfg
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libloragw/library.cfg	Wed Apr 11 14:38:42 2018 +0000
@@ -0,0 +1,11 @@
+# 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_COM= 0
+DEBUG_REG= 0
+DEBUG_MCU= 0
+DEBUG_HAL= 0
diff -r 000000000000 -r 102b50f941d0 libloragw/readme.md
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libloragw/readme.md	Wed Apr 11 14:38:42 2018 +0000
@@ -0,0 +1,317 @@
+	 / _____)             _              | |    
+	( (____  _____ ____ _| |_ _____  ____| |__  
+	 \____ \| ___ |    (_   _) ___ |/ ___)  _ \ 
+	 _____) ) ____| | | || |_| ____( (___| | | |
+	(______/|_____)_|_|_| \__)_____)\____)_| |_|
+	  (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 modules:
+
+* loragw_hal
+* loragw_reg
+* loragw_mcu
+* loragw_com
+* loragw_aux
+* loragw_radio
+
+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 1.5 ms delay for the analog circuitry to
+start and be stable (TX_START_DELAY).
+
+In 'timestamp' mode, this is transparent: the modem is started 1.5ms 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 TX_START_DELAY, then the packet is emitted.
+
+In 'triggered' mode (aka PPS/GPS mode), the packet, typically a beacon, is 
+emitted 1.5ms 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_mcu ###
+
+This module wraps the HAL functions into commands to be sent to the concentrator
+MCU.
+
+The HAL structures are serialized in a byte array and sent over the COM/USB
+interface.
+
+* board configuration
+* send/receive packets
+* ...
+
+### 2.3. 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.4. loragw_com ###
+
+This module contains the functions to access the LoRa concentrator register
+array through the USB/UART interface:
+
+* lgw_com_r to read one byte
+* lgw_com_w to write one byte
+* lgw_com_rb to read two bytes or more
+* lgw_com_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.5. 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.6. loragw_radio ###
+
+This module contains functions to handle the configuration of SX125x radios.
+
+
+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. USB/UART communication ###
+
+loragw_com contains 4 functions (read, write, burst read, burst write) that are
+platform-dependant.
+The functions must be rewritten depending on the communication bridge you use:
+
+* USB/UART over linux tty port (provided)
+
+You can use the test program test_loragw_com to check that the USB communication
+is working.
+
+
+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 -r 000000000000 -r 102b50f941d0 libloragw/src/agc_fw.var
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libloragw/src/agc_fw.var	Wed Apr 11 14:38:42 2018 +0000
@@ -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 -r 000000000000 -r 102b50f941d0 libloragw/src/arb_fw.var
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libloragw/src/arb_fw.var	Wed Apr 11 14:38:42 2018 +0000
@@ -0,0 +1,529 @@
+/*
+ / _____)             _              | |
+( (____  _____ ____ _| |_ _____  ____| |__
+ \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+  (C)2017 Semtech-Cycleo
+
+Description:
+	Arbiter firmware
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+
+*/
+
+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 -r 000000000000 -r 102b50f941d0 libloragw/src/cal_fw.var
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libloragw/src/cal_fw.var	Wed Apr 11 14:38:42 2018 +0000
@@ -0,0 +1,529 @@
+/*
+ / _____)             _              | |
+( (____  _____ ____ _| |_ _____  ____| |__
+ \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+  (C)2017 Semtech-Cycleo
+
+Description:
+	Calibration firmware
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+
+*/
+
+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 -r 000000000000 -r 102b50f941d0 libloragw/src/cal_fw5-12.var
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libloragw/src/cal_fw5-12.var	Wed Apr 11 14:38:42 2018 +0000
@@ -0,0 +1,529 @@
+/*
+ / _____)             _              | |
+( (____  _____ ____ _| |_ _____  ____| |__
+ \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+  (C)2017 Semtech-Cycleo
+
+Description:
+	AGC firmware
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+
+*/
+
+static uint8_t callow_firmware[MCU_AGC_FW_BYTE] = {
+0x8A, 0x51, 0xD4, 0x6F, 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, 0x0C, 0x28, 0xA2, 0xC0, 0x10, 0xF0, 0x22, 0xC2, 0x22, 0xC8, 0x03, 0x18, 
+0x1E, 0xA8, 0x1F, 0xBE, 0x84, 0x80, 0x8A, 0x95, 0x00, 0x60, 0x08, 0x40, 0xA1, 0xC0, 0x03, 0xD0, 
+0xA1, 0x4C, 0x03, 0xD0, 0xA1, 0x4C, 0x03, 0xD0, 0xA1, 0x4C, 0x21, 0xC8, 0x01, 0xBE, 0x84, 0x80, 
+0x8A, 0x95, 0x00, 0x60, 0x08, 0x40, 0xA3, 0x41, 0x23, 0x08, 0xEA, 0xBE, 0x84, 0x80, 0x23, 0x08, 
+0xA1, 0xC0, 0x00, 0xB0, 0xBE, 0xE0, 0x8A, 0x51, 0x83, 0x93, 0x80, 0x40, 0x23, 0x08, 0xE8, 0x7E, 
+0x84, 0x80, 0x23, 0x08, 0xA1, 0xC0, 0x01, 0xF0, 0xBE, 0xE0, 0x8A, 0x51, 0x83, 0x93, 0x80, 0x40, 
+0x23, 0x08, 0xE6, 0xBE, 0x84, 0x80, 0x23, 0x08, 0xA1, 0xC0, 0x02, 0xF0, 0xBE, 0xE0, 0x8A, 0x51, 
+0x83, 0x93, 0x80, 0x40, 0x23, 0x08, 0xE4, 0x7E, 0x84, 0x80, 0x23, 0x08, 0xA1, 0xC0, 0x03, 0x30, 
+0xBE, 0xE0, 0x8A, 0x51, 0x83, 0x93, 0x80, 0x40, 0x23, 0x08, 0xE2, 0x7E, 0x84, 0x80, 0x23, 0x08, 
+0xA1, 0xC0, 0x04, 0xF0, 0xBE, 0xE0, 0x8A, 0x51, 0x83, 0x93, 0x80, 0x40, 0x23, 0x08, 0xE0, 0x3E, 
+0x84, 0x80, 0x23, 0x08, 0xA1, 0xC0, 0x05, 0x30, 0xBE, 0xE0, 0x8A, 0x51, 0x83, 0x93, 0x80, 0x40, 
+0x23, 0x08, 0xDE, 0xFE, 0x84, 0x80, 0x23, 0x08, 0xA1, 0xC0, 0x06, 0x30, 0xBE, 0xE0, 0x8A, 0x51, 
+0x83, 0x93, 0x80, 0x40, 0x23, 0x08, 0xAC, 0x7E, 0x84, 0x80, 0x23, 0x08, 0xA1, 0xC0, 0x08, 0xF0, 
+0xBE, 0xE0, 0x8A, 0x51, 0x83, 0xD7, 0x80, 0x40, 0x23, 0x08, 0xAA, 0x7E, 0x84, 0x80, 0x23, 0x08, 
+0xA1, 0xC0, 0x0A, 0x30, 0xBE, 0xE0, 0x8A, 0x51, 0x83, 0xD7, 0x80, 0x40, 0x23, 0x08, 0xA8, 0x3E, 
+0x84, 0x80, 0x23, 0x08, 0xA1, 0xC0, 0x0B, 0x70, 0xBE, 0xE0, 0x8A, 0x51, 0x83, 0xD7, 0x80, 0x40, 
+0x23, 0x08, 0xA6, 0x7E, 0x84, 0x80, 0x23, 0x08, 0xA1, 0xC0, 0x0C, 0x30, 0xBE, 0xE0, 0x8A, 0x51, 
+0x83, 0xD7, 0x80, 0x40, 0x23, 0x08, 0xA4, 0x3E, 0x84, 0x80, 0x23, 0x08, 0xA1, 0xC0, 0x0D, 0x70, 
+0xBE, 0xE0, 0x8A, 0x51, 0x83, 0xD7, 0x80, 0x40, 0x23, 0x08, 0xA2, 0x3E, 0x84, 0x80, 0x23, 0x08, 
+0xA1, 0xC0, 0x0E, 0x70, 0xBE, 0xE0, 0x8A, 0x51, 0x83, 0xD7, 0x80, 0x40, 0x23, 0x08, 0xA0, 0xFE, 
+0x84, 0x80, 0x23, 0x08, 0xA1, 0xC0, 0x10, 0xF0, 0xBE, 0xE0, 0x8A, 0x51, 0x83, 0xD7, 0x80, 0x40, 
+0x02, 0xF0, 0xA3, 0x8A, 0x23, 0x02, 0x03, 0x18, 0x08, 0x40, 0x2C, 0x68, 0xA2, 0xC0, 0x21, 0xC8, 
+0x03, 0x59, 0xC7, 0xE8, 0x22, 0xC8, 0x86, 0xC0, 0x22, 0xC8, 0x86, 0xC0, 0xCB, 0xE8, 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, 
+0x61, 0xA3, 0x8A, 0x51, 0x38, 0x08, 0x02, 0xBE, 0xA1, 0xC0, 0x02, 0xF0, 0xA2, 0xC0, 0x54, 0x70, 
+0x61, 0xA3, 0x8A, 0x51, 0x02, 0xF0, 0xA1, 0xC0, 0x54, 0x70, 0xEB, 0x63, 0x8A, 0x51, 0xDD, 0x80, 
+0xDD, 0xDF, 0xE2, 0xA8, 0x02, 0xF0, 0xA1, 0xC0, 0x57, 0xF0, 0xEB, 0x63, 0x8A, 0x51, 0xB5, 0x40, 
+0x02, 0xF0, 0xA1, 0xC0, 0x58, 0x70, 0xEB, 0x63, 0x8A, 0x51, 0xB6, 0x40, 0x3B, 0x88, 0x25, 0x3E, 
+0x84, 0x80, 0x36, 0x48, 0xFF, 0xE3, 0x8A, 0x51, 0xA4, 0xC0, 0x35, 0x48, 0xFF, 0xE3, 0x8A, 0x51, 
+0x24, 0x47, 0x83, 0x93, 0x80, 0x40, 0x0F, 0xB0, 0xBB, 0x0A, 0x3B, 0x82, 0x03, 0x5C, 0xD3, 0xE8, 
+0xBA, 0x81, 0x25, 0x08, 0xB9, 0x40, 0xB7, 0xC1, 0xBB, 0xC1, 0x3B, 0x88, 0x25, 0x3E, 0x84, 0x80, 
+0x39, 0x48, 0x00, 0x42, 0x03, 0x18, 0x1B, 0xE9, 0x3B, 0x88, 0x25, 0x3E, 0x84, 0x80, 0x00, 0x48, 
+0xB9, 0x40, 0x3B, 0x88, 0xB7, 0x80, 0x0F, 0xB0, 0xBB, 0x0A, 0x3B, 0x82, 0x03, 0x5C, 0x0D, 0xA9, 
+0x37, 0x88, 0x25, 0x3E, 0x84, 0x80, 0xFF, 0xB0, 0x80, 0x40, 0x08, 0xF0, 0xBA, 0xCA, 0x3A, 0x42, 
+0x03, 0x5C, 0x09, 0x69, 0x39, 0x48, 0x08, 0x40, 0xB2, 0x00, 0xC9, 0x41, 0xCA, 0x41, 0xA1, 0xC0, 
+0x02, 0xF0, 0xA2, 0xC0, 0x53, 0xB0, 0x61, 0xA3, 0xC7, 0x81, 0x49, 0x08, 0xB3, 0x40, 0x4A, 0x08, 
+0xBC, 0x40, 0x47, 0x48, 0x4A, 0x3E, 0x84, 0x80, 0x8A, 0x95, 0x00, 0x60, 0x8A, 0x51, 0x49, 0x87, 
+0xB4, 0x00, 0x47, 0x48, 0x4A, 0x3E, 0x84, 0x80, 0x8A, 0x95, 0x00, 0x60, 0x8A, 0x51, 0x4A, 0x87, 
+0xBD, 0x80, 0x47, 0x48, 0x4A, 0x3E, 0x84, 0x80, 0x8A, 0x95, 0x00, 0x60, 0x8A, 0x51, 0x49, 0x87, 
+0xB5, 0x40, 0x47, 0x48, 0x4A, 0x3E, 0x84, 0x80, 0x8A, 0x95, 0x00, 0x60, 0x8A, 0x51, 0x4A, 0x02, 
+0xBE, 0x80, 0x47, 0x48, 0x4A, 0x3E, 0x84, 0x80, 0x8A, 0x95, 0x00, 0x60, 0x8A, 0x51, 0x49, 0x02, 
+0xB6, 0x40, 0x47, 0x48, 0x4A, 0x3E, 0x84, 0x80, 0x8A, 0x95, 0x00, 0x60, 0x8A, 0x51, 0x4A, 0x87, 
+0xBF, 0xC0, 0x47, 0x48, 0x4A, 0x3E, 0x84, 0x80, 0x8A, 0x95, 0x00, 0x60, 0x8A, 0x51, 0x49, 0x02, 
+0xB7, 0x80, 0x47, 0x48, 0x4A, 0x3E, 0x84, 0x80, 0x8A, 0x95, 0x00, 0x60, 0x8A, 0x51, 0x4A, 0x02, 
+0xC0, 0x80, 0xC8, 0x01, 0x48, 0xC8, 0x33, 0x7E, 0x84, 0x80, 0x83, 0x93, 0x00, 0x48, 0xA1, 0xC0, 
+0x27, 0xB0, 0xA2, 0x01, 0xA2, 0x4A, 0x61, 0xA3, 0x8A, 0x51, 0x48, 0xC8, 0x3C, 0x7E, 0x84, 0x80, 
+0x83, 0x93, 0x00, 0x48, 0xA1, 0xC0, 0x28, 0x30, 0xA2, 0x01, 0xA2, 0x4A, 0x61, 0xA3, 0x47, 0x48, 
+0x43, 0x3E, 0x84, 0x80, 0x8A, 0x95, 0x00, 0x60, 0x8A, 0x51, 0x8C, 0xA3, 0x8A, 0x51, 0xC6, 0x00, 
+0x48, 0xC8, 0x03, 0x59, 0x9F, 0x69, 0x45, 0x08, 0x46, 0x02, 0x03, 0x18, 0xAB, 0x29, 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, 0x7A, 0x29, 
+0x07, 0x70, 0xC7, 0xCA, 0x47, 0x42, 0x49, 0x08, 0xB3, 0x40, 0x4A, 0x08, 0xBC, 0x40, 0x03, 0x5C, 
+0x39, 0xE9, 0x49, 0x08, 0x01, 0xBE, 0xB4, 0x00, 0x4A, 0x08, 0x01, 0xBE, 0xBD, 0x80, 0x49, 0x08, 
+0x01, 0xBE, 0xB5, 0x40, 0x4A, 0x08, 0xFF, 0x7E, 0xBE, 0x80, 0x49, 0x08, 0xFF, 0x7E, 0xB6, 0x40, 
+0x4A, 0x08, 0x01, 0xBE, 0xBF, 0xC0, 0x49, 0x08, 0xFF, 0x7E, 0xB7, 0x80, 0x4A, 0x08, 0xFF, 0x7E, 
+0xC0, 0x80, 0x49, 0x08, 0xB8, 0x00, 0x4A, 0x08, 0x01, 0xBE, 0xC1, 0xC0, 0x49, 0x08, 0xB9, 0x40, 
+0x4A, 0x08, 0xFF, 0x7E, 0xC2, 0xC0, 0x49, 0x08, 0x01, 0xBE, 0xBA, 0x40, 0x4A, 0x08, 0xC3, 0x00, 
+0x49, 0x08, 0xFF, 0x7E, 0xBB, 0x80, 0x4A, 0x08, 0xC4, 0xC0, 0xC8, 0x01, 0x48, 0xC8, 0x33, 0x7E, 
+0x84, 0x80, 0x00, 0x48, 0xA1, 0xC0, 0x27, 0xB0, 0xA2, 0x01, 0xA2, 0x4A, 0x61, 0xA3, 0x8A, 0x51, 
+0x48, 0xC8, 0x3C, 0x7E, 0x84, 0x80, 0x83, 0x93, 0x00, 0x48, 0xA1, 0xC0, 0x28, 0x30, 0xA2, 0x01, 
+0xA2, 0x4A, 0x61, 0xA3, 0x8A, 0x51, 0x07, 0x70, 0x8C, 0xA3, 0x8A, 0x51, 0xC6, 0x00, 0x48, 0xC8, 
+0x03, 0x59, 0x06, 0x6A, 0x45, 0x08, 0x46, 0x02, 0x03, 0x18, 0x12, 0x6A, 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, 0xE6, 0x29, 0x49, 0x08, 
+0xA1, 0xC0, 0x27, 0xB0, 0xA2, 0x01, 0xA2, 0x4A, 0x61, 0xA3, 0x8A, 0x51, 0x4A, 0x08, 0xA1, 0xC0, 
+0x28, 0x30, 0xA2, 0x01, 0xA2, 0x4A, 0x61, 0xEB, 0xB3, 0x40, 0xCB, 0x81, 0xCC, 0x41, 0x33, 0xCB, 
+0x2D, 0xEA, 0x74, 0xB0, 0xC7, 0x40, 0x75, 0xF0, 0x30, 0x6A, 0x72, 0xB0, 0xC7, 0x40, 0x73, 0xF0, 
+0xC8, 0xC0, 0x33, 0x48, 0xA1, 0xC0, 0x02, 0xF0, 0xA2, 0xC0, 0x53, 0xB0, 0x61, 0xA3, 0xCA, 0x41, 
+0x4B, 0x48, 0xB5, 0x40, 0x4C, 0x08, 0xBE, 0x80, 0x4A, 0x08, 0x56, 0x7E, 0x84, 0x80, 0x8A, 0x95, 
+0x00, 0x60, 0x8A, 0x51, 0x4B, 0xC7, 0xB6, 0x40, 0x4A, 0x08, 0x56, 0x7E, 0x84, 0x80, 0x8A, 0x95, 
+0x00, 0x60, 0x8A, 0x51, 0x4C, 0x87, 0xBF, 0xC0, 0x4A, 0x08, 0x56, 0x7E, 0x84, 0x80, 0x8A, 0x95, 
+0x00, 0x60, 0x8A, 0x51, 0x4B, 0xC7, 0xB7, 0x80, 0x4A, 0x08, 0x56, 0x7E, 0x84, 0x80, 0x8A, 0x95, 
+0x00, 0x60, 0x8A, 0x51, 0x4C, 0x02, 0xC0, 0x80, 0x4A, 0x08, 0x56, 0x7E, 0x84, 0x80, 0x8A, 0x95, 
+0x00, 0x60, 0x8A, 0x51, 0x4B, 0x42, 0xB8, 0x00, 0x4A, 0x08, 0x56, 0x7E, 0x84, 0x80, 0x8A, 0x95, 
+0x00, 0x60, 0x8A, 0x51, 0x4C, 0x87, 0xC1, 0xC0, 0x4A, 0x08, 0x56, 0x7E, 0x84, 0x80, 0x8A, 0x95, 
+0x00, 0x60, 0x8A, 0x51, 0x4B, 0x42, 0xB9, 0x40, 0x4A, 0x08, 0x56, 0x7E, 0x84, 0x80, 0x8A, 0x95, 
+0x00, 0x60, 0x8A, 0x51, 0x4C, 0x02, 0xC2, 0xC0, 0xCD, 0x81, 0x1F, 0xF0, 0xA1, 0xC0, 0xE0, 0x70, 
+0xA2, 0xC0, 0x4D, 0x48, 0x35, 0x7E, 0x84, 0x80, 0x83, 0x93, 0x00, 0x48, 0x75, 0x23, 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, 0x75, 0x23, 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, 0x61, 0xA3, 0x8A, 0x51, 0x4D, 0x48, 
+0x3E, 0xBE, 0x84, 0x80, 0x83, 0x93, 0x00, 0x48, 0xA1, 0xC0, 0xA2, 0x01, 0x48, 0xC8, 0x61, 0xA3, 
+0x4A, 0x08, 0x51, 0x3E, 0x84, 0x80, 0x8A, 0x95, 0x00, 0x60, 0x8A, 0x51, 0x8C, 0xA3, 0x8A, 0x51, 
+0xC9, 0x00, 0x4D, 0x48, 0x03, 0x59, 0xC0, 0x6A, 0x34, 0x08, 0x49, 0x02, 0x03, 0x18, 0xCC, 0xEA, 
+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, 
+0x7D, 0x6A, 0x05, 0x30, 0xCA, 0x8A, 0x4A, 0x02, 0x4B, 0x48, 0xB5, 0x40, 0x4C, 0x08, 0xBE, 0x80, 
+0x03, 0x5C, 0x3C, 0xEA, 0x4B, 0x48, 0x01, 0xBE, 0xB6, 0x40, 0x4C, 0x08, 0x01, 0xBE, 0xBF, 0xC0, 
+0x4B, 0x48, 0x01, 0xBE, 0xB7, 0x80, 0x4C, 0x08, 0xFF, 0x7E, 0xC0, 0x80, 0x4B, 0x48, 0xFF, 0x7E, 
+0xB8, 0x00, 0x4C, 0x08, 0x01, 0xBE, 0xC1, 0xC0, 0x4B, 0x48, 0xFF, 0x7E, 0xB9, 0x40, 0x4C, 0x08, 
+0xFF, 0x7E, 0xC2, 0xC0, 0x4B, 0x48, 0xBA, 0x40, 0x4C, 0x08, 0x01, 0xBE, 0xC3, 0x00, 0x4B, 0x48, 
+0xBB, 0x80, 0x4C, 0x08, 0xFF, 0x7E, 0xC4, 0xC0, 0x4B, 0x48, 0x01, 0xBE, 0xBC, 0x40, 0x4C, 0x08, 
+0xC5, 0x00, 0x4B, 0x48, 0xFF, 0x7E, 0xBD, 0x80, 0x4C, 0x08, 0xC6, 0x00, 0xCD, 0x81, 0x1F, 0xF0, 
+0xA1, 0xC0, 0xE0, 0x70, 0xA2, 0xC0, 0x4D, 0x48, 0x35, 0x7E, 0x84, 0x80, 0x00, 0x48, 0x75, 0x23, 
+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, 0x75, 0x23, 
+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, 0x61, 0xA3, 0x8A, 0x51, 
+0x4D, 0x48, 0x3E, 0xBE, 0x84, 0x80, 0x83, 0x93, 0x00, 0x48, 0xA1, 0xC0, 0xA2, 0x01, 0x48, 0xC8, 
+0x61, 0xA3, 0x8A, 0x51, 0x07, 0x70, 0x8C, 0xA3, 0x8A, 0x51, 0xC9, 0x00, 0x4D, 0x48, 0x03, 0x59, 
+0x45, 0xEB, 0x34, 0x08, 0x49, 0x02, 0x03, 0x18, 0x51, 0xEB, 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, 0x07, 0xEB, 0x4B, 0x48, 0xA1, 0xC0, 
+0xA2, 0x01, 0x47, 0x48, 0x61, 0xA3, 0x8A, 0x51, 0x4C, 0x08, 0xA1, 0xC0, 0xA2, 0x01, 0x48, 0xC8, 
+0x61, 0xEB, 0xA3, 0x00, 0x22, 0x0A, 0x03, 0x59, 0x6F, 0xAB, 0x22, 0xC8, 0x65, 0x86, 0x03, 0x59, 
+0x6F, 0xAB, 0x22, 0xC8, 0x88, 0x80, 0x80, 0xF0, 0x8C, 0xC0, 0x22, 0xC8, 0xE5, 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, 0x80, 0x6B, 0x21, 0xC8, 0x08, 0x40, 
+0x24, 0xC8, 0x80, 0x7A, 0xA3, 0x00, 0x22, 0xC8, 0x80, 0x7A, 0xA3, 0x42, 0x03, 0x18, 0x8A, 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, 0x61, 0xA3, 
+0x8A, 0x51, 0x2E, 0x48, 0x02, 0xBE, 0xA1, 0xC0, 0x02, 0xF0, 0xA2, 0xC0, 0x54, 0x70, 0x61, 0xA3, 
+0x8A, 0x51, 0x02, 0xF0, 0xA1, 0xC0, 0x54, 0x70, 0xEB, 0x63, 0x8A, 0x51, 0xDD, 0x80, 0xDD, 0xDF, 
+0xA1, 0xEB, 0x02, 0xF0, 0xA1, 0xC0, 0x57, 0xF0, 0xEB, 0x63, 0x8A, 0x51, 0xAB, 0x40, 0x02, 0xF0, 
+0xA1, 0xC0, 0x58, 0x70, 0xEB, 0x63, 0x8A, 0x51, 0xAC, 0x00, 0x31, 0x08, 0x25, 0x3E, 0x84, 0x80, 
+0x2C, 0x08, 0xFF, 0xE3, 0x8A, 0x51, 0xA4, 0xC0, 0x2B, 0x48, 0xFF, 0xE3, 0x8A, 0x51, 0x24, 0x47, 
+0x83, 0x93, 0x80, 0x40, 0x05, 0x30, 0xB1, 0x8A, 0x31, 0x02, 0x03, 0x5C, 0x92, 0xEB, 0xB0, 0x01, 
+0x25, 0x08, 0xAF, 0x80, 0xAD, 0x81, 0xB1, 0x41, 0x31, 0x08, 0x25, 0x3E, 0x84, 0x80, 0x2F, 0x88, 
+0x00, 0x42, 0x03, 0x18, 0xDA, 0x6B, 0x31, 0x08, 0x25, 0x3E, 0x84, 0x80, 0x00, 0x48, 0xAF, 0x80, 
+0x31, 0x08, 0xAD, 0x40, 0x05, 0x30, 0xB1, 0x8A, 0x31, 0x02, 0x03, 0x5C, 0xCC, 0x2B, 0x2D, 0x48, 
+0x25, 0x3E, 0x84, 0x80, 0xFF, 0xB0, 0x80, 0x40, 0x03, 0x30, 0xB0, 0x4A, 0x30, 0xC2, 0x03, 0x5C, 
+0xC8, 0xEB, 0x2F, 0x88, 0x08, 0x40, 0xA2, 0xC0, 0x21, 0x0A, 0x03, 0x59, 0xF9, 0xAB, 0x21, 0xC8, 
+0x65, 0x86, 0x03, 0x59, 0xF9, 0xAB, 0x21, 0xC8, 0x88, 0x80, 0x80, 0xF0, 0x8C, 0xC0, 0x21, 0xC8, 
+0xE5, 0x40, 0x22, 0xC8, 0x8C, 0xC0, 0x22, 0xC8, 0x8C, 0xC0, 0x08, 0x88, 0x08, 0x40, 0xA1, 0xC0, 
+0xA1, 0x1F, 0x05, 0x6C, 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, 0x19, 0xAC, 0x00, 0xB0, 0xA1, 0x01, 0xA1, 0x43, 0x8A, 0x51, 0xEB, 0x63, 0x8A, 0x51, 
+0x03, 0xBA, 0x03, 0x9D, 0x3A, 0xEC, 0x03, 0x30, 0xE5, 0x40, 0xC8, 0x70, 0xA1, 0xC0, 0x02, 0xF0, 
+0xA2, 0xC0, 0x56, 0xB0, 0x8A, 0x51, 0x61, 0xA3, 0x8A, 0x51, 0x02, 0xF0, 0xA1, 0xC0, 0x56, 0xB0, 
+0x8A, 0x51, 0xEB, 0x63, 0x8A, 0x51, 0xDD, 0x80, 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, 0xBE, 0xE0, 0x8A, 0x51, 0xDD, 0x80, 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, 0xBE, 0xE0, 0x8A, 0x51, 0xDD, 0x80, 0xCA, 0x3A, 0x03, 0x59, 
+0x1B, 0xD5, 0x14, 0xC8, 0xCE, 0x40, 0x06, 0x30, 0x03, 0xD0, 0xCE, 0xCC, 0xFF, 0x7E, 0x03, 0x9D, 
+0x7C, 0x2C, 0x4E, 0x48, 0xD1, 0x00, 0x14, 0x5C, 0x89, 0xAC, 0x83, 0x52, 0x03, 0x53, 0x67, 0xD4, 
+0x8C, 0xAC, 0x83, 0x52, 0x03, 0x53, 0x67, 0x90, 0x94, 0x9C, 0x92, 0xAC, 0x83, 0x52, 0x03, 0x53, 
+0xE6, 0x57, 0x95, 0xEC, 0x83, 0x52, 0x03, 0x53, 0xE6, 0x13, 0x14, 0x9D, 0x9B, 0x2C, 0x83, 0x52, 
+0x03, 0x53, 0x66, 0x17, 0x9E, 0x2C, 0x83, 0x52, 0x03, 0x53, 0x66, 0xD3, 0x94, 0xDD, 0xA4, 0xAC, 
+0x83, 0x52, 0x03, 0x53, 0xE6, 0x16, 0xA7, 0x2C, 0x83, 0x52, 0x03, 0x53, 0xE6, 0xD2, 0x14, 0x9E, 
+0xAD, 0x2C, 0x83, 0x52, 0x03, 0x53, 0x66, 0xD6, 0xB0, 0xAC, 0x83, 0x52, 0x03, 0x53, 0x66, 0x92, 
+0x94, 0xDE, 0xB6, 0x2C, 0x83, 0x52, 0x03, 0x53, 0xE6, 0x15, 0xB9, 0x2C, 0x83, 0x52, 0x03, 0x53, 
+0xE6, 0xD1, 0x51, 0x08, 0x03, 0x9D, 0xC0, 0x6C, 0x83, 0x52, 0x03, 0x53, 0x66, 0xD5, 0xC3, 0xEC, 
+0x83, 0x52, 0x03, 0x53, 0x66, 0x91, 0x51, 0x8B, 0xC9, 0xEC, 0x83, 0x52, 0x03, 0x53, 0xE6, 0xD4, 
+0xCC, 0xEC, 0x83, 0x52, 0x03, 0x53, 0xE6, 0x90, 0x02, 0xF0, 0x51, 0x46, 0x03, 0x9D, 0xD4, 0xEC, 
+0x83, 0x52, 0x03, 0x53, 0x66, 0x94, 0xD7, 0x6C, 0x83, 0x52, 0x03, 0x53, 0x66, 0x50, 0x8A, 0x51, 
+0x2B, 0x60, 0x8A, 0x51, 0xD4, 0x41, 0x54, 0x08, 0xE8, 0x7E, 0x84, 0x80, 0x83, 0x93, 0x00, 0x48, 
+0xCE, 0x40, 0x54, 0x08, 0xDC, 0xBE, 0x84, 0x80, 0x4E, 0x48, 0x80, 0x40, 0x54, 0x08, 0xE6, 0xBE, 
+0x84, 0x80, 0x00, 0x48, 0xCE, 0x40, 0x54, 0x08, 0x5B, 0xBE, 0x84, 0x80, 0x4E, 0x48, 0x80, 0x40, 
+0x54, 0x08, 0xE4, 0x7E, 0x84, 0x80, 0x00, 0x48, 0xCE, 0x40, 0x54, 0x08, 0xDA, 0xBE, 0x84, 0x80, 
+0x4E, 0x48, 0x80, 0x40, 0x54, 0x08, 0xE2, 0x7E, 0x84, 0x80, 0x00, 0x48, 0xCE, 0x40, 0x54, 0x08, 
+0x59, 0x7E, 0x84, 0x80, 0x4E, 0x48, 0x80, 0x40, 0x54, 0x08, 0xE0, 0x3E, 0x84, 0x80, 0x00, 0x48, 
+0xCE, 0x40, 0x54, 0x08, 0x57, 0xBE, 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, 
+0x02, 0xF0, 0xD4, 0x8A, 0x54, 0x02, 0x03, 0x5C, 0xDB, 0x6C, 0x69, 0xB0, 0xA1, 0x01, 0xA2, 0x01, 
+0x8A, 0x51, 0x61, 0xA3, 0x8A, 0x51, 0x19, 0x10, 0x19, 0x51, 0x99, 0x50, 0x99, 0x91, 0x21, 0x30, 
+0xA1, 0x01, 0xA1, 0x4A, 0xA2, 0x01, 0xA2, 0x4A, 0x8A, 0x51, 0x61, 0xA3, 0x8A, 0x51, 0x21, 0x30, 
+0xA1, 0x01, 0xA2, 0x01, 0xA2, 0x4A, 0x8A, 0x51, 0x61, 0xA3, 0x8A, 0x51, 0x07, 0x70, 0xA1, 0xC0, 
+0x02, 0xF0, 0xA2, 0xC0, 0x30, 0x30, 0x8A, 0x51, 0x61, 0xA3, 0x8A, 0x51, 0xE6, 0xD8, 0xEA, 0x81, 
+0x27, 0xB0, 0xA1, 0x01, 0xA2, 0x01, 0xA2, 0x4A, 0x8A, 0x51, 0x61, 0xA3, 0x8A, 0x51, 0x28, 0x30, 
+0xA1, 0x01, 0xA2, 0x01, 0xA2, 0x4A, 0x8A, 0x51, 0x61, 0xA3, 0x8A, 0x51, 0x67, 0x1C, 0xFF, 0x2D, 
+0x66, 0x1D, 0x66, 0x98, 0x55, 0x2D, 0xE6, 0x1C, 0x7B, 0xAD, 0x18, 0x14, 0xE6, 0x1C, 0x70, 0xED, 
+0x03, 0x30, 0xA1, 0xC0, 0x02, 0xF0, 0xA2, 0xC0, 0x2C, 0x70, 0x8A, 0x51, 0x61, 0xA3, 0x8A, 0x51, 
+0x99, 0xD5, 0x29, 0x70, 0x83, 0x52, 0x03, 0x53, 0xD0, 0xC0, 0x96, 0xB0, 0xCF, 0x80, 0x7E, 0x30, 
+0xCE, 0x40, 0xCE, 0x0B, 0x69, 0x2D, 0xCF, 0x4B, 0x69, 0x2D, 0xD0, 0x8B, 0x69, 0x2D, 0x00, 0x00, 
+0x03, 0x30, 0x83, 0x52, 0x03, 0x53, 0xEE, 0x80, 0x0F, 0xB0, 0xEF, 0xC0, 0x00, 0xB0, 0x8A, 0x95, 
+0xEB, 0x65, 0x8A, 0x51, 0x85, 0xED, 0x18, 0xD0, 0x02, 0xF0, 0xEE, 0x80, 0x0E, 0x70, 0xEF, 0xC0, 
+0x01, 0xF0, 0xAA, 0x41, 0x8A, 0x95, 0x58, 0xA5, 0x8A, 0x51, 0x6C, 0x48, 0x83, 0x96, 0xD2, 0x00, 
+0x83, 0x52, 0x6B, 0x88, 0x83, 0x96, 0xD3, 0x40, 0x83, 0x52, 0x5E, 0x88, 0x83, 0x96, 0xD4, 0x00, 
+0x83, 0x52, 0x02, 0xF0, 0xA1, 0x01, 0xA2, 0xC0, 0x53, 0xB0, 0x8A, 0x51, 0x61, 0xA3, 0x8A, 0x51, 
+0x14, 0x30, 0xA1, 0xC0, 0x02, 0xF0, 0xA2, 0xC0, 0x56, 0xB0, 0x8A, 0x51, 0x61, 0xA3, 0x8A, 0x51, 
+0x02, 0xF0, 0x8A, 0x51, 0xCD, 0xA0, 0x8A, 0x51, 0xD2, 0x00, 0xEC, 0xF0, 0xA1, 0xC0, 0x02, 0xF0, 
+0xA2, 0xC0, 0x56, 0xB0, 0x8A, 0x51, 0x61, 0xA3, 0x8A, 0x51, 0x00, 0xB0, 0x8A, 0x51, 0x24, 0x22, 
+0x8A, 0x51, 0x07, 0x70, 0x8A, 0x51, 0xCD, 0xA0, 0x8A, 0x51, 0xD3, 0x40, 0x02, 0xF0, 0xA1, 0x01, 
+0xA2, 0xC0, 0x2F, 0xF0, 0x8A, 0x51, 0x61, 0xA3, 0x8A, 0x51, 0x24, 0x30, 0xA1, 0xC0, 0x02, 0xF0, 
+0xA2, 0xC0, 0x2F, 0xF0, 0x8A, 0x51, 0x61, 0xA3, 0x8A, 0x51, 0x2A, 0x70, 0x83, 0x52, 0x03, 0x53, 
+0xCF, 0x80, 0x8D, 0xB0, 0xCE, 0x40, 0xCE, 0x0B, 0xCB, 0x6D, 0xCF, 0x4B, 0xCB, 0x6D, 0x83, 0x52, 
+0x02, 0xF0, 0x03, 0x53, 0xA1, 0x01, 0xA2, 0xC0, 0x2F, 0xF0, 0x8A, 0x51, 0x61, 0xA3, 0x8A, 0x51, 
+0x66, 0x1D, 0x66, 0x98, 0xDD, 0xAD, 0xE6, 0x1C, 0xE4, 0x2D, 0x99, 0x91, 0x03, 0x30, 0xA1, 0xC0, 
+0x00, 0xB0, 0xA2, 0x01, 0xA2, 0x4A, 0xE8, 0x2D, 0x03, 0x30, 0xA1, 0xC0, 0x00, 0xB0, 0xA2, 0x01, 
+0x8A, 0x95, 0xF0, 0x27, 0x8A, 0x51, 0x53, 0x48, 0x8A, 0x51, 0x13, 0x20, 0x8A, 0x51, 0xCE, 0x40, 
+0x52, 0x08, 0x8A, 0x51, 0x13, 0x20, 0x8A, 0x51, 0xCF, 0x80, 0x4E, 0x48, 0x4F, 0x82, 0x1E, 0x7E, 
+0x83, 0x96, 0xD0, 0xC0, 0x32, 0x70, 0x50, 0xC2, 0x83, 0x52, 0x03, 0x18, 0x9B, 0x15, 0x83, 0x52, 
+0xE6, 0x9F, 0xB5, 0x6E, 0x66, 0x1D, 0x66, 0x98, 0x07, 0xEE, 0xE6, 0x1C, 0x2D, 0x2E, 0x18, 0xD0, 
+0xE6, 0x1C, 0x22, 0xAE, 0x03, 0x30, 0xA1, 0xC0, 0x02, 0xF0, 0xA2, 0xC0, 0x2C, 0x70, 0x8A, 0x51, 
+0x61, 0xA3, 0x8A, 0x51, 0x99, 0x94, 0x29, 0x70, 0x83, 0x52, 0x03, 0x53, 0xD0, 0xC0, 0x96, 0xB0, 
+0xCF, 0x80, 0x7E, 0x30, 0xCE, 0x40, 0xCE, 0x0B, 0x1B, 0x2E, 0xCF, 0x4B, 0x1B, 0x2E, 0xD0, 0x8B, 
+0x1B, 0x2E, 0x00, 0x00, 0x03, 0x30, 0x83, 0x52, 0x03, 0x53, 0xEE, 0x80, 0x0F, 0xB0, 0xEF, 0xC0, 
+0x01, 0xF0, 0x8A, 0x95, 0xEB, 0x65, 0x8A, 0x51, 0x38, 0xEE, 0x18, 0x14, 0x02, 0xF0, 0xEE, 0x80, 
+0x0E, 0x70, 0xEF, 0xC0, 0x01, 0xF0, 0xAA, 0x41, 0xAA, 0x8A, 0x8A, 0x95, 0x58, 0xA5, 0x8A, 0x51, 
+0x6C, 0x48, 0x83, 0x96, 0xD2, 0x00, 0x83, 0x52, 0x6B, 0x88, 0x83, 0x96, 0xD3, 0x40, 0x83, 0x52, 
+0x5E, 0x88, 0x83, 0x96, 0xD4, 0x00, 0x83, 0x52, 0x02, 0xF0, 0xA1, 0x01, 0xA1, 0x4A, 0xA2, 0xC0, 
+0x53, 0xB0, 0x8A, 0x51, 0x61, 0xA3, 0x8A, 0x51, 0x14, 0x30, 0xA1, 0xC0, 0x02, 0xF0, 0xA2, 0xC0, 
+0x56, 0xB0, 0x8A, 0x51, 0x61, 0xA3, 0x8A, 0x51, 0x02, 0xF0, 0x8A, 0x51, 0xCD, 0xA0, 0x8A, 0x51, 
+0xD2, 0x00, 0xEC, 0xF0, 0xA1, 0xC0, 0x02, 0xF0, 0xA2, 0xC0, 0x56, 0xB0, 0x8A, 0x51, 0x61, 0xA3, 
+0x8A, 0x51, 0x01, 0xF0, 0x8A, 0x51, 0x24, 0x22, 0x8A, 0x51, 0x07, 0x70, 0x8A, 0x51, 0xCD, 0xA0, 
+0x8A, 0x51, 0xD3, 0x40, 0x02, 0xF0, 0xA1, 0x01, 0xA2, 0xC0, 0x2F, 0xF0, 0x8A, 0x51, 0x61, 0xA3, 
+0x8A, 0x51, 0x25, 0x70, 0xA1, 0xC0, 0x02, 0xF0, 0xA2, 0xC0, 0x2F, 0xF0, 0x8A, 0x51, 0x61, 0xA3, 
+0x8A, 0x51, 0x2A, 0x70, 0x83, 0x52, 0x03, 0x53, 0xCF, 0x80, 0x8D, 0xB0, 0xCE, 0x40, 0xCE, 0x0B, 
+0x7F, 0xEE, 0xCF, 0x4B, 0x7F, 0xEE, 0x83, 0x52, 0x02, 0xF0, 0x03, 0x53, 0xA1, 0x01, 0xA2, 0xC0, 
+0x2F, 0xF0, 0x8A, 0x51, 0x61, 0xA3, 0x8A, 0x51, 0x66, 0x1D, 0x66, 0x98, 0x91, 0xEE, 0xE6, 0x1C, 
+0x99, 0x2E, 0xE6, 0x1C, 0x94, 0xEE, 0x99, 0x50, 0x03, 0x30, 0xA1, 0xC0, 0x00, 0xB0, 0xA2, 0x01, 
+0x9E, 0x6E, 0x03, 0x30, 0xA1, 0xC0, 0x00, 0xB0, 0xA2, 0x01, 0xA2, 0x4A, 0x8A, 0x95, 0xF0, 0x27, 
+0x8A, 0x51, 0x53, 0x48, 0x8A, 0x51, 0x13, 0x20, 0x8A, 0x51, 0xCE, 0x40, 0x52, 0x08, 0x8A, 0x51, 
+0x13, 0x20, 0x8A, 0x51, 0xCF, 0x80, 0x4E, 0x48, 0x4F, 0x82, 0x1E, 0x7E, 0x83, 0x96, 0xD1, 0x00, 
+0x32, 0x70, 0x51, 0x02, 0x83, 0x52, 0x03, 0x18, 0x1B, 0xD6, 0x83, 0x52, 0x66, 0x1E, 0xBA, 0x6E, 
+0x03, 0x30, 0xBB, 0xAE, 0x02, 0xF0, 0xEE, 0x80, 0x01, 0xF0, 0xDF, 0xC0, 0x14, 0x30, 0xA1, 0xC0, 
+0x02, 0xF0, 0xA2, 0xC0, 0x56, 0xB0, 0x8A, 0x51, 0x61, 0xA3, 0x8A, 0x51, 0x66, 0x5F, 0x3F, 0xEF, 
+0x18, 0xD0, 0x02, 0xF0, 0xA1, 0x01, 0xA2, 0xC0, 0x53, 0xB0, 0x8A, 0x51, 0x61, 0xA3, 0x8A, 0x51, 
+0x9B, 0x16, 0xD4, 0x41, 0x27, 0xB0, 0xA1, 0x01, 0xA2, 0x01, 0xA2, 0x4A, 0x8A, 0x51, 0x61, 0xA3, 
+0x8A, 0x51, 0x28, 0x30, 0xA1, 0x01, 0xA2, 0x01, 0xA2, 0x4A, 0x8A, 0x51, 0x61, 0xA3, 0x8A, 0x51, 
+0x54, 0x08, 0x05, 0xFE, 0xEF, 0xC0, 0xAA, 0x41, 0x54, 0x08, 0x03, 0x9D, 0xE9, 0x6E, 0x01, 0xF0, 
+0xEA, 0x6E, 0x00, 0xB0, 0x8A, 0x95, 0x58, 0xA5, 0x8A, 0x51, 0x54, 0x08, 0xD2, 0x7E, 0x84, 0x80, 
+0x6B, 0x0E, 0xF0, 0x39, 0x5E, 0x84, 0x83, 0x93, 0x80, 0x40, 0x03, 0x30, 0x8A, 0x51, 0xCD, 0xA0, 
+0x8A, 0x51, 0xD2, 0x00, 0x00, 0xB0, 0x8A, 0x51, 0x2C, 0x61, 0x8A, 0x51, 0x07, 0x70, 0x8A, 0x51, 
+0xCD, 0xA0, 0x8A, 0x51, 0xD3, 0x40, 0x8A, 0x51, 0x13, 0x20, 0x8A, 0x51, 0xCE, 0x40, 0x52, 0x08, 
+0x8A, 0x51, 0x13, 0x20, 0x8A, 0x51, 0xCF, 0x80, 0x4E, 0x48, 0x4F, 0x82, 0x18, 0xFE, 0xD0, 0xC0, 
+0x54, 0x08, 0xC0, 0xFE, 0x84, 0x80, 0x50, 0xC8, 0x83, 0x93, 0x80, 0x40, 0x54, 0x08, 0xA0, 0xFE, 
+0x84, 0x80, 0x27, 0xB0, 0xA1, 0x01, 0xA1, 0x4A, 0x8A, 0x51, 0xEB, 0x63, 0x8A, 0x51, 0x83, 0x93, 
+0x80, 0x40, 0x54, 0x08, 0xA8, 0x3E, 0x84, 0x80, 0x28, 0x30, 0xA1, 0x01, 0xA1, 0x4A, 0x8A, 0x51, 
+0xEB, 0x63, 0x8A, 0x51, 0x83, 0x93, 0x80, 0x40, 0x54, 0x08, 0xC0, 0xFE, 0x84, 0x80, 0x14, 0x30, 
+0x00, 0x42, 0x03, 0x5C, 0x9B, 0xD2, 0x08, 0xF0, 0xD4, 0x8A, 0x54, 0x02, 0x03, 0x5C, 0xD2, 0x2E, 
+0x03, 0x30, 0xA1, 0xC0, 0x00, 0xB0, 0xA2, 0x01, 0x8A, 0x95, 0xF0, 0x27, 0x8A, 0x51, 0xE6, 0x5E, 
+0xBB, 0xEF, 0x18, 0x14, 0x02, 0xF0, 0xA1, 0x01, 0xA1, 0x4A, 0xA2, 0xC0, 0x53, 0xB0, 0x8A, 0x51, 
+0x61, 0xA3, 0x8A, 0x51, 0x1B, 0x17, 0xD4, 0x41, 0x27, 0xB0, 0xA1, 0x01, 0xA2, 0x01, 0xA2, 0x4A, 
+0x8A, 0x51, 0x61, 0xA3, 0x8A, 0x51, 0x28, 0x30, 0xA1, 0x01, 0xA2, 0x01, 0xA2, 0x4A, 0x8A, 0x51, 
+0x61, 0xA3, 0x8A, 0x51, 0x54, 0x08, 0x05, 0xFE, 0xEF, 0xC0, 0xAA, 0x41, 0xAA, 0x8A, 0x54, 0x08, 
+0x03, 0x9D, 0x64, 0x2F, 0x01, 0xF0, 0x65, 0x6F, 0x00, 0xB0, 0x8A, 0x95, 0x58, 0xA5, 0x8A, 0x51, 
+0x54, 0x08, 0xD2, 0x7E, 0x84, 0x80, 0x6B, 0x0E, 0xF0, 0x39, 0x5E, 0x84, 0x83, 0x93, 0x80, 0x40, 
+0x03, 0x30, 0x8A, 0x51, 0xCD, 0xA0, 0x8A, 0x51, 0xD2, 0x00, 0x01, 0xF0, 0x8A, 0x51, 0x2C, 0x61, 
+0x8A, 0x51, 0x07, 0x70, 0x8A, 0x51, 0xCD, 0xA0, 0x8A, 0x51, 0xD3, 0x40, 0x8A, 0x51, 0x13, 0x20, 
+0x8A, 0x51, 0xCE, 0x40, 0x52, 0x08, 0x8A, 0x51, 0x13, 0x20, 0x8A, 0x51, 0xCF, 0x80, 0x4E, 0x48, 
+0x4F, 0x82, 0x18, 0xFE, 0xD0, 0xC0, 0x54, 0x08, 0xC8, 0x3E, 0x84, 0x80, 0x50, 0xC8, 0x83, 0x93, 
+0x80, 0x40, 0x54, 0x08, 0xB0, 0x3E, 0x84, 0x80, 0x27, 0xB0, 0xA1, 0x01, 0xA1, 0x4A, 0x8A, 0x51, 
+0xEB, 0x63, 0x8A, 0x51, 0x83, 0x93, 0x80, 0x40, 0x54, 0x08, 0xB8, 0x7E, 0x84, 0x80, 0x28, 0x30, 
+0xA1, 0x01, 0xA1, 0x4A, 0x8A, 0x51, 0xEB, 0x63, 0x8A, 0x51, 0x83, 0x93, 0x80, 0x40, 0x54, 0x08, 
+0xC8, 0x3E, 0x84, 0x80, 0x14, 0x30, 0x00, 0x42, 0x03, 0x5C, 0x1B, 0xD3, 0x08, 0xF0, 0xD4, 0x8A, 
+0x54, 0x02, 0x03, 0x5C, 0x4C, 0x2F, 0x03, 0x30, 0xA1, 0xC0, 0x00, 0xB0, 0xA2, 0x01, 0xA2, 0x4A, 
+0x8A, 0x95, 0xF0, 0x27, 0x8A, 0x51, 0x18, 0x56, 0x18, 0x12, 0x8A, 0x95, 0x4F, 0x67, 0x8A, 0x51, 
+0xE4, 0xB0, 0x83, 0x52, 0x03, 0x53, 0xCE, 0x40, 0xC5, 0x6F, 0xC6, 0x6F, 0xCE, 0x0B, 0xC4, 0x2F, 
+0x00, 0x00, 0x0E, 0x70, 0x83, 0x52, 0x03, 0x53, 0xA1, 0xC0, 0x69, 0xB0, 0xA2, 0x01, 0x8A, 0x51, 
+0x61, 0xA3, 0x8A, 0x51, 0x9B, 0x57, 0xD3, 0xAF, 0x83, 0x96, 0x01, 0xF0, 0xEE, 0x80, 0x83, 0x52, 
+0x06, 0x30, 0xE8, 0x00, 0x07, 0x70, 0xE9, 0x40, 0x01, 0xF0, 0xEA, 0x40, 0x0F, 0xB0, 0xEB, 0x80, 
+0x01, 0xF0, 0xEC, 0x40, 0x05, 0x30, 0xED, 0x80, 0x02, 0xF0, 0xEE, 0x80, 0x0E, 0x70, 0xEF, 0xC0, 
+0xA0, 0x30, 0x83, 0xD7, 0x84, 0x80, 0xAE, 0xF0, 0x8A, 0x51, 0x0B, 0x20, 0x8A, 0x51, 0xDA, 0xF0, 
+0x83, 0x93, 0x84, 0x80, 0xEE, 0x30, 0x8A, 0x51, 0x0B, 0x20, 0x8A, 0x51, 0x55, 0xB0, 0x84, 0x80, 
+0x66, 0xB0, 0x8A, 0x51, 0x0B, 0x20, 0xE6, 0x81, 0xE7, 0xC1, 0x83, 0x01, 0x8A, 0x51, 0x07, 0xAC, 
+0x08, 0xF0, 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, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xA8, 0xC0, 0x28, 0x5C, 0xEB, 0x6C, 0x83, 0x52, 
+0x03, 0x53, 0x18, 0x14, 0xEE, 0x6C, 0x83, 0x52, 0x03, 0x53, 0x18, 0xD0, 0x07, 0x70, 0xDE, 0x80, 
+0x5E, 0x0E, 0xF0, 0x39, 0x96, 0x00, 0x18, 0x55, 0x18, 0x11, 0xA9, 0x41, 0x28, 0xC8, 0xA4, 0xC0, 
+0x00, 0xB0, 0x39, 0xE5, 0x8A, 0x95, 0x98, 0x95, 0x98, 0x51, 0xA7, 0x81, 0x74, 0xB0, 0x0E, 0x02, 
+0x03, 0x5C, 0x09, 0xAD, 0x0B, 0x70, 0x5E, 0x82, 0x03, 0x18, 0x09, 0xAD, 0x5E, 0x88, 0x01, 0xBE, 
+0x13, 0xED, 0x2D, 0xB0, 0x0E, 0x02, 0x03, 0x18, 0x19, 0xED, 0x08, 0xF0, 0x5E, 0x82, 0x03, 0x5C, 
+0x19, 0xED, 0x5E, 0x88, 0xFF, 0x7E, 0xDE, 0x80, 0x5E, 0x0E, 0xF0, 0x39, 0x96, 0x00, 0x18, 0x55, 
+0x18, 0x11, 0x24, 0x30, 0x0F, 0x42, 0x03, 0x5C, 0x23, 0xED, 0x09, 0x30, 0x29, 0x02, 0x03, 0x18, 
+0x23, 0xED, 0xA9, 0x8A, 0x2C, 0xED, 0x10, 0xF0, 0x0F, 0x42, 0x03, 0x18, 0x33, 0x2D, 0x29, 0x08, 
+0x03, 0x59, 0x33, 0x2D, 0xFF, 0xB0, 0xA9, 0xC7, 0x28, 0xC8, 0xA4, 0xC0, 0x29, 0x08, 0x39, 0xE5, 
+0x8A, 0x95, 0x98, 0x95, 0x98, 0x51, 0x14, 0x30, 0xA7, 0xCA, 0x27, 0x42, 0x03, 0x18, 0x08, 0x40, 
+0xFE, 0xAC, 0xA6, 0x00, 0x39, 0x7E, 0x84, 0x80, 0x8A, 0x95, 0x00, 0x60, 0x8A, 0x95, 0xEC, 0x40, 
+0x26, 0x08, 0x2F, 0xBE, 0x84, 0x80, 0x8A, 0x95, 0x00, 0x60, 0x8A, 0x95, 0xEB, 0x80, 0x6C, 0x48, 
+0xA5, 0x00, 0x05, 0x30, 0x03, 0xD0, 0xA5, 0xCD, 0xFF, 0x7E, 0x03, 0xD0, 0x03, 0x9D, 0x4B, 0x2D, 
+0x6B, 0x0D, 0x25, 0x04, 0x6A, 0x44, 0xA1, 0xC0, 0x24, 0xC8, 0xA2, 0xC0, 0x0C, 0x30, 0xF0, 0x6F, 
+0xAD, 0x40, 0x01, 0xF0, 0x83, 0x96, 0xED, 0x80, 0x83, 0x52, 0x2A, 0x08, 0x99, 0xE6, 0x8A, 0x95, 
+0x2D, 0x48, 0x03, 0x59, 0xE7, 0xAD, 0x2A, 0x08, 0xDC, 0xBE, 0x84, 0x80, 0x83, 0x93, 0x00, 0x48, 
+0xAB, 0x40, 0x2A, 0x08, 0x59, 0x7E, 0x84, 0x80, 0x2B, 0x48, 0x80, 0x40, 0xE6, 0x5D, 0x76, 0x6D, 
+0x2A, 0x08, 0x5B, 0xBE, 0x84, 0x80, 0x00, 0x48, 0x28, 0xFE, 0x7B, 0xAD, 0x2A, 0x08, 0x5B, 0xBE, 
+0x84, 0x80, 0x00, 0x48, 0x14, 0xFE, 0xAB, 0x40, 0x2A, 0x08, 0x57, 0xBE, 0x84, 0x80, 0x2B, 0x48, 
+0x80, 0x40, 0x2A, 0x08, 0x5B, 0xBE, 0x84, 0x80, 0x00, 0x48, 0xAB, 0x40, 0x2A, 0x08, 0x57, 0xBE, 
+0x84, 0x80, 0x00, 0x48, 0xAC, 0x00, 0x2B, 0x48, 0x2C, 0x02, 0x2A, 0x08, 0x03, 0x18, 0x9B, 0x6D, 
+0x59, 0x7E, 0x84, 0x80, 0x00, 0x48, 0x01, 0xBE, 0xAB, 0x40, 0x2A, 0x08, 0x59, 0x7E, 0x84, 0x80, 
+0x2B, 0x48, 0x80, 0x40, 0x2A, 0x08, 0xDA, 0xBE, 0x84, 0x80, 0x00, 0x48, 0xAB, 0x40, 0x2A, 0x08, 
+0x55, 0x7E, 0x84, 0x80, 0x2B, 0x48, 0x80, 0x40, 0x2A, 0x08, 0x59, 0x7E, 0x84, 0x80, 0x00, 0x48, 
+0xA1, 0xC0, 0x2A, 0x08, 0xA2, 0xC0, 0x04, 0xF0, 0xF0, 0x27, 0x8A, 0x95, 0x2A, 0x08, 0x57, 0xBE, 
+0x84, 0x80, 0x83, 0x93, 0x00, 0x48, 0xA1, 0xC0, 0x2A, 0x08, 0xA2, 0xC0, 0x05, 0x30, 0xF0, 0x27, 
+0x8A, 0x95, 0x2A, 0x08, 0x55, 0x7E, 0x84, 0x80, 0x83, 0x93, 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, 0x83, 0x52, 0x03, 0x53, 0xAB, 0x40, 0xD0, 0xED, 
+0xD1, 0x2D, 0xAB, 0x0B, 0xCF, 0xAD, 0x00, 0x00, 0x0F, 0xB0, 0x83, 0x52, 0x03, 0x53, 0xA1, 0xC0, 
+0x2A, 0x08, 0xA2, 0xC0, 0x00, 0xB0, 0xF0, 0x27, 0x8A, 0x95, 0xD0, 0x70, 0x83, 0x52, 0x03, 0x53, 
+0xAC, 0x00, 0xC9, 0xB0, 0xAB, 0x40, 0xAB, 0x0B, 0xE3, 0x6D, 0xAC, 0xCB, 0xE3, 0x6D, 0x83, 0x52, 
+0x03, 0x53, 0x2A, 0x08, 0xE4, 0xEC, 0xAC, 0x00, 0x2C, 0x08, 0x03, 0x59, 0xF3, 0xAD, 0xAD, 0x81, 
+0xAD, 0xCA, 0xAE, 0x81, 0xF6, 0xAD, 0xAD, 0x81, 0xAE, 0x81, 0xAE, 0xCA, 0x83, 0x96, 0xED, 0xC1, 
+0x0E, 0x70, 0x83, 0x52, 0xEF, 0xC0, 0x02, 0xF0, 0xEE, 0x80, 0x2D, 0x48, 0x99, 0xE6, 0x8A, 0x95, 
+0x2E, 0x48, 0x99, 0xE6, 0x8A, 0x95, 0x2D, 0x48, 0xDC, 0xBE, 0x84, 0x80, 0x83, 0x93, 0x00, 0x48, 
+0xAA, 0x00, 0x2E, 0x48, 0x59, 0x7E, 0x84, 0x80, 0x2A, 0x08, 0x80, 0x40, 0xE6, 0x5D, 0x16, 0xEE, 
+0x2D, 0x48, 0x5B, 0xBE, 0x84, 0x80, 0x00, 0x48, 0x28, 0xFE, 0x1B, 0x2E, 0x2D, 0x48, 0x5B, 0xBE, 
+0x84, 0x80, 0x00, 0x48, 0x14, 0xFE, 0xAA, 0x00, 0x2E, 0x48, 0x57, 0xBE, 0x84, 0x80, 0x2A, 0x08, 
+0x80, 0x40, 0x2D, 0x48, 0x5B, 0xBE, 0x84, 0x80, 0x00, 0x48, 0xAA, 0x00, 0x2E, 0x48, 0x57, 0xBE, 
+0x84, 0x80, 0x00, 0x48, 0xAB, 0x40, 0x2A, 0x08, 0x2B, 0x42, 0x03, 0x18, 0x3A, 0x2E, 0x2E, 0x48, 
+0x59, 0x7E, 0x84, 0x80, 0x00, 0x48, 0x01, 0xBE, 0xAA, 0x00, 0x2E, 0x48, 0x59, 0x7E, 0x84, 0x80, 
+0x2A, 0x08, 0x80, 0x40, 0x2D, 0x48, 0xDA, 0xBE, 0x84, 0x80, 0x00, 0x48, 0xAA, 0x00, 0x2E, 0x48, 
+0x55, 0x7E, 0x84, 0x80, 0x2A, 0x08, 0x80, 0x40, 0x2E, 0x48, 0x59, 0x7E, 0x84, 0x80, 0x00, 0x48, 
+0xA1, 0xC0, 0x2E, 0x48, 0xA2, 0xC0, 0x04, 0xF0, 0xF0, 0x27, 0x8A, 0x95, 0x2E, 0x48, 0x57, 0xBE, 
+0x84, 0x80, 0x83, 0x93, 0x00, 0x48, 0xA1, 0xC0, 0x2E, 0x48, 0xA2, 0xC0, 0x05, 0x30, 0xF0, 0x27, 
+0x8A, 0x95, 0x2E, 0x48, 0x55, 0x7E, 0x84, 0x80, 0x83, 0x93, 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, 0x83, 0x52, 0x03, 0x53, 0xAA, 0x00, 0x77, 0xAE, 0x78, 0x2E, 
+0xAA, 0xCB, 0x76, 0x6E, 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, 0x83, 0x52, 0x03, 0x53, 0xAB, 0x40, 0xC9, 0xB0, 
+0xAA, 0x00, 0xAA, 0xCB, 0x91, 0xEE, 0xAB, 0x0B, 0x91, 0xEE, 0x83, 0x52, 0x03, 0x53, 0x2D, 0x48, 
+0xE4, 0xEC, 0xA6, 0x00, 0xDC, 0xBE, 0x84, 0x80, 0x83, 0x93, 0x00, 0x48, 0xA1, 0xC0, 0x26, 0x08, 
+0xA2, 0xC0, 0x01, 0xF0, 0xF0, 0x27, 0x8A, 0x95, 0x26, 0x08, 0x5B, 0xBE, 0x84, 0x80, 0x83, 0x93, 
+0x00, 0x48, 0xA1, 0xC0, 0x26, 0x08, 0xA2, 0xC0, 0x02, 0xF0, 0xF0, 0x27, 0x8A, 0x95, 0x26, 0x08, 
+0xDA, 0xBE, 0x84, 0x80, 0x83, 0x93, 0x00, 0x48, 0xA1, 0xC0, 0x26, 0x08, 0xA2, 0xC0, 0x03, 0x30, 
+0xF0, 0x27, 0x8A, 0x95, 0x26, 0x08, 0x59, 0x7E, 0x84, 0x80, 0x83, 0x93, 0x00, 0x48, 0xA1, 0xC0, 
+0x26, 0x08, 0xA2, 0xC0, 0x04, 0xF0, 0xF0, 0x27, 0x8A, 0x95, 0x26, 0x08, 0x57, 0xBE, 0x84, 0x80, 
+0x83, 0x93, 0x00, 0x48, 0xA1, 0xC0, 0x26, 0x08, 0xA2, 0xC0, 0x05, 0x30, 0xF0, 0x27, 0x8A, 0x95, 
+0x26, 0x08, 0x55, 0x7E, 0x84, 0x80, 0x83, 0x93, 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, 0x63, 0x48, 0xA4, 0xC0, 0x04, 0xF0, 0x03, 0xD0, 
+0xA4, 0x8D, 0xFF, 0x7E, 0x03, 0xD0, 0x03, 0x9D, 0xE8, 0x2E, 0x24, 0x4D, 0x64, 0x04, 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, 0x00, 0x6F, 0x6B, 0x0D, 0x24, 0xC4, 0x6A, 0x44, 
+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, 0x11, 0xEF, 0x68, 0x08, 0xA5, 0x00, 
+0x01, 0xF0, 0x03, 0xD0, 0xA5, 0xCD, 0xFF, 0x7E, 0x03, 0xD0, 0x03, 0x9D, 0x1A, 0x2F, 0x25, 0x8D, 
+0x24, 0xC4, 0x62, 0x04, 0xA1, 0xC0, 0x26, 0x08, 0xA2, 0xC0, 0x0D, 0x70, 0xF0, 0x27, 0x8A, 0x95, 
+0x03, 0xD0, 0x61, 0x8D, 0x60, 0xC4, 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, 0x5F, 0xC4, 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, 0xE8, 0x7E, 0x84, 0x80, 0x83, 0x93, 0x00, 0x48, 
+0xA1, 0xC0, 0x24, 0xC8, 0xA2, 0xC0, 0x01, 0xF0, 0xF0, 0x27, 0x8A, 0x95, 0x24, 0xC8, 0xE6, 0xBE, 
+0x84, 0x80, 0x83, 0x93, 0x00, 0x48, 0xA1, 0xC0, 0x24, 0xC8, 0xA2, 0xC0, 0x02, 0xF0, 0xF0, 0x27, 
+0x8A, 0x95, 0x24, 0xC8, 0xE4, 0x7E, 0x84, 0x80, 0x83, 0x93, 0x00, 0x48, 0xA1, 0xC0, 0x24, 0xC8, 
+0xA2, 0xC0, 0x03, 0x30, 0xF0, 0x27, 0x8A, 0x95, 0x24, 0xC8, 0xE2, 0x7E, 0x84, 0x80, 0x83, 0x93, 
+0x00, 0x48, 0xA1, 0xC0, 0x24, 0xC8, 0xA2, 0xC0, 0x04, 0xF0, 0xF0, 0x27, 0x8A, 0x95, 0x24, 0xC8, 
+0xE0, 0x3E, 0x84, 0x80, 0x83, 0x93, 0x00, 0x48, 0xA1, 0xC0, 0x24, 0xC8, 0xA2, 0xC0, 0x05, 0x30, 
+0xF0, 0x27, 0x8A, 0x95, 0x24, 0xC8, 0xDE, 0xFE, 0x84, 0x80, 0x83, 0x93, 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, 0xAA, 0x7E, 0x84, 0x80, 0x83, 0xD7, 0x00, 0x48, 0xA1, 0xC0, 0x24, 0xC8, 0xA2, 0xC0, 
+0x0A, 0x30, 0xF0, 0x27, 0x8A, 0x95, 0x24, 0xC8, 0xA8, 0x3E, 0x84, 0x80, 0x83, 0xD7, 0x00, 0x48, 
+0xA1, 0xC0, 0x24, 0xC8, 0xA2, 0xC0, 0x0B, 0x70, 0xF0, 0x27, 0x8A, 0x95, 0x24, 0xC8, 0xA6, 0x7E, 
+0x84, 0x80, 0x83, 0xD7, 0x00, 0x48, 0xA1, 0xC0, 0x24, 0xC8, 0xA2, 0xC0, 0x0C, 0x30, 0xF0, 0x27, 
+0x8A, 0x95, 0x24, 0xC8, 0xA4, 0x3E, 0x84, 0x80, 0x83, 0xD7, 0x00, 0x48, 0xA1, 0xC0, 0x24, 0xC8, 
+0xA2, 0xC0, 0x0D, 0x70, 0xF0, 0x27, 0x8A, 0x95, 0x24, 0xC8, 0xA2, 0x3E, 0x84, 0x80, 0x83, 0xD7, 
+0x00, 0x48, 0xA1, 0xC0, 0x24, 0xC8, 0xA2, 0xC0, 0x0E, 0x70, 0xF0, 0x27, 0x8A, 0x95, 0x24, 0xC8, 
+0xA0, 0xFE, 0x84, 0x80, 0x83, 0xD7, 0x00, 0x48, 0xA1, 0xC0, 0x24, 0xC8, 0xA2, 0xC0, 0x10, 0xF0, 
+0xF0, 0x27, 0x8A, 0x95, 0x02, 0xF0, 0xA4, 0x4A, 0x24, 0xC2, 0x03, 0x18, 0x08, 0x40, 0x50, 0xEF, 
+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 -r 000000000000 -r 102b50f941d0 libloragw/src/loragw_aux.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libloragw/src/loragw_aux.c	Wed Apr 11 14:38:42 2018 +0000
@@ -0,0 +1,110 @@
+/*
+ / _____)             _              | |
+( (____  _____ ____ _| |_ _____  ____| |__
+ \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+  (C)2017 Semtech-Cycleo
+
+Description:
+    LoRa concentrator HAL auxiliary functions
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+
+*/
+
+
+/* -------------------------------------------------------------------------- */
+/* --- 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_linux(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;
+}
+
+void wait_ns_linux(unsigned long a) {
+    struct timespec dly;
+    struct timespec rem;
+
+    dly.tv_sec = 0;
+    dly.tv_nsec = a;
+
+    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 > 1))) {
+        clock_nanosleep(CLOCK_MONOTONIC, 0, &dly, &rem);
+        DEBUG_PRINTF("NOTE remain: %ld sec %ld ns\n", rem.tv_sec, rem.tv_nsec);
+    }
+    return;
+}
+
+void wait_ms(unsigned long a) {
+#ifdef _WIN32
+    return wait_ms_win(a) ;
+#elif __linux__
+    return wait_ms_linux(a) ;
+#elif __APPLE__
+    DEBUG_PRINTF("System is not recognized.");
+#elif __unix__
+    DEBUG_PRINTF("System is not recognized.");
+#elif __posix__
+    DEBUG_PRINTF("System is not recognized.");
+#else
+    DEBUG_PRINTF("System is not recognized.");
+#endif
+}
+void wait_ns(unsigned long a) {
+#ifdef _WIN32
+    return wait_ns_win(a) ;
+#elif __linux__
+    return wait_ns_linux(a) ;
+#elif __APPLE__
+    DEBUG_PRINTF("System is not recognized.");
+#elif __unix__
+    DEBUG_PRINTF("System is not recognized.");
+#elif __posix__
+    DEBUG_PRINTF("System is not recognized.");
+#else
+    DEBUG_PRINTF("System is not recognized.");
+#endif
+}
+
+/* --- EOF ------------------------------------------------------------------ */
diff -r 000000000000 -r 102b50f941d0 libloragw/src/loragw_com.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libloragw/src/loragw_com.c	Wed Apr 11 14:38:42 2018 +0000
@@ -0,0 +1,233 @@
+/*
+ / _____)             _              | |
+( (____  _____ ____ _| |_ _____  ____| |__
+ \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+  (C)2017 Semtech-Cycleo
+
+Description:
+  A communication bridge layer to abstract linux/windows OS or others.
+  The current project support only linux os
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+*/
+
+
+/* -------------------------------------------------------------------------- */
+/* --- 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 <errno.h>              /* Error number definitions */
+#include <termios.h>            /* POSIX terminal control definitions */
+#include <sys/ioctl.h>
+#include <pthread.h>
+#include <time.h>
+#include <sys/select.h>
+
+#include "loragw_aux.h"
+#include "loragw_reg.h"
+#include "loragw_com.h"
+#include "loragw_com_linux.h"
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE MACROS ------------------------------------------------------- */
+
+#if DEBUG_COM == 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_COM_ERROR;}
+#else
+#define DEBUG_MSG(str)
+#define DEBUG_PRINTF(fmt, args...)
+#define CHECK_NULL(a)                if(a==NULL){return LGW_COM_ERROR;}
+#endif
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE SHARED VARIABLES (GLOBAL) ------------------------------------ */
+
+extern void *lgw_com_target; /*! generic pointer to the COM device */
+
+pthread_mutex_t mx_usbbridgesync = PTHREAD_MUTEX_INITIALIZER; /* control access to usbbridge sync offsets */
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE CONSTANTS ---------------------------------------------------- */
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE FUNCTIONS DEFINITION ----------------------------------------- */
+
+int lgw_com_send_cmd(lgw_com_cmd_t cmd, lgw_handle_t handle) {
+#ifdef _WIN32
+    return lgw_com_send_cmd_win(cmd, handle);
+#elif __linux__
+    return lgw_com_send_cmd_linux(cmd, handle);
+#elif __APPLE__
+    DEBUG_PRINTF("System is not recognized.");
+#elif __unix__
+    DEBUG_PRINTF("System is not recognized.");
+#elif __posix__
+    DEBUG_PRINTF("System is not recognized.");
+#else
+    DEBUG_PRINTF("System is not recognized.");
+#endif
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int lgw_com_receive_ans(lgw_com_ans_t *ans, lgw_handle_t handle) {
+#ifdef _WIN32
+    return lgw_com_receive_ans_win(ans, handle);
+#elif __linux__
+    return lgw_com_receive_ans_linux(ans, handle);
+#elif __APPLE__
+    DEBUG_PRINTF("System is not recognized.");
+#elif __unix__
+    DEBUG_PRINTF("System is not recognized.");
+#elif __posix__
+    DEBUG_PRINTF("System is not recognized.");
+#else
+    DEBUG_PRINTF("System is not recognized.");
+#endif
+}
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC FUNCTIONS DEFINITION ------------------------------------------ */
+
+int lgw_com_open(void **com_target_ptr, const char *com_path) {
+#ifdef _WIN32
+    return lgw_com_open_win(com_target_ptr);
+#elif __linux__
+    return lgw_com_open_linux(com_target_ptr, com_path);
+#elif __APPLE__
+    DEBUG_PRINTF("System is not recognized.");
+#elif __unix__
+    DEBUG_PRINTF("System is not recognized.");
+#elif __posix__
+    DEBUG_PRINTF("System is not recognized.");
+#else
+    DEBUG_PRINTF("System is not recognized.");
+#endif
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int lgw_com_close(void *com_target) {
+#ifdef _WIN32
+    return lgw_com_close_win(com_target);
+#elif __linux__
+    return lgw_com_close_linux(com_target);
+#elif __APPLE__
+    DEBUG_PRINTF("System is not recognized.");
+#elif __unix__
+    DEBUG_PRINTF("System is not recognized.");
+#elif __posix__
+    DEBUG_PRINTF("System is not recognized.");
+#else
+    DEBUG_PRINTF("System is not recognized.");
+#endif
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int lgw_com_w(void *com_target, uint8_t com_mux_mode, uint8_t com_mux_target, uint8_t address, uint8_t data) {
+#ifdef _WIN32
+    return lgw_com_w_win(com_target, com_mux_mode, com_mux_target, address, data);
+#elif __linux__
+    return lgw_com_w_linux(com_target, com_mux_mode, com_mux_target, address, data);
+#elif __APPLE__
+    DEBUG_PRINTF("System is not recognized.");
+#elif __unix__
+    DEBUG_PRINTF("System is not recognized.");
+#elif __posix__
+    DEBUG_PRINTF("System is not recognized.");
+#else
+    DEBUG_PRINTF("System is not recognized.");
+#endif
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int lgw_com_r(void *com_target, uint8_t com_mux_mode, uint8_t com_mux_target, uint8_t address, uint8_t *data) {
+#ifdef _WIN32
+    return lgw_com_r_win(com_target, com_mux_mode, com_mux_target, address, data);
+#elif __linux__
+    return lgw_com_r_linux(com_target, com_mux_mode, com_mux_target, address, data);
+#elif __APPLE__
+    DEBUG_PRINTF("System is not recognized.");
+#elif __unix__
+    DEBUG_PRINTF("System is not recognized.");
+#elif __posix__
+    DEBUG_PRINTF("System is not recognized.");
+#else
+    DEBUG_PRINTF("System is not recognized.");
+#endif
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int lgw_com_wb(void *com_target, uint8_t com_mux_mode, uint8_t com_mux_target, uint8_t address, uint8_t *data, uint16_t size) {
+#ifdef _WIN32
+    return lgw_com_wb_win(com_target, com_mux_mode, com_mux_target, address, data, size);
+#elif __linux__
+    return lgw_com_wb_linux(com_target, com_mux_mode, com_mux_target, address, data, size);
+#elif __APPLE__
+    DEBUG_PRINTF("System is not recognized.");
+#elif __unix__
+    DEBUG_PRINTF("System is not recognized.");
+#elif __posix__
+    DEBUG_PRINTF("System is not recognized.");
+#else
+    DEBUG_PRINTF("System is not recognized.");
+#endif
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int lgw_com_rb(void *com_target, uint8_t com_mux_mode, uint8_t com_mux_target, uint8_t address, uint8_t *data, uint16_t size) {
+#ifdef _WIN32
+    return lgw_com_rb_win(com_target, com_mux_mode, com_mux_target, address, data, size);
+#elif __linux__
+    return lgw_com_rb_linux(com_target, com_mux_mode, com_mux_target, address, data, size);
+#elif __APPLE__
+    DEBUG_PRINTF("System is not recognized.");
+#elif __unix__
+    DEBUG_PRINTF("System is not recognized.");
+#elif __posix__
+    DEBUG_PRINTF("System is not recognized.");
+#else
+    DEBUG_PRINTF("System is not recognized.");
+#endif
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int lgw_com_send_command(void *com_target, lgw_com_cmd_t cmd, lgw_com_ans_t *ans) {
+    lgw_handle_t handle;
+
+    CHECK_NULL(com_target);
+    CHECK_NULL(ans);
+
+    handle = LGW_GET_HANDLE(com_target);
+
+    pthread_mutex_lock(&mx_usbbridgesync);
+
+    if (lgw_com_send_cmd(cmd, handle) == LGW_COM_ERROR) {
+        pthread_mutex_unlock(&mx_usbbridgesync);
+        return LGW_COM_ERROR;
+    }
+    if (lgw_com_receive_ans(ans, handle) == LGW_COM_ERROR) {
+        pthread_mutex_unlock(&mx_usbbridgesync);
+        return LGW_COM_ERROR;
+    }
+
+    pthread_mutex_unlock(&mx_usbbridgesync);
+
+    return LGW_COM_SUCCESS;
+}
+
+/* --- EOF ------------------------------------------------------------------ */
diff -r 000000000000 -r 102b50f941d0 libloragw/src/loragw_com_linux.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libloragw/src/loragw_com_linux.c	Wed Apr 11 14:38:42 2018 +0000
@@ -0,0 +1,559 @@
+/*
+ / _____)             _              | |
+( (____  _____ ____ _| |_ _____  ____| |__
+ \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+  (C)2017 Semtech-Cycleo
+
+Description:
+this file contains the USB commands to configure and communicate with the SX1308
+LoRA concentrator.
+A USB CDC drivers is required to establish the connection with the PicoCell
+board.
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+*/
+
+
+/* -------------------------------------------------------------------------- */
+/* --- 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 <errno.h>      /* Error number definitions */
+#include <termios.h>    /* POSIX terminal control definitions */
+#include <sys/ioctl.h>
+#include <pthread.h>
+#include <time.h>
+#include <sys/select.h>
+
+#include "loragw_com.h"
+#include "loragw_com_linux.h"
+#include "loragw_aux.h"
+#include "loragw_reg.h"
+#include "loragw_mcu.h"
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE MACROS ------------------------------------------------------- */
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+#if DEBUG_COM == 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_COM_ERROR;}
+#else
+#define DEBUG_MSG(str)
+#define DEBUG_PRINTF(fmt, args...)
+#define CHECK_NULL(a)                if(a==NULL){return LGW_COM_ERROR;}
+#endif
+
+#define UNUSED(x) (void)(x)
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE SHARED VARIABLES (GLOBAL) ------------------------------------ */
+
+extern pthread_mutex_t mx_usbbridgesync;
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE FUNCTIONS ---------------------------------------------------- */
+
+int set_interface_attribs_linux(int fd, int speed) {
+    struct termios tty;
+
+    memset(&tty, 0, sizeof tty);
+
+    /* Get current attributes */
+    if (tcgetattr(fd, &tty) != 0) {
+        DEBUG_PRINTF("ERROR: tcgetattr failed with %d - %s", errno, strerror(errno));
+        return LGW_COM_ERROR;
+    }
+
+    cfsetospeed(&tty, speed);
+    cfsetispeed(&tty, speed);
+
+    /* Control Modes */
+    tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8; /* set 8-bit characters */
+    tty.c_cflag |= CLOCAL;                      /* local connection, no modem control */
+    tty.c_cflag |= CREAD;                       /* enable receiving characters */
+    tty.c_cflag &= ~PARENB;                     /* no parity */
+    tty.c_cflag &= ~CSTOPB;                     /* one stop bit */
+    /* Input Modes */
+    tty.c_iflag &= ~IGNBRK;
+    tty.c_iflag &= ~(IXON | IXOFF | IXANY | ICRNL);
+    /* Output Modes */
+    tty.c_oflag &= ~IGNBRK;
+    tty.c_oflag &= ~(IXON | IXOFF | IXANY | ICRNL);
+    /* Local Modes */
+    tty.c_lflag = 0;
+    /* Settings for non-canonical mode */
+    tty.c_cc[VMIN] = 0;                         /* non-blocking mode */
+    tty.c_cc[VTIME] = 50;                       /* wait for (n * 0.1) seconds before returning */
+
+    /* Set attributes */
+    if (tcsetattr(fd, TCSANOW, &tty) != 0) {
+        DEBUG_PRINTF("ERROR: tcsetattr failed with %d - %s", errno, strerror(errno));
+        return LGW_COM_ERROR;
+    }
+
+    return LGW_COM_SUCCESS;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+/* configure TTYACM0 read blocking or not*/
+int set_blocking_linux(int fd, bool blocking) {
+    struct termios tty;
+
+    memset(&tty, 0, sizeof tty);
+
+    /* Get current attributes */
+    if (tcgetattr(fd, &tty) != 0) {
+        DEBUG_PRINTF("ERROR: tcgetattr failed with %d - %s", errno, strerror(errno));
+        return LGW_COM_ERROR;
+    }
+
+    tty.c_cc[VMIN] = (blocking == true) ? 1 : 0;    /* set blocking or non-blocking mode */
+    tty.c_cc[VTIME] = 1;                            /* wait for (n * 0.1) seconds before returning */
+
+    /* Set attributes */
+    if (tcsetattr(fd, TCSANOW, &tty) != 0) {
+        DEBUG_PRINTF("ERROR: tcsetattr failed with %d - %s", errno, strerror(errno));
+        return LGW_COM_ERROR;
+    }
+
+    return LGW_COM_SUCCESS;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+bool checkcmd_linux(uint8_t cmd) {
+    switch (cmd) {
+        case 'r': /* read register */
+        case 's': /* read burst - first chunk */
+        case 't': /* read burst - middle chunk */
+        case 'u': /* read burst - end chunk */
+        case 'p': /* read burst - atomic */
+        case 'w': /* write register */
+        case 'x': /* write burst - first chunk */
+        case 'y': /* write burst - middle chunk */
+        case 'z': /* write burst - end chunk */
+        case 'a': /* write burst - atomic */
+        case 'b': /* lgw_receive */
+        case 'c': /* lgw_rxrf_setconf */
+        case 'd': /* lgw_rxif_setconf */
+        case 'f': /* lgw_send */
+        case 'h': /* lgw_txgain_setconf */
+        case 'q': /* lgw_get_trigcnt */
+        case 'i': /* lgw_board_setconf */
+        case 'j': /* lgw_calibration_snapshot */
+        case 'l': /* lgw_check_fw_version */
+        case 'm': /* reset STM32 */
+        case 'n': /* Go to bootloader */
+            return true;
+        default:
+            return false;
+    }
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int lgw_com_send_cmd_linux(lgw_com_cmd_t cmd, lgw_handle_t handle) {
+    int i;
+    uint8_t buffertx[CMD_HEADER_TX_SIZE + CMD_DATA_TX_SIZE];
+    uint16_t Clen = cmd.len_lsb + (cmd.len_msb << 8);
+    uint16_t Tlen = CMD_HEADER_TX_SIZE + Clen;
+    ssize_t lencheck;
+
+    /* Initialize buffer */
+    memset(buffertx, 0, sizeof buffertx);
+
+    /* Prepare command */
+    buffertx[0] = (uint8_t)cmd.id;
+    buffertx[1] = cmd.len_msb;
+    buffertx[2] = cmd.len_lsb;
+    buffertx[3] = cmd.address;
+    for (i = 0; i < Clen; i++) {
+        buffertx[i + 4] = cmd.cmd_data[i];
+    }
+
+    /* Send command */
+    lencheck = write(handle, buffertx, Tlen);
+    if (lencheck < 0) {
+        DEBUG_PRINTF("ERROR: failed to write cmd (%d - %s)\n", errno, strerror(errno));
+        return LGW_COM_ERROR;
+    }
+    if (lencheck != Tlen) {
+        DEBUG_PRINTF("WARNING: incomplete cmd written (%d)\n", (int)lencheck);
+    }
+
+    DEBUG_PRINTF("Note: sent cmd \'%c\', addr 0x%02X, length=%d\n", cmd.id, cmd.address, Clen);
+
+    return LGW_COM_SUCCESS;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int lgw_com_receive_ans_linux(lgw_com_ans_t *ans, lgw_handle_t handle) {
+    int i;
+    uint8_t bufferrx[CMD_HEADER_RX_SIZE + CMD_DATA_RX_SIZE];
+    unsigned int buffer_idx;
+    size_t cmd_size;
+    ssize_t buf_size = 0;
+    ssize_t lencheck;
+
+    /* Initialize variables */
+    memset(bufferrx, 0, sizeof bufferrx);
+
+    /* Wait for cmd answer header */
+    buffer_idx = 0;
+    while ((checkcmd_linux(bufferrx[0]) != true) || (buffer_idx < CMD_HEADER_RX_SIZE)) {
+        lencheck = read(handle, &bufferrx[buffer_idx], CMD_HEADER_RX_SIZE - buffer_idx);
+        if (lencheck < 0) {
+            DEBUG_PRINTF("WARNING: failed to read from communication bridge (%d - %s), retry...\n", errno, strerror(errno));
+            return LGW_COM_ERROR;
+        }
+        buffer_idx += lencheck;
+    }
+
+    cmd_size = (bufferrx[1] << 8) + bufferrx[2];
+
+    DEBUG_PRINTF("Note: received answer header for cmd \'%c\', length=%zd, ack=%u\n", bufferrx[0], cmd_size, bufferrx[3]);
+
+    /* Read answer Data */
+    if (cmd_size > 0) {
+        /* Determine how much we need to read */
+        buf_size = cmd_size + CMD_HEADER_RX_SIZE;
+        if ((buf_size % 64) == 0) {
+            cmd_size = cmd_size + 1; /* one padding byte is added by USB driver, we need to read it */
+        }
+        /* Check that data size does not exceed buffer size */
+        if (cmd_size > CMD_DATA_RX_SIZE) {
+            DEBUG_PRINTF("ERROR: exceed read buffer size, abort. (%zd)\n", cmd_size);
+            return LGW_COM_ERROR;
+        }
+        /* Read the answer */
+        buffer_idx = 0;
+        while (buffer_idx < cmd_size) {
+            lencheck = read(handle, &bufferrx[CMD_HEADER_RX_SIZE + buffer_idx], cmd_size - buffer_idx);
+            if (lencheck < 0) {
+                DEBUG_PRINTF("ERROR: failed to read cmd answer (%d - %s)\n", errno, strerror(errno));
+                return LGW_COM_ERROR;
+            }
+            buffer_idx += lencheck;
+        }
+    }
+    ans->id = (char)bufferrx[0];
+    ans->len_msb = bufferrx[1];
+    ans->len_lsb = bufferrx[2];
+    ans->status = bufferrx[3];
+    for (i = 0; i < (int)cmd_size; i++) {
+        ans->ans_data[i] = bufferrx[CMD_HEADER_RX_SIZE + i];
+    }
+
+    DEBUG_PRINTF("Note: received answer for cmd \'%c\', length=%zd\n", bufferrx[0], cmd_size);
+
+    return LGW_COM_SUCCESS;
+}
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC FUNCTIONS DEFINITION ------------------------------------------ */
+
+int lgw_com_open_linux(void **com_target_ptr, const char *com_path) {
+
+    int *usb_device = NULL;
+    char portname[50];
+    int x;
+    int fd;
+
+    /*check input variables*/
+    CHECK_NULL(com_target_ptr);
+
+    usb_device = malloc(sizeof(int));
+    if (usb_device == NULL) {
+        DEBUG_MSG("ERROR : MALLOC FAIL\n");
+        return LGW_COM_ERROR;
+    }
+
+    /* open tty port */
+    sprintf(portname, "%s", com_path);
+    fd = open(portname, O_RDWR | O_NOCTTY | O_SYNC);
+    if (fd < 0) {
+        printf("ERROR: failed to open COM port %s - %s\n", portname, strerror(errno));
+    } else {
+        x = set_interface_attribs_linux(fd, B115200);
+        x |= set_blocking_linux(fd, true);
+        if (x != 0) {
+            printf("ERROR: failed to configure COM port %s\n", portname);
+            free(usb_device);
+            return LGW_COM_ERROR;
+        }
+
+        *usb_device = fd;
+        *com_target_ptr = (void*)usb_device;
+
+        return LGW_COM_SUCCESS;
+    }
+
+    free(usb_device);
+    return LGW_COM_ERROR;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int lgw_com_close_linux(void *com_target) {
+    int usb_device;
+    int a;
+
+    /*check input variables*/
+    CHECK_NULL(com_target);
+
+    /* close file & deallocate file descriptor */
+    usb_device = *(int*)com_target;
+    a = close(usb_device);
+    free(com_target);
+
+    /* determine return code */
+    if (a < 0) {
+        printf("ERROR: failed to close COM port - %s\n", strerror(errno));
+        return LGW_COM_ERROR;
+    } else {
+        DEBUG_MSG("Note : USB port closed\n");
+        return LGW_COM_SUCCESS;
+    }
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int lgw_com_w_linux(void *com_target, uint8_t com_mux_mode, uint8_t com_mux_target, uint8_t address, uint8_t data) {
+    int fd;
+    lgw_com_cmd_t cmd;
+    lgw_com_ans_t ans;
+    UNUSED(com_mux_mode);
+    UNUSED(com_mux_target);
+
+    /*check input variables*/
+    CHECK_NULL(com_target);
+
+    fd = *(int *)com_target; /* must check that com_target is not null beforehand */
+
+    cmd.id = 'w';
+    cmd.len_msb = 0;
+    cmd.len_lsb = 1;
+    cmd.address = address;
+    cmd.cmd_data[0] = data;
+
+    pthread_mutex_lock(&mx_usbbridgesync);
+    lgw_com_send_cmd_linux(cmd, fd);
+    if (lgw_com_receive_ans_linux(&ans, fd) == LGW_COM_ERROR) {
+        pthread_mutex_unlock(&mx_usbbridgesync);
+        return LGW_COM_ERROR;
+    }
+    pthread_mutex_unlock(&mx_usbbridgesync);
+
+    return LGW_COM_SUCCESS;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int lgw_com_r_linux(void *com_target, uint8_t com_mux_mode, uint8_t com_mux_target, uint8_t address, uint8_t *data) {
+    int fd;
+    lgw_com_cmd_t cmd;
+    lgw_com_ans_t ans;
+    UNUSED(com_mux_mode);
+    UNUSED(com_mux_target);
+
+    /* check input variables */
+    CHECK_NULL(com_target);
+    CHECK_NULL(data);
+
+    fd = *(int *)com_target; /* must check that com_target is not null beforehand */
+
+    cmd.id = 'r';
+    cmd.len_msb = 0;
+    cmd.len_lsb = 1;
+    cmd.address = address;
+    cmd.cmd_data[0] = 0;
+
+    pthread_mutex_lock(&mx_usbbridgesync);
+    lgw_com_send_cmd_linux(cmd, fd);
+    if (lgw_com_receive_ans_linux(&ans, fd) == LGW_COM_ERROR) {
+        pthread_mutex_unlock(&mx_usbbridgesync);
+        return LGW_COM_ERROR;
+    }
+    pthread_mutex_unlock(&mx_usbbridgesync);
+
+    *data = ans.ans_data[0];
+
+    return LGW_COM_SUCCESS;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int lgw_com_wb_linux(void *com_target, uint8_t com_mux_mode, uint8_t com_mux_target, uint8_t address, uint8_t *data, uint16_t size) {
+    int fd;
+    int i;
+    uint16_t chunk_size = size;
+    int cptalc = 0;
+    lgw_com_cmd_t cmd;
+    lgw_com_ans_t ans;
+    UNUSED(com_mux_mode);
+    UNUSED(com_mux_target);
+
+    /* check input parameters */
+    CHECK_NULL(com_target);
+    CHECK_NULL(data);
+
+    fd = *(int *)com_target;
+
+    /* lock for complete burst */
+    pthread_mutex_lock(&mx_usbbridgesync);
+
+    /* Split burst in multiple chunks if necessary */
+    while (chunk_size > ATOMICTX) {
+        /* Prepare command */
+        if (chunk_size == size) {
+            cmd.id = 'x'; /* write burst - first */
+        } else {
+            cmd.id = 'y'; /* write burst - middle */
+        }
+        cmd.len_msb = (uint8_t)((ATOMICTX >> 8) & 0xFF);
+        cmd.len_lsb = (uint8_t)((ATOMICTX >> 0) & 0xFF);
+        cmd.address = address;
+        for (i = 0; i < ATOMICTX; i++) {
+            cmd.cmd_data[i] = data[i + cptalc];
+        }
+
+        /* Send command */
+        lgw_com_send_cmd_linux(cmd, fd);
+        if (lgw_com_receive_ans_linux(&ans, fd) == LGW_COM_ERROR) {
+            pthread_mutex_unlock(&mx_usbbridgesync);
+            return LGW_COM_ERROR;
+        }
+
+        chunk_size = chunk_size - ATOMICTX;
+        cptalc = cptalc + ATOMICTX;
+    }
+
+    /* Complete multiple-chunk transfer, or send atomic one */
+    if (chunk_size > 0) {
+        /* Prepare command */
+        if (size <= ATOMICTX) {
+            cmd.id = 'a'; /* write burst - atomic */
+        } else {
+            cmd.id = 'z'; /* write burst - end */
+        }
+        cmd.len_msb = (uint8_t)((chunk_size >> 8) & 0xFF);
+        cmd.len_lsb = (uint8_t)((chunk_size >> 0) & 0xFF);
+        cmd.address = address;
+        for (i = 0; i < ((cmd.len_msb << 8) + cmd.len_lsb); i++) {
+            cmd.cmd_data[i] = data[i + cptalc];
+        }
+
+        /* Send command */
+        lgw_com_send_cmd_linux(cmd, fd);
+        if (lgw_com_receive_ans_linux(&ans, fd) == LGW_COM_ERROR) {
+            pthread_mutex_unlock(&mx_usbbridgesync);
+            return LGW_COM_ERROR;
+        }
+    } else {
+        pthread_mutex_unlock(&mx_usbbridgesync);
+        return LGW_COM_ERROR;
+    }
+
+    /* unlock burst */
+    pthread_mutex_unlock(&mx_usbbridgesync);
+
+    return LGW_COM_SUCCESS;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int lgw_com_rb_linux(void *com_target, uint8_t com_mux_mode, uint8_t com_mux_target, uint8_t address, uint8_t *data, uint16_t size) {
+    int fd;
+    int i;
+    uint16_t chunk_size = size;
+    int cptalc = 0;
+    lgw_com_cmd_t cmd;
+    lgw_com_ans_t ans;
+    UNUSED(com_mux_mode);
+    UNUSED(com_mux_target);
+
+    /* check input parameters */
+    CHECK_NULL(com_target);
+    CHECK_NULL(data);
+
+    fd = *(int *)com_target;
+
+    /* lock for complete burst */
+    pthread_mutex_lock(&mx_usbbridgesync);
+
+    /* Split burst in multiple chunks if necessary */
+    while (chunk_size > ATOMICRX) {
+        /* Prepare command */
+        if (chunk_size == size) {
+            cmd.id = 's'; /* read burst - first */
+        } else {
+            cmd.id = 't'; /* read burst - middle */
+        }
+        cmd.len_msb = 0;
+        cmd.len_lsb = 2;
+        cmd.cmd_data[0] = (uint8_t)((ATOMICRX >> 8) & 0xFF);
+        cmd.cmd_data[1] = (uint8_t)((ATOMICRX >> 0) & 0xFF);
+        cmd.address = address;
+
+        /* Send command */
+        lgw_com_send_cmd_linux(cmd, fd);
+        if (lgw_com_receive_ans_linux(&ans, fd) == LGW_COM_SUCCESS) {
+            for (i = 0; i < ATOMICRX; i++) {
+                data[i + cptalc] = ans.ans_data[i];
+            }
+        } else {
+            pthread_mutex_unlock(&mx_usbbridgesync);
+            return LGW_COM_ERROR;
+        }
+
+        chunk_size = chunk_size - ATOMICRX;
+        cptalc = cptalc + ATOMICRX;
+    }
+
+    /* Complete multiple-chunk transfer, or send atomic one */
+    if (chunk_size > 0) {
+        /* Prepare command */
+        if (size <= ATOMICRX) {
+            cmd.id = 'p'; /* read burst - atomic */
+        } else {
+            cmd.id = 'u'; /* read burst - end */
+        }
+        cmd.len_msb = 0;
+        cmd.len_lsb = 2;
+        cmd.cmd_data[0] = (uint8_t)((chunk_size >> 8) & 0xFF);
+        cmd.cmd_data[1] = (uint8_t)((chunk_size >> 0) & 0xFF);
+        cmd.address = address;
+
+        /* Send command */
+        lgw_com_send_cmd_linux(cmd, fd);
+        if (lgw_com_receive_ans_linux(&ans, fd) == LGW_COM_SUCCESS) {
+            for (i = 0; i < chunk_size; i++) {
+                data[i + cptalc] = ans.ans_data[i];
+            }
+        } else {
+            pthread_mutex_unlock(&mx_usbbridgesync);
+            return LGW_COM_ERROR;
+        }
+    } else {
+        pthread_mutex_unlock(&mx_usbbridgesync);
+        return LGW_COM_ERROR;
+    }
+
+    /* unlock burst */
+    pthread_mutex_unlock(&mx_usbbridgesync);
+
+    return LGW_COM_SUCCESS;
+}
+
+/* --- EOF ------------------------------------------------------------------ */
diff -r 000000000000 -r 102b50f941d0 libloragw/src/loragw_hal.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libloragw/src/loragw_hal.c	Wed Apr 11 14:38:42 2018 +0000
@@ -0,0 +1,1285 @@
+/*
+ / _____)             _              | |
+( (____  _____ ____ _| |_ _____  ____| |__
+ \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+  (C)2017 Semtech-Cycleo
+
+Description:
+    LoRa concentrator Hardware Abstraction Layer
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+*/
+
+
+/* -------------------------------------------------------------------------- */
+/* --- 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 <inttypes.h>   /* format macro constants... */
+
+#include "loragw_reg.h"
+#include "loragw_mcu.h"
+#include "loragw_hal.h"
+#include "loragw_aux.h"
+#include "loragw_radio.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   4
+#define STD_LORA_PREAMBLE   6
+#define MIN_FSK_PREAMBLE    3
+#define STD_FSK_PREAMBLE    5
+
+#define TX_START_DELAY      1500
+
+#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
+
+#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 */
+
+/* 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 */
+#include "cal_fw5-12.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 = false;
+
+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 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);
+
+int lgw_calibrate_sx125x(uint8_t *cal_fw, uint8_t idx_start, uint8_t idx_nb);
+
+/* -------------------------------------------------------------------------- */
+/* --- 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) {
+
+        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 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;
+    }
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int lgw_calibrate_sx125x(uint8_t *cal_fw, uint8_t idx_start, uint8_t idx_nb) {
+    int i, err;
+    int32_t read_val;
+    uint8_t fw_version;
+    uint8_t cal_cmd;
+    uint16_t cal_time;
+    uint8_t cal_status;
+
+    /* check parameters */
+    if (cal_fw == NULL) {
+        DEBUG_MSG("ERROR: invalid parameter, null pointer\n");
+        return LGW_HAL_ERROR;
+    }
+    if ((idx_start < 5) || (idx_start > 15)) {
+        DEBUG_MSG("ERROR: invalid parameter, calibration offset index start must be [5-15]\n");
+        return LGW_HAL_ERROR;
+    }
+    if (idx_nb > 8) {
+        DEBUG_MSG("ERROR: invalid parameter, calibration offset index number must be <= 8\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);
+
+#if 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 */
+#endif
+    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;
+    }
+  
+    /* 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_fw, 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) {
+
+        return LGW_HAL_ERROR;
+    }
+
+    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 = 0x%X)\n", cal_status);
+        return LGW_HAL_ERROR;
+    } else {
+        DEBUG_PRINTF("Note: calibration finished (status = 0x%X)\n", cal_status);
+    }
+    if (rf_enable[0] && ((cal_status & 0x02) == 0)) {
+        DEBUG_MSG("ERROR: calibration could not access radio A\n");
+        return LGW_HAL_ERROR;
+    }
+    if (rf_enable[1] && ((cal_status & 0x04) == 0)) {
+        DEBUG_MSG("ERROR: calibration could not access radio B\n");
+        return LGW_HAL_ERROR;
+    }
+    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 < (int)idx_nb; ++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;
+        DEBUG_PRINTF("calibration a_i = %d\n", cal_offset_a_i[i]);
+    }
+
+    /* Require MCU to capture calibration values */
+    lgw_mcu_commit_radio_calibration(idx_start, idx_nb);
+
+    return LGW_HAL_SUCCESS;
+}
+
+/* -------------------------------------------------------------------------- */
+/* --- 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);
+
+    /* send configuration to concentrator MCU */
+    return lgw_mcu_board_setconf(conf);
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+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;
+    }
+
+    /* 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;
+
+    DEBUG_PRINTF("Note: rf_chain %d configuration; en:%d freq:%d rssi_offset:%f radio_type:%d tx_enable:%d\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]);
+
+    /* send configuration to concentrator MCU */
+    return lgw_mcu_rxrf_setconf(rf_chain, conf);
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+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;
+    }
+    switch (conf.bandwidth) {
+        case BW_250KHZ:
+            rf_rx_bandwidth = LGW_RF_RX_BANDWIDTH_250KHZ;
+            break;
+        case BW_500KHZ:
+            rf_rx_bandwidth = LGW_RF_RX_BANDWIDTH_500KHZ;
+            break;
+        default:
+            rf_rx_bandwidth = LGW_RF_RX_BANDWIDTH_125KHZ;
+            break;
+    }
+
+    bw_hz = lgw_bw_getval(conf.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:%u dr:%u (%u real dr) sync:0x%0*" PRIx64 "\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;
+    }
+
+    /* send configuration to concentrator MCU */
+    return lgw_mcu_rxif_setconf(if_chain, conf);
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+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;
+        }
+        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;
+    }
+
+    /* send configuration to concentrator MCU */
+    return lgw_mcu_txgain_setconf(conf);
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int lgw_start(void) {
+    int i, err;
+    unsigned x;
+    uint8_t radio_select;
+    int32_t read_val;
+    uint8_t load_val;
+    uint8_t fw_version;
+    uint64_t fsk_sync_word_reg;
+
+    if (lgw_is_started == true) {
+        DEBUG_MSG("Note: LoRa concentrator already started, restarting it now\n");
+    }
+
+    /* Calibrate radios */
+    err = lgw_calibrate_sx125x(callow_firmware, 5, 8);
+    if (err != LGW_HAL_SUCCESS) {
+        DEBUG_MSG("ERROR: Failed to calibrate sx125x radios (5-12)\n");
+        return LGW_HAL_ERROR;
+    }
+    wait_ms(5);
+    err = lgw_calibrate_sx125x(cal_firmware, 8, 8);
+    if (err != LGW_HAL_SUCCESS) {
+        DEBUG_MSG("ERROR: Failed to calibrate sx125x radios (8-15)\n");
+        return LGW_HAL_ERROR;
+    }
+
+    /* RX and TX packets signalling through GPIOs */
+    lgw_reg_w(LGW_GPIO_MODE, 31); /* Set all GPIOs as output */
+    lgw_reg_w(LGW_GPIO_SELECT_OUTPUT, 0);
+
+    /* 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(10);
+
+    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(10);
+        load_val = AGC_CMD_ABORT;
+        lgw_reg_w(LGW_RADIO_SELECT, load_val);
+        wait_ms(10);
+        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(10);
+    lgw_reg_w(LGW_RADIO_SELECT, 3);
+    wait_ms(10);
+    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(10);
+    lgw_reg_w(LGW_RADIO_SELECT, 0);
+    wait_ms(10);
+    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(10);
+    lgw_reg_w(LGW_RADIO_SELECT, radio_select); /* Load intended value of RADIO_SELECT */
+    wait_ms(10);
+    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, 0);
+
+    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) {
+    /* 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;
+    }
+
+    /* send packet data to concentrator MCU */
+    return lgw_mcu_receive( max_pkt, pkt_data);
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int lgw_send(struct lgw_pkt_tx_s pkt_data) {
+    /* 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;
+    }
+
+    /* send packet data to concentrator MCU */
+    return lgw_mcu_send(pkt_data);
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+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) {
+    return lgw_reg_w(LGW_TX_TRIG_ALL, 0);
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int lgw_get_trigcnt(uint32_t* trig_cnt_us) {
+    return lgw_mcu_get_trigcnt(trig_cnt_us);
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+const char* lgw_version_info() {
+    return lgw_version_string;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int lgw_mcu_version_info() {
+    return (int)(STM32FWVERSION);
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+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 = (8 + 4.25) * Tsym; /* 8 programmed symbols in preamble */
+
+        /* 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 -r 000000000000 -r 102b50f941d0 libloragw/src/loragw_mcu.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libloragw/src/loragw_mcu.c	Wed Apr 11 14:38:42 2018 +0000
@@ -0,0 +1,552 @@
+/*
+ / _____)             _              | |
+( (____  _____ ____ _| |_ _____  ____| |__
+ \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+  (C)2017 Semtech-Cycleo
+
+Description:
+ Wrapper to call MCU's HAL functions
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+*/
+
+
+/* -------------------------------------------------------------------------- */
+/* --- 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 <errno.h>              /* Error number definitions */
+#include <termios.h>            /* POSIX terminal control definitions */
+#include <sys/ioctl.h>
+#include <pthread.h>
+#include <time.h>
+#include <sys/select.h>
+
+#include "loragw_com.h"
+#include "loragw_mcu.h"
+#include "loragw_aux.h"
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE MACROS ------------------------------------------------------- */
+
+#if DEBUG_MCU == 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_COM_ERROR;}
+#else
+#define DEBUG_MSG(str)
+#define DEBUG_PRINTF(fmt, args...)
+#define CHECK_NULL(a)                if(a==NULL){return LGW_COM_ERROR;}
+#endif
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE SHARED VARIABLES (GLOBAL) ------------------------------------ */
+
+extern void *lgw_com_target; /*! generic pointer to the COM device */
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE CONSTANTS ---------------------------------------------------- */
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC FUNCTIONS DEFINITION ------------------------------------------ */
+
+int lgw_mcu_board_setconf(struct lgw_conf_board_s conf) {
+    int i, x;
+    lgw_com_cmd_t cmd;
+    lgw_com_ans_t ans;
+    uint8_t PADDING = 0;
+    uint8_t data[4];
+    uint16_t size;
+
+    /* struct to byte array */
+    data[0] = conf.lorawan_public;
+    data[1] = conf.clksrc;
+    data[2] = PADDING;
+    data[3] = PADDING;
+    size = sizeof(data) / sizeof(uint8_t);
+
+    /* prepare command */
+    cmd.id = 'i';
+    cmd.len_msb = (uint8_t)((size >> 8) & 0xFF);
+    cmd.len_lsb = (uint8_t)((size >> 0) & 0xFF);
+    cmd.address = 0;
+    for (i = 0; i < size; i++) {
+        cmd.cmd_data[i] = data[i];
+    }
+
+    /* send command to MCU */
+    x = lgw_com_send_command(lgw_com_target, cmd, &ans);
+    if (x != LGW_COM_SUCCESS) {
+        printf("ERROR: failed to configure board\n");
+        return LGW_MCU_ERROR;
+    }
+
+    /* check command acknoledge */
+    if (ans.status != ACK_OK) {
+        printf("ERROR: failed to configure board, ACK failed\n");
+        return LGW_MCU_ERROR;
+    }
+
+    return LGW_MCU_SUCCESS;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int lgw_mcu_rxrf_setconf(uint8_t rfchain, struct lgw_conf_rxrf_s conf) {
+    int i, x;
+    lgw_com_cmd_t cmd;
+    lgw_com_ans_t ans;
+    uint8_t PADDING = 0;
+    uint8_t data[20];
+    uint16_t size;
+
+    /* struct to byte array */
+    /* --- 64-bits start --- */
+    data[0] = conf.enable;
+    data[1] = PADDING;
+    data[2] = PADDING;
+    data[3] = PADDING;
+    data[4] = *(((uint8_t *)(&conf.freq_hz)));
+    data[5] = *(((uint8_t *)(&conf.freq_hz)) + 1);
+    data[6] = *(((uint8_t *)(&conf.freq_hz)) + 2);
+    data[7] = *(((uint8_t *)(&conf.freq_hz)) + 3);
+    /* --- 64-bits start --- */
+    data[8] = *(((uint8_t *)(&conf.rssi_offset)));
+    data[9] = *(((uint8_t *)(&conf.rssi_offset)) + 1);
+    data[10] = *(((uint8_t *)(&conf.rssi_offset)) + 2);
+    data[11] = *(((uint8_t *)(&conf.rssi_offset)) + 3);
+    data[12] = *(((uint8_t *)(&conf.type)));
+    data[13] = PADDING;
+    data[14] = PADDING;
+    data[15] = PADDING;
+    /* --- 64-bits start --- */
+    data[16] = *(((uint8_t *)(&conf.tx_enable)));
+    data[17] = *(((uint8_t *)(&conf.tx_enable)) + 1);
+    data[18] = *(((uint8_t *)(&conf.tx_enable)) + 2);
+    data[19] = *(((uint8_t *)(&conf.tx_enable)) + 3);
+    size = sizeof(data) / sizeof(uint8_t);
+
+    /* prepare command */
+    cmd.id = 'c';
+    cmd.len_msb = (uint8_t)((size >> 8) & 0xFF);
+    cmd.len_lsb = (uint8_t)((size >> 0) & 0xFF);
+    cmd.address = rfchain;
+    for (i = 0; i < size; i++) {
+        cmd.cmd_data[i] = data[i];
+    }
+
+    /* send command to MCU */
+    x = lgw_com_send_command(lgw_com_target, cmd, &ans);
+    if (x != LGW_COM_SUCCESS) {
+        printf("ERROR: failed to send rxrf configuration\n");
+        return LGW_MCU_ERROR;
+    }
+
+    /* check command acknoledge */
+    if (ans.status != ACK_OK) {
+        printf("ERROR: rxrf configuration, ACK failed\n");
+        return LGW_MCU_ERROR;
+    }
+
+    return LGW_MCU_SUCCESS;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int lgw_mcu_rxif_setconf(uint8_t ifchain, struct lgw_conf_rxif_s conf) {
+    int i, x;
+    lgw_com_cmd_t cmd;
+    lgw_com_ans_t ans;
+    uint8_t PADDING = 0;
+    uint8_t data[32];
+    uint16_t size;
+
+    /* struct to byte array */
+    /* --- 64-bits start --- */
+    data[0] = conf.enable;
+    data[1] = *(((uint8_t *)(&conf.rf_chain)));
+    data[2] = PADDING;
+    data[3] = PADDING;
+    data[4] = *(((uint8_t *)(&conf.freq_hz)));
+    data[5] = *(((uint8_t *)(&conf.freq_hz)) + 1);
+    data[6] = *(((uint8_t *)(&conf.freq_hz)) + 2);
+    data[7] = *(((uint8_t *)(&conf.freq_hz)) + 3);
+    /* --- 64-bits start --- */
+    data[8] = *(((uint8_t *)(&conf.bandwidth)));
+    data[9] = PADDING;
+    data[10] = PADDING;
+    data[11] = PADDING;
+    data[12] = *(((uint8_t *)(&conf.datarate)));
+    data[13] = *(((uint8_t *)(&conf.datarate)) + 1);
+    data[14] = *(((uint8_t *)(&conf.datarate)) + 2);
+    data[15] = *(((uint8_t *)(&conf.datarate)) + 3);
+    /* --- 64-bits start --- */
+    data[16] = *(((uint8_t *)(&conf.sync_word_size)));
+    data[17] = PADDING;
+    data[18] = PADDING;
+    data[19] = PADDING;
+    data[20] = PADDING;
+    data[21] = PADDING;
+    data[22] = PADDING;
+    data[23] = PADDING;
+    /* --- 64-bits start --- */
+    data[24] = *(((uint8_t *)(&conf.sync_word)));
+    data[25] = *(((uint8_t *)(&conf.sync_word)) + 1);
+    data[26] = *(((uint8_t *)(&conf.sync_word)) + 2);
+    data[27] = *(((uint8_t *)(&conf.sync_word)) + 3);
+    data[28] = *(((uint8_t *)(&conf.sync_word)) + 4);
+    data[29] = *(((uint8_t *)(&conf.sync_word)) + 5);
+    data[30] = *(((uint8_t *)(&conf.sync_word)) + 6);
+    data[31] = *(((uint8_t *)(&conf.sync_word)) + 7);
+    size = sizeof(data) / sizeof(uint8_t);
+
+    /* prepare command */
+    cmd.id = 'd';
+    cmd.len_msb = (uint8_t)((size >> 8) & 0xFF);
+    cmd.len_lsb = (uint8_t)((size >> 0) & 0xFF);
+    cmd.address = ifchain;
+    for (i = 0; i < size; i++) {
+        cmd.cmd_data[i] = data[i];
+    }
+
+    /* send command to MCU */
+    x = lgw_com_send_command(lgw_com_target, cmd, &ans);
+    if (x != LGW_COM_SUCCESS) {
+        printf("ERROR: failed to send rxif configuration\n");
+        return LGW_MCU_ERROR;
+    }
+
+    /* check command acknoledge */
+    if (ans.status != ACK_OK) {
+        printf("ERROR: rxif configuration, ACK failed\n");
+        return LGW_MCU_ERROR;
+    }
+
+    return LGW_MCU_SUCCESS;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int lgw_mcu_txgain_setconf(struct lgw_tx_gain_lut_s *conf) {
+    int i, x;
+    lgw_com_cmd_t cmd;
+    lgw_com_ans_t ans;
+    uint32_t u = 0;
+    uint8_t data[(LGW_MULTI_NB * TX_GAIN_LUT_SIZE_MAX) + 4];
+    uint16_t size;
+
+    /* struct to byte array */
+    for (u = 0; u < TX_GAIN_LUT_SIZE_MAX; u++) {
+        data[0 + (5 * u)] = 0;
+        data[1 + (5 * u)] = 0;
+        data[2 + (5 * u)] = 0;
+        data[3 + (5 * u)] = 0;
+        data[4 + (5 * u)] = 0;
+    }
+
+    for (u = 0; u < conf->size; u++) {
+        data[0 + (5 * u)] = conf->lut[u].dig_gain;
+        data[1 + (5 * u)] = conf->lut[u].pa_gain;
+        data[2 + (5 * u)] = conf->lut[u].dac_gain;
+        data[3 + (5 * u)] = conf->lut[u].mix_gain;
+        data[4 + (5 * u)] = conf->lut[u].rf_power;
+    }
+    data[(TX_GAIN_LUT_SIZE_MAX) * 5] = conf->size;
+    size = ((TX_GAIN_LUT_SIZE_MAX) * 5) + 1;
+
+    /* prepare command */
+    cmd.id = 'h';
+    cmd.len_msb = (uint8_t)((size >> 8) & 0xFF);
+    cmd.len_lsb = (uint8_t)((size >> 0) & 0xFF);
+    cmd.address = 0;
+    for (i = 0; i < size; i++) {
+        cmd.cmd_data[i] = data[i];
+    }
+
+    /* send command to MCU */
+    x = lgw_com_send_command(lgw_com_target, cmd, &ans);
+    if (x != LGW_COM_SUCCESS) {
+        printf("ERROR: failed to send tx gain configuration\n");
+        return LGW_MCU_ERROR;
+    }
+
+    /* check command acknoledge */
+    if (ans.status != ACK_OK) {
+        printf("ERROR: tx gain configuration, ACK failed\n");
+        return LGW_MCU_ERROR;
+    }
+
+    return LGW_MCU_SUCCESS;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int lgw_mcu_receive(uint8_t max_pkt, struct lgw_pkt_rx_s *pkt_data) {
+    int i, j, x;
+    int cptalc = 0;
+    lgw_com_cmd_t cmd;
+    lgw_com_ans_t ans;
+    int nb_packet ;
+    uint8_t data[LGW_PKT_RX_STRUCT_SIZE_ALIGNED * max_pkt];
+    uint16_t pkt_size;
+
+    /* check input variables */
+    CHECK_NULL(pkt_data);
+
+    /* Prepare command for fetching packets */
+    cmd.id = 'b';
+    cmd.len_msb = 0;
+    cmd.len_lsb = 1;
+    cmd.address = 0;
+    cmd.cmd_data[0] = max_pkt;
+
+    /* send command to MCU */
+    x = lgw_com_send_command(lgw_com_target, cmd, &ans);
+    if ((x != LGW_COM_SUCCESS) || (ans.status != ACK_OK)) {
+        DEBUG_MSG("ERROR: failed to receive packets from concentrator\n");
+        return 0;
+    }
+
+    /* check nb_packet variables */
+    nb_packet = ans.ans_data[0];
+    if ((nb_packet > LGW_PKT_FIFO_SIZE) || (nb_packet < 0)) {
+        DEBUG_PRINTF("ERROR: NOT A VALID NUMBER OF RECEIVED PACKET (%d)\n", nb_packet);
+        return 0;
+    }
+
+    //DEBUG_PRINTF("NOTE: Available packet %d %d\n", nb_packet, (ans.len_msb << 8) + ans.len_lsb);
+
+    /* over the number of packets */
+    for (i = 0; i < nb_packet; i++) {
+        /* for each packet */
+        pkt_size = (uint16_t)((uint8_t)(ans.ans_data[cptalc + 42] << 8) | (uint8_t)ans.ans_data[cptalc + 43]);
+        for (j = 0; j < (LGW_PKT_RX_METADATA_SIZE_ALIGNED + pkt_size); j++) {
+            data[(i * LGW_PKT_RX_STRUCT_SIZE_ALIGNED) + j] = ans.ans_data[j + cptalc + 1]; /* +1 because ans.ans_data[0] is nb_packet */
+        }
+        cptalc += j;
+    }
+
+    /* byte array to struct - the following code is done to work both with 32 or 64 bits host */
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wstrict-aliasing"
+    for (i = 0; i < nb_packet; i++) {
+        /* --- 64-bits start --- */
+        pkt_data[i].freq_hz = *((uint32_t*)(&data[0 + LGW_PKT_RX_STRUCT_SIZE_ALIGNED * i]));
+        pkt_data[i].if_chain = *((uint8_t*)(&data[4 + LGW_PKT_RX_STRUCT_SIZE_ALIGNED * i]));
+        pkt_data[i].status = *((uint8_t*)(&data[5 + LGW_PKT_RX_STRUCT_SIZE_ALIGNED * i]));
+        /* 1 BYTE PADDING FOR 64-bits ALIGNMENT */
+        /* 1 BYTE PADDING FOR 64-bits ALIGNMENT */
+        /* --- 64-bits start --- */
+        pkt_data[i].count_us = *((uint32_t*)(&data[8 + LGW_PKT_RX_STRUCT_SIZE_ALIGNED * i]));
+        pkt_data[i].rf_chain = *((uint8_t*)(&data[12 + LGW_PKT_RX_STRUCT_SIZE_ALIGNED * i]));
+        pkt_data[i].modulation = *((uint8_t*)(&data[13 + LGW_PKT_RX_STRUCT_SIZE_ALIGNED * i]));
+        pkt_data[i].bandwidth = *((uint8_t*)(&data[14 + LGW_PKT_RX_STRUCT_SIZE_ALIGNED * i]));
+        /* 1 BYTE PADDING FOR 64-bits ALIGNMENT */
+        /* --- 64-bits start --- */
+        pkt_data[i].datarate = *((uint32_t*)(&data[16 + LGW_PKT_RX_STRUCT_SIZE_ALIGNED * i]));
+        pkt_data[i].coderate = *((uint8_t*)(&data[20 + LGW_PKT_RX_STRUCT_SIZE_ALIGNED * i]));
+        /* --- 64-bits start --- */
+        pkt_data[i].rssi = *((float*)(&data[24 + LGW_PKT_RX_STRUCT_SIZE_ALIGNED * i]));
+        pkt_data[i].snr = *((float*)(&data[28 + LGW_PKT_RX_STRUCT_SIZE_ALIGNED * i]));
+        /* --- 64-bits start --- */
+        pkt_data[i].snr_min = *((float*)(&data[32 + LGW_PKT_RX_STRUCT_SIZE_ALIGNED * i]));
+        pkt_data[i].snr_max = *((float*)(&data[36 + LGW_PKT_RX_STRUCT_SIZE_ALIGNED * i]));
+        /* --- 64-bits start --- */
+        pkt_data[i].crc = *((uint16_t*)(&data[40 + LGW_PKT_RX_STRUCT_SIZE_ALIGNED * i]));
+        pkt_data[i].size = *((uint16_t*)(&data[42 + LGW_PKT_RX_STRUCT_SIZE_ALIGNED * i]));
+        /* NO PADDING NEEDED HERE, END OF ARRAY */
+        for (j = 0; j < 256; j++) {
+            (pkt_data[i].payload[j]) = *((uint8_t*)(&data[LGW_PKT_RX_METADATA_SIZE_ALIGNED + j + LGW_PKT_RX_STRUCT_SIZE_ALIGNED * i]));
+        }
+    }
+#pragma GCC diagnostic pop
+
+    return nb_packet;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int lgw_mcu_send(struct lgw_pkt_tx_s pkt_data) {
+    int i, x;
+    lgw_com_cmd_t cmd;
+    lgw_com_ans_t ans;
+    uint8_t PADDING = 0;
+    uint8_t data[LGW_PKT_TX_STRUCT_SIZE_ALIGNED];
+    uint16_t size;
+
+    /* struct to byte array */
+    /* --- 64-bits start --- */
+    data[0] = *(((uint8_t *)(&pkt_data.freq_hz)));
+    data[1] = *(((uint8_t *)(&pkt_data.freq_hz)) + 1);
+    data[2] = *(((uint8_t *)(&pkt_data.freq_hz)) + 2);
+    data[3] = *(((uint8_t *)(&pkt_data.freq_hz)) + 3);
+    data[4] = *(((uint8_t *)(&pkt_data.tx_mode)));
+    data[5] = PADDING;
+    data[6] = PADDING;
+    data[7] = PADDING;
+    /* --- 64-bits start --- */
+    data[8] = *(((uint8_t *)(&pkt_data.count_us)));
+    data[9] = *(((uint8_t *)(&pkt_data.count_us)) + 1);
+    data[10] = *(((uint8_t *)(&pkt_data.count_us)) + 2);
+    data[11] = *(((uint8_t *)(&pkt_data.count_us)) + 3);
+    data[12] = *(((uint8_t *)(&pkt_data.rf_chain)));
+    data[13] = *(((uint8_t *)(&pkt_data.rf_power)));
+    data[14] = *(((uint8_t *)(&pkt_data.modulation)));
+    data[15] = *(((uint8_t *)(&pkt_data.bandwidth)));
+    /* --- 64-bits start --- */
+    data[16] = *(((uint8_t *)(&pkt_data.datarate)));
+    data[17] = *(((uint8_t *)(&pkt_data.datarate)) + 1);
+    data[18] = *(((uint8_t *)(&pkt_data.datarate)) + 2);
+    data[19] = *(((uint8_t *)(&pkt_data.datarate)) + 3);
+    data[20] = *(((uint8_t *)(&pkt_data.coderate)));
+    data[21] = *(((uint8_t *)(&pkt_data.invert_pol)));
+    data[22] = *(((uint8_t *)(&pkt_data.f_dev)));
+    data[23] = PADDING;
+    /* --- 64-bits start --- */
+    data[24] = *(((uint8_t *)(&pkt_data.preamble)));
+    data[25] = *(((uint8_t *)(&pkt_data.preamble)) + 1);
+    data[26] = *(((uint8_t *)(&pkt_data.no_crc)));
+    data[27] = *(((uint8_t *)(&pkt_data.no_header)));
+    data[28] = *(((uint8_t *)(&pkt_data.size)));
+    data[29] = *(((uint8_t *)(&pkt_data.size)) + 1);
+    /* NO PADDING NEEDED HERE, END OF ARRAY */
+    for (i = 0; i < 256; i++) {
+        data[i + LGW_PKT_TX_METADATA_SIZE_ALIGNED] = *(((uint8_t *)(&pkt_data.payload)) + i);
+    }
+    size = sizeof(data) / sizeof(uint8_t);
+
+    /* prepare command */
+    cmd.id = 'f';
+    cmd.len_msb = (uint8_t)((size >> 8) & 0xFF);
+    cmd.len_lsb = (uint8_t)((size >> 0) & 0xFF);
+    cmd.address = 0;
+    for (i = 0; i < size; i++) {
+        cmd.cmd_data[i] = data[i];
+    }
+
+    /* send command to MCU */
+    x = lgw_com_send_command(lgw_com_target, cmd, &ans);
+    if (x != LGW_COM_SUCCESS) {
+        printf("ERROR: failed to send packet\n");
+        return LGW_MCU_ERROR;
+    }
+
+    /* check command acknoledge */
+    if (ans.status != ACK_OK) {
+        printf("ERROR: failed to send packet, ACK failed\n");
+        return LGW_MCU_ERROR;
+    }
+
+    return LGW_MCU_SUCCESS;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int lgw_mcu_get_trigcnt(uint32_t *data) {
+    int x;
+    lgw_com_cmd_t cmd;
+    lgw_com_ans_t ans;
+
+    /* check input variables */
+    CHECK_NULL(data);
+
+    /* prepare command */
+    cmd.id = 'q';
+    cmd.len_msb = 0;
+    cmd.len_lsb = 0;
+    cmd.address = 0;
+
+    /* send command to MCU */
+    x = lgw_com_send_command(lgw_com_target, cmd, &ans);
+    if ((x != LGW_COM_SUCCESS) || (ans.status != ACK_OK)) {
+        DEBUG_MSG("ERROR: failed to get concentrator internal counter\n");
+        return LGW_MCU_ERROR;
+    }
+
+    *data = (ans.ans_data[0] << 24) + (ans.ans_data[1] << 16) + (ans.ans_data[2] << 8) + (ans.ans_data[3]);
+    DEBUG_PRINTF("Note: sx1301 counter %u\n", *data);
+
+    return LGW_MCU_SUCCESS;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int lgw_mcu_commit_radio_calibration(uint8_t idx_start, uint8_t idx_nb) {
+    lgw_com_cmd_t cmd;
+    lgw_com_ans_t ans;
+
+    /* prepare command */
+    cmd.id = 'j';
+    cmd.len_msb = 0;
+    cmd.len_lsb = 2;
+    cmd.address = 0;
+    cmd.cmd_data[0] = idx_start;
+    cmd.cmd_data[1] = idx_nb;
+
+    /* send command to MCU */
+    return lgw_com_send_command(lgw_com_target, cmd, &ans);
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int lgw_mcu_reset(void) {
+    lgw_com_cmd_t cmd;
+    lgw_com_ans_t ans;
+
+    /* prepare command */
+    cmd.id = 'm';
+    cmd.len_msb = 0;
+    cmd.len_lsb = 0;
+    cmd.address = 0;
+
+    /* send command to MCU */
+    return lgw_com_send_command(lgw_com_target, cmd, &ans);
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int lgw_mcu_get_unique_id(uint8_t *uid) {
+    int i, x;
+    int fwversion = STM32FWVERSION;
+    lgw_com_cmd_t cmd;
+    lgw_com_ans_t ans;
+
+    /* prepare command */
+    cmd.id = 'l';
+    cmd.len_msb = 0;
+    cmd.len_lsb = 4;
+    cmd.address = 0;
+    cmd.cmd_data[0] = (uint8_t)((fwversion >> 24) & (0x000000ff));
+    cmd.cmd_data[1] = (uint8_t)((fwversion >> 16) & (0x000000ff));
+    cmd.cmd_data[2] = (uint8_t)((fwversion >> 8) & (0x000000ff));
+    cmd.cmd_data[3] = (uint8_t)((fwversion) & (0x000000ff));
+
+    /* send command to MCU */
+    x = lgw_com_send_command(lgw_com_target, cmd, &ans);
+    if (x != LGW_COM_SUCCESS) {
+        DEBUG_MSG("ERROR: Failed to get MCU unique ID\n");
+        return LGW_MCU_ERROR;
+    }
+
+    /* Check MCU FW version */
+    if (ans.status == ACK_KO) {
+        DEBUG_MSG("ERROR: Invalid MCU firmware version\n");
+        return LGW_MCU_ERROR;
+    }
+
+    /* Get MCU unique ID */
+    for (i = 0; i <= 7; i++) {
+        uid[i] = ans.ans_data[i];
+    }
+
+    return LGW_MCU_SUCCESS;
+}
+
+/* --- EOF ------------------------------------------------------------------ */
diff -r 000000000000 -r 102b50f941d0 libloragw/src/loragw_radio.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libloragw/src/loragw_radio.c	Wed Apr 11 14:38:42 2018 +0000
@@ -0,0 +1,250 @@
+/*
+ / _____)             _              | |
+( (____  _____ ____ _| |_ _____  ____| |__
+ \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+  (C)2017 Semtech-Cycleo
+
+Description:
+    Functions used to handle LoRa concentrator radios.
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+
+*/
+
+/* -------------------------------------------------------------------------- */
+/* --- DEPENDANCIES --------------------------------------------------------- */
+
+#include <stdint.h>     /* C99 types */
+#include <stdbool.h>    /* bool type */
+#include <stdio.h>      /* printf fprintf */
+
+#include "loragw_sx125x.h"
+#include "loragw_com.h"
+#include "loragw_aux.h"
+#include "loragw_reg.h"
+#include "loragw_hal.h"
+#include "loragw_radio.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_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
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE VARIABLES ---------------------------------------------------- */
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE FUNCTIONS ---------------------------------------------------- */
+
+void sx125x_write(uint8_t channel, uint8_t addr, uint8_t data);
+uint8_t sx125x_read(uint8_t channel, uint8_t addr);
+
+/* -------------------------------------------------------------------------- */
+/* --- 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;
+}
+
+/* -------------------------------------------------------------------------- */
+/* --- 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;
+}
+
+/* --- EOF ------------------------------------------------------------------ */
diff -r 000000000000 -r 102b50f941d0 libloragw/src/loragw_reg.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libloragw/src/loragw_reg.c	Wed Apr 11 14:38:42 2018 +0000
@@ -0,0 +1,798 @@
+/*
+ / _____)             _              | |
+( (____  _____ ____ _| |_ _____  ____| |__
+ \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+  (C)2017 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
+
+*/
+
+
+/* -------------------------------------------------------------------------- */
+/* --- DEPENDANCIES --------------------------------------------------------- */
+
+#include <stdint.h>     /* C99 types */
+#include <stdbool.h>    /* bool type */
+#include <stdio.h>      /* printf fprintf */
+
+#include "loragw_com.h"
+#include "loragw_mcu.h"
+#include "loragw_reg.h"
+#include "loragw_aux.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
+
+/*
+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},  /* com_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},  /* com_MASTER_CHIP_SELECT_POLARITY */
+    {2, 82, 1, 0, 1, 0, 0},  /* com_MASTER_CPOL */
+    {2, 82, 2, 0, 1, 0, 0},  /* com_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 ---------------------------------------------------- */
+
+void *lgw_com_target = NULL; /*! generic pointer to the COM device */
+static int lgw_regpage = -1; /*! keep the value of the register page selected */
+uint8_t lgw_com_mux_mode = 0; /*! current SPI mux mode used */
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE FUNCTIONS ---------------------------------------------------- */
+
+int page_switch(uint8_t target) {
+    lgw_regpage = PAGE_MASK & target;
+    lgw_com_w(lgw_com_target, lgw_com_mux_mode, LGW_COM_MUX_TARGET_SX1301, PAGE_ADDR, (uint8_t)lgw_regpage);
+    return LGW_REG_SUCCESS;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int reg_w_align32(void *com_target, uint8_t com_mux_mode, uint8_t com_mux_target, struct lgw_reg_s r, int32_t reg_value) {
+    int com_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 */
+        com_stat += lgw_com_w(com_target, com_mux_mode, com_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] */
+        com_stat += lgw_com_r(com_target, com_mux_mode, com_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 */
+        com_stat += lgw_com_w(com_target, com_mux_mode, com_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);
+        }
+        com_stat += lgw_com_wb(com_target, com_mux_mode, com_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 com_stat;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int reg_r_align32(void *com_target, uint8_t com_mux_mode, uint8_t com_mux_target, struct lgw_reg_s r, int32_t *reg_value) {
+    int com_stat = LGW_COM_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 */
+        com_stat += lgw_com_r(com_target, com_mux_mode, com_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 */
+        com_stat += lgw_com_rb(com_target, com_mux_mode, com_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 com_stat;
+}
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC FUNCTIONS DEFINITION ------------------------------------------ */
+
+/* Concentrator connect */
+int lgw_connect(const char *com_path) {
+    uint8_t uid[8];
+    int com_stat = LGW_COM_SUCCESS;
+    uint8_t u = 0;
+
+    DEBUG_MSG("Note: Connecting to concentrator...\n");
+
+    /* check COM link status */
+    if (lgw_com_target != NULL) {
+        DEBUG_MSG("WARNING: concentrator was already connected\n");
+        lgw_com_close(lgw_com_target);
+    }
+
+    /* open the COM link */
+    com_stat = lgw_com_open(&lgw_com_target, com_path);
+    if (com_stat != LGW_COM_SUCCESS) {
+        DEBUG_MSG("ERROR: FAIL TO CONNECT CONCENTRATOR\n");
+        return LGW_REG_ERROR;
+    }
+
+    DEBUG_PRINTF("Note: %s opened successfully\n", com_path);
+
+    /* check MCU FW version */
+    com_stat = lgw_mcu_get_unique_id(&uid[0]);
+    if (com_stat != LGW_COM_SUCCESS) {
+        DEBUG_MSG("ERROR: MCU FW VERSION CHECK FAILED\n");
+        return LGW_REG_ERROR;
+    }
+
+    DEBUG_PRINTF("Note: MCU firmware version checked: 0x%X\n", STM32FWVERSION);
+
+    lgw_com_mux_mode = LGW_COM_MUX_MODE0;
+
+    /* check SX1301 version */
+    com_stat = lgw_com_r(lgw_com_target, lgw_com_mux_mode, LGW_COM_MUX_TARGET_SX1301, loregs[LGW_VERSION].addr, &u);
+    if (com_stat != LGW_COM_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 */
+    com_stat = lgw_com_w(lgw_com_target, lgw_com_mux_mode, LGW_COM_MUX_TARGET_SX1301, loregs[LGW_PAGE_REG].addr, 0);
+    if (com_stat != LGW_COM_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_com_target != NULL) {
+        /* reset MCU */
+        lgw_mcu_reset();
+        /* close COM bridge immediatly after reset to avoid re-enumeration
+        before close */
+        lgw_com_close(lgw_com_target);
+        /* Wait for MCU reset and COM initialization to be complete before
+        returning to avoid trying to restart while MCU is still starting up */
+        wait_ms(MCU_DELAY_COM_INIT + MCU_DELAY_RESET);
+        /* exit */
+        lgw_com_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_com_target == NULL) || (lgw_regpage < 0)) {
+        DEBUG_MSG("ERROR: CONCENTRATOR UNCONNECTED\n");
+        return LGW_REG_ERROR;
+    }
+    lgw_com_w(lgw_com_target, lgw_com_mux_mode, LGW_COM_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_com_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: %d (%x) default: %d (%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 com_stat = LGW_COM_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_com_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)) {
+        com_stat += page_switch(r.page);
+    }
+
+    com_stat += reg_w_align32(lgw_com_target, lgw_com_mux_mode, LGW_COM_MUX_TARGET_SX1301, r, reg_value);
+
+    if (com_stat != LGW_COM_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 com_stat = LGW_COM_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_com_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)) {
+        com_stat += page_switch(r.page);
+    }
+
+    com_stat += reg_r_align32(lgw_com_target, lgw_com_mux_mode, LGW_COM_MUX_TARGET_SX1301, r, reg_value);
+
+    if (com_stat != LGW_COM_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 com_stat = LGW_COM_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_com_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)) {
+        com_stat += page_switch(r.page);
+    }
+
+    /* do the burst write */
+    com_stat += lgw_com_wb(lgw_com_target, lgw_com_mux_mode, LGW_COM_MUX_TARGET_SX1301, r.addr, data, size);
+
+    if (com_stat != LGW_COM_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 com_stat = LGW_COM_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_com_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)) {
+        com_stat += page_switch(r.page);
+    }
+
+    /* do the burst read */
+    com_stat += lgw_com_rb(lgw_com_target, lgw_com_mux_mode, LGW_COM_MUX_TARGET_SX1301, r.addr, data, size);
+
+    if (com_stat != LGW_COM_SUCCESS) {
+        DEBUG_MSG("ERROR: SPI ERROR DURING REGISTER BURST READ\n");
+        return LGW_REG_ERROR;
+    } else {
+        return LGW_REG_SUCCESS;
+    }
+}
+
+/* --- EOF ------------------------------------------------------------------ */
diff -r 000000000000 -r 102b50f941d0 libloragw/tst/test_loragw_cal.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libloragw/tst/test_loragw_cal.c	Wed Apr 11 14:38:42 2018 +0000
@@ -0,0 +1,768 @@
+/*
+ / _____)             _              | |
+( (____  _____ ____ _| |_ _____  ____| |__
+ \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+  (C)2017 Semtech-Cycleo
+
+Description:
+    Minimum test program for the loragw_cal 'library'
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+
+*/
+
+
+/* -------------------------------------------------------------------------- */
+/* --- 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 COM_PATH_DEFAULT        "/dev/ttyACM0"
+#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(" -d <path> COM device to be used to access the concentrator board\n");
+    printf("            => default path: " COM_PATH_DEFAULT "\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;
+
+    /* COM interfaces */
+    const char com_path_default[] = COM_PATH_DEFAULT;
+    const char *com_path = com_path_default;
+
+    /* 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:d:")) != -1) {
+        switch (i) {
+            case 'h':
+                usage();
+                return -1;
+                break;
+            case 'd':
+                if (optarg != NULL) {
+                    com_path = optarg;
+                }
+                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 */
+
+    /* Open communication bridge */
+    x = lgw_connect(com_path);
+    if (x == -1) {
+        printf("ERROR: FAIL TO CONNECT BOARD ON %s\n", com_path);
+        return -1;
+    }
+
+    /* 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));
+
+    /* 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 -r 000000000000 -r 102b50f941d0 libloragw/tst/test_loragw_hal.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libloragw/tst/test_loragw_hal.c	Wed Apr 11 14:38:42 2018 +0000
@@ -0,0 +1,459 @@
+/*
+ / _____)             _              | |
+( (____  _____ ____ _| |_ _____  ____| |__
+ \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+  (C)2017 Semtech-Cycleo
+
+Description:
+    Minimum test program for the loragw_hal 'library'
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+
+*/
+
+
+/* -------------------------------------------------------------------------- */
+/* --- 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 COM_PATH_DEFAULT    "/dev/ttyACM0"
+#define DEFAULT_RSSI_OFFSET 0.0
+
+/* -------------------------------------------------------------------------- */
+/* --- 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(" -d <path> COM device to be used to access the concentrator board\n");
+    printf("            => default path: " COM_PATH_DEFAULT "\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;
+
+    /* COM interfaces */
+    const char com_path_default[] = COM_PATH_DEFAULT;
+    const char *com_path = com_path_default;
+
+    /* parse command line options */
+    while ((i = getopt (argc, argv, "ha:b:t:r:k:d:")) != -1) {
+        switch (i) {
+            case 'h':
+                usage();
+                return -1;
+                break;
+            case 'd':
+                if (optarg != NULL) {
+                    com_path = optarg;
+                }
+                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());
+
+    /* Open communication bridge */
+    i = lgw_connect(com_path);
+    if (i == -1) {
+        printf("ERROR: FAIL TO CONNECT BOARD ON %s\n", com_path);
+        return -1;
+    }
+
+    /* 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;
+    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 #%u, 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 -r 000000000000 -r 102b50f941d0 libloragw/tst/test_loragw_reg.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libloragw/tst/test_loragw_reg.c	Wed Apr 11 14:38:42 2018 +0000
@@ -0,0 +1,174 @@
+/*
+ / _____)             _              | |
+( (____  _____ ____ _| |_ _____  ____| |__
+ \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+  (C)2017 Semtech-Cycleo
+
+Description:
+    Minimum test program for the loragw_reg 'library'
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+*/
+
+/* -------------------------------------------------------------------------- */
+/* --- DEPENDANCIES --------------------------------------------------------- */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <getopt.h>
+
+#include "loragw_reg.h"
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE CONSTANTS ---------------------------------------------------- */
+
+#define COM_PATH_DEFAULT    "/dev/ttyACM0"
+#define BURST_TEST_LENGTH    8192
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE FUNCTIONS DEFINITION ----------------------------------------- */
+
+/* describe command line options */
+void usage(void) {
+    printf("Available options:\n");
+    printf(" -h print this help\n");
+    printf(" -d <path> COM device to be used to access the concentrator board\n");
+    printf("            => default path: " COM_PATH_DEFAULT "\n");
+}
+
+/* -------------------------------------------------------------------------- */
+/* --- MAIN FUNCTION -------------------------------------------------------- */
+
+int main(int argc, char **argv) {
+    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;
+    /* COM interfaces */
+    const char com_path_default[] = COM_PATH_DEFAULT;
+    const char *com_path = com_path_default;
+
+    /* parse command line options */
+    while ((i = getopt (argc, argv, "hd:")) != -1) {
+        switch (i) {
+            case 'h':
+                usage();
+                return -1;
+                break;
+            case 'd':
+                if (optarg != NULL) {
+                    com_path = optarg;
+                }
+                break;
+            default:
+                printf("ERROR: argument parsing\n");
+                usage();
+                return -1;
+        }
+    }
+
+    printf("Beginning of test for loragw_reg.c\n");
+
+    i = lgw_connect(com_path);
+    if (i == -1) {
+        printf("ERROR: FAIL TO CONNECT BOARD ON %s\n", com_path);
+        return -1;
+    }
+
+    /* 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 -r 000000000000 -r 102b50f941d0 lora_indent.sh
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lora_indent.sh	Wed Apr 11 14:38:42 2018 +0000
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+# Convert file encoding type from dos 2 unix
+find . -regex '.*\.\(cpp\|h\|c\)' -exec dos2unix {} \;
+
+# Remove trailing spaces from source files
+find . -regex '.*\.\(cpp\|h\|c\)' -exec sed -i 's/[ \t]*$//g' {} \;
+
+# Replace tabs with 4-spaces in all source files
+find . -regex '.*\.\(cpp\|h\|c\)' -exec sed -i 's/\t/    /g' {} \;
+
+# indent code
+find . -regex '.*\.\(cpp\|h\|c\)' -exec astyle --indent-switches --indent-cases --pad-oper --pad-comma --add-brackets --indent=spaces=4 -A2 --mode=c  {} \;
diff -r 000000000000 -r 102b50f941d0 readme.md
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/readme.md	Wed Apr 11 14:38:42 2018 +0000
@@ -0,0 +1,143 @@
+	 / _____)             _              | |    
+	( (____  _____ ____ _| |_ _____  ____| |__  
+	 \____ \| ___ |    (_   _) ___ |/ ___)  _ \ 
+	 _____) ) ____| | | || |_| ____( (___| | | |
+	(______/|_____)_|_|_| \__)_____)\____)_| |_|
+	  (C)2013 Semtech-Cycleo
+
+LoRa Gateway project
+=====================
+
+## 1. Core library: libloragw
+-----------------------------
+
+This directory contains the sources of the library to build a LoRa Picocell
+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 implements the communication with the concentrator embedded MCU
+through a serial port.
+
+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_com_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_boot ###
+
+This software is used to jump to the PicoCell Gateway bootloader for programming
+the MCU with a new firmware.
+Please refer to the readme of picoGW_mcu repository for more information about
+MCU flash programming.
+
+### 2.6. util_chip_id ###
+
+This software is used to obtain the unique id of the PicoCell gateway (the
+64 bits unique id extracted from the STM32 unique id registers).
+
+## 4. User Guide
+----------------
+
+[A detailed PicoCell GW user guide is available here](http://www.semtech.com/images/datasheet/picocell_gateway_user_guide.pdf)
+
+## 5. Changelog
+---------------
+
+### v0.2.2  ###
+
+* HAL: updated MCU firmware version to match with picoGW_mcu V0.2.1 release.
+
+### v0.2.1  ###
+
+* HAL: Fixed bug in lgw_mcu_receive() which was preventing from fetching more
+than 2 packets simultaneously.
+
+### v0.2.0  ###
+
+* HAL: reverted AGC FW to version 4, as v5 was necessary to fix a HW bug which
+has been fixed since rev V02A of the picoCell reference design.
+* HAL: fixed a bug lgw_com_send_command() function to prevent from hanging when
+writing on the COM link was not possible.
+* HAL: fixed memory alignment on FSK syncword configuration.
+
+### v0.1.2  ###
+
+* HAL: fixed a wrong copy size and position of MCU unique ID in lgw_mcu_get_unique_id().
+* HAL: disabled some logs.
+
+### v0.1.1  ###
+
+* HAL: fixed MCU command wrong size in lgw_mcu_commit_radio_calibration().
+* HAL: fixed MCU reset sequence to wait for MCU to complete reset and reinit
+the communication bridge before exiting. This is to avoid issues when restarting
+the concentrator after exit.
+
+### v0.1.0  ###
+
+* HAL: code clean-up/refactoring
+* HAL: serial port configuration to handle both USB or UART communication with
+mcu.
+* util_boot: only used to jump to the MCU bootloader.
+* util_chip_id: no more command line parameter, just print the PicoCell GW
+unique ID on the console.
+* HAL/util_*: added a parameter to lgw_connect() function to specify the COM
+device path to be used to communicate with the concentrator board (tty...).
+
+### v0.0.1  ###
+
+* Initial release
+
+
+## 6. 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 -r 000000000000 -r 102b50f941d0 util_boot/Makefile
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/util_boot/Makefile	Wed Apr 11 14:38:42 2018 +0000
@@ -0,0 +1,66 @@
+### Application-specific constants
+
+APP_NAME := util_boot
+
+### 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 -r 000000000000 -r 102b50f941d0 util_boot/readme.md
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/util_boot/readme.md	Wed Apr 11 14:38:42 2018 +0000
@@ -0,0 +1,55 @@
+	  ______                              _
+	 / _____)             _              | |
+	( (____  _____ ____ _| |_ _____  ____| |__
+	 \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+	 _____) ) ____| | | || |_| ____( (___| | | |
+	(______/|_____)_|_|_| \__)_____)\____)_| |_|
+	  (C)2014 Semtech-Cycleo
+
+util_boot program for LoRa concentrator
+===========================================
+
+
+1. Introduction
+----------------
+
+This software is used to jump to the PicoCell Gateway bootloader in order to
+program the MCU flash with a new firmware.
+
+
+2. Usage
+--------
+
+See command line help to get the list of all available options:
+./util_boot -h
+
+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 -r 000000000000 -r 102b50f941d0 util_boot/src/util_boot.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/util_boot/src/util_boot.c	Wed Apr 11 14:38:42 2018 +0000
@@ -0,0 +1,127 @@
+/*
+ / _____)             _              | |
+( (____  _____ ____ _| |_ _____  ____| |__
+ \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+  (C)2017 Semtech-Cycleo
+
+Description:
+ Utility to jump to the PicoCell MCU bootloader
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+*/
+
+
+/* -------------------------------------------------------------------------- */
+/* --- 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 <stdio.h>      /* printf fprintf sprintf fopen fputs */
+#include <unistd.h>     /* getopt access */
+#include <stdlib.h>     /* EXIT_FAILURE */
+
+#include "loragw_com.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 COM_PATH_DEFAULT "/dev/ttyACM0"
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE VARIABLES (GLOBAL) ------------------------------------------- */
+
+void *lgw_com_target = NULL; /*! generic pointer to the COM device */
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE FUNCTIONS DECLARATION ---------------------------------------- */
+
+void usage (void);
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE FUNCTIONS DEFINITION ----------------------------------------- */
+
+/* describe command line options */
+void usage(void) {
+    MSG("Available options:\n");
+    MSG(" -h print this help\n");
+    MSG(" -d <path> COM device to be used to access the concentrator board\n");
+    MSG("            => default path: " COM_PATH_DEFAULT "\n");
+}
+
+/* -------------------------------------------------------------------------- */
+/* --- MAIN FUNCTION -------------------------------------------------------- */
+
+int main(int argc, char **argv) {
+    int i, x;
+    lgw_com_cmd_t cmd;
+    lgw_com_ans_t ans;
+    /* COM interfaces */
+    const char com_path_default[] = COM_PATH_DEFAULT;
+    const char *com_path = com_path_default;
+
+    while ((i = getopt (argc, argv, "hd:")) != -1) {
+        switch (i) {
+            case 'h':
+                usage();
+                return EXIT_FAILURE;
+                break;
+
+            case 'd':
+                if (optarg != NULL) {
+                    com_path = optarg;
+                }
+                break;
+
+            default:
+                MSG("ERROR: argument parsing use -h option for help\n");
+                usage();
+                return EXIT_FAILURE;
+        }
+    }
+
+    /* Open communication bridge */
+    x = lgw_com_open(&lgw_com_target, com_path);
+    if (x == LGW_COM_ERROR) {
+        printf("ERROR: FAIL TO CONNECT BOARD ON %s\n", com_path);
+        return -1;
+    }
+
+    /* prepare command to jump to bootloader */
+    cmd.id = 'n';
+    cmd.len_msb = 0;
+    cmd.len_lsb = 0;
+    cmd.address = 0;
+    /* send command to MCU */
+    x = lgw_com_send_command(lgw_com_target, cmd, &ans);
+    if (x == LGW_COM_ERROR) {
+        printf("ERROR: FAIL TO SEND COMMAND\n");
+        return -1;
+    }
+
+    /* Close communication bridge */
+    x = lgw_com_close(lgw_com_target);
+    if (x == LGW_COM_ERROR) {
+        printf("ERROR: FAIL TO DISCONNECT BOARD\n");
+        return -1;
+    }
+
+    return EXIT_SUCCESS;
+}
+
+/* --- EOF ------------------------------------------------------------------ */
+
+
diff -r 000000000000 -r 102b50f941d0 util_chip_id/Makefile
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/util_chip_id/Makefile	Wed Apr 11 14:38:42 2018 +0000
@@ -0,0 +1,66 @@
+### Application-specific constants
+
+APP_NAME := util_chip_id
+
+### 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 -r 000000000000 -r 102b50f941d0 util_chip_id/readme.md
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/util_chip_id/readme.md	Wed Apr 11 14:38:42 2018 +0000
@@ -0,0 +1,58 @@
+	  ______                              _
+	 / _____)             _              | |
+	( (____  _____ ____ _| |_ _____  ____| |__
+	 \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+	 _____) ) ____| | | || |_| ____( (___| | | |
+	(______/|_____)_|_|_| \__)_____)\____)_| |_|
+	  (C)2014 Semtech-Cycleo
+
+util_chip_id program for LoRa concentrator
+===========================================
+
+
+1. Introduction
+----------------
+
+This software is used to obtain the unique id of the PicoCell gateway.
+64 bits unique id extracts from the STM32 uinque id registers.
+
+
+2. Usage
+--------
+
+See command line help to get the list of all available options:
+./util_chip_id -h
+
+example
+./util_chip_id -l
+
+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 -r 000000000000 -r 102b50f941d0 util_chip_id/src/util_chip_id.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/util_chip_id/src/util_chip_id.c	Wed Apr 11 14:38:42 2018 +0000
@@ -0,0 +1,119 @@
+/*
+/ _____)             _              | |
+( (____  _____ ____ _| |_ _____  ____| |__
+\____ \| ___ |    (_   _) ___ |/ ___)  _ \
+_____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+ (C)2013 Semtech-Cycleo
+
+Description:
+  Get unique ID of the PicoCell gateway board
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+*/
+
+
+/* -------------------------------------------------------------------------- */
+/* --- 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"
+#include "loragw_mcu.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 COM_PATH_DEFAULT "/dev/ttyACM0"
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE VARIABLES (GLOBAL) ------------------------------------------- */
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE FUNCTIONS DECLARATION ---------------------------------------- */
+
+void usage (void);
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE FUNCTIONS DEFINITION ----------------------------------------- */
+
+/* describe command line options */
+void usage(void) {
+    MSG("Available options:\n");
+    MSG(" -h print this help\n");
+    MSG(" -d <path> COM device to be used to access the concentrator board\n");
+    MSG("            => default path: " COM_PATH_DEFAULT "\n");
+    MSG(" -l generate a new guid.json file\n");
+    MSG(" -p print the ID of the PicoCell gateway\n");
+}
+
+/* -------------------------------------------------------------------------- */
+/* --- MAIN FUNCTION -------------------------------------------------------- */
+
+int main(int argc, char **argv) {
+    int i, x;
+    uint8_t uid[8];
+    /* COM interfaces */
+    const char com_path_default[] = COM_PATH_DEFAULT;
+    const char *com_path = com_path_default;
+
+    while ((i = getopt (argc, argv, "hd:")) != -1) {
+        switch (i) {
+            case 'h':
+                usage();
+                return EXIT_FAILURE;
+                break;
+
+            case 'd':
+                if (optarg != NULL) {
+                    com_path = optarg;
+                }
+                break;
+
+            default:
+                MSG("ERROR: argument parsing use -h option for help\n");
+                usage();
+                return EXIT_FAILURE;
+        }
+    }
+
+    x = lgw_connect(com_path);
+    if (x == -1) {
+        printf("ERROR: FAIL TO CONNECT BOARD ON %s\n", com_path);
+        return -1;
+    }
+
+    lgw_mcu_get_unique_id(&uid[0]);
+    printf("%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x\n", uid[0], uid[1], uid[2], uid[3], uid[4], uid[5], uid[6], uid[7]);
+
+    x = lgw_disconnect();
+    if (x == -1) {
+        printf("ERROR: FAIL TO DISCONNECT BOARD\n");
+        return -1;
+    }
+
+    return EXIT_SUCCESS;
+}
+
+/* --- EOF ------------------------------------------------------------------ */
+
+
diff -r 000000000000 -r 102b50f941d0 util_com_stress/Makefile
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/util_com_stress/Makefile	Wed Apr 11 14:38:42 2018 +0000
@@ -0,0 +1,66 @@
+### Application-specific constants
+
+APP_NAME := util_com_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 -r 000000000000 -r 102b50f941d0 util_com_stress/readme.md
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/util_com_stress/readme.md	Wed Apr 11 14:38:42 2018 +0000
@@ -0,0 +1,91 @@
+	 / _____)             _              | |    
+	( (____  _____ ____ _| |_ _____  ____| |__  
+	 \____ \| ___ |    (_   _) ___ |/ ___)  _ \ 
+	 _____) ) ____| | | || |_| ____( (___| | | |
+	(______/|_____)_|_|_| \__)_____)\____)_| |_|
+	  (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.
+
+
+
+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 
+
+Test 4 > data buffer R/W 
+
+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 -r 000000000000 -r 102b50f941d0 util_com_stress/src/util_com_stress.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/util_com_stress/src/util_com_stress.c	Wed Apr 11 14:38:42 2018 +0000
@@ -0,0 +1,317 @@
+/*
+ / _____)             _              | |
+( (____  _____ ____ _| |_ _____  ____| |__
+ \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+  (C)2017 Semtech-Cycleo
+
+Description:
+   USB stress test
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+*/
+
+
+/* -------------------------------------------------------------------------- */
+/* --- 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 COM_PATH_DEFAULT        "/dev/ttyACM0"
+#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 */
+
+/* -------------------------------------------------------------------------- */
+/* --- 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(" -d <path> COM device to be used to access the concentrator board\n");
+    MSG("            => default path: " COM_PATH_DEFAULT "\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];
+
+    /* COM interfaces */
+    const char com_path_default[] = COM_PATH_DEFAULT;
+    const char *com_path = com_path_default;
+
+    /* parse command line options */
+    while ((i = getopt (argc, argv, "ht:d:")) != -1) {
+        switch (i) {
+            case 'h':
+                usage();
+                return EXIT_FAILURE;
+                break;
+
+            case 'd':
+                if (optarg != NULL) {
+                    com_path = optarg;
+                }
+                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(com_path);
+    if (i != LGW_REG_SUCCESS) {
+        MSG("ERROR: lgw_connect() did not return SUCCESS ON %s\n", com_path);
+        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 */
+        int bufftest = 5;
+        while ((quit_sig != 1) && (exit_sig != 1)) {
+            if(bufftest < BUFF_SIZE) {
+                bufftest++;
+            } else {
+                bufftest = 5;
+            }
+
+            for (i = 0; i < bufftest; ++i) {
+                test_buff[i] = rand() & 0xFF;
+            }
+            printf("Cycle %i > ", cycle_number);
+            test_addr = rand() & 0x0000FFFF;
+            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, bufftest);
+
+            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, bufftest);
+            for (i = 0; ((i < bufftest) && (test_buff[i] == read_buff[i])); ++i);
+            if (i != bufftest) {
+                printf("error during the buffer comparison\n");
+                printf("Written values:\n");
+                for (i = 0; i < bufftest; ++i) {
+                    printf(" %02X ", test_buff[i]);
+                    if (i % 16 == 15) {
+                        printf("\n");
+                    }
+                }
+                printf("\n");
+                printf("Read values:\n");
+                for (i = 0; i < bufftest; ++i) {
+                    printf(" %02X ", (uint8_t)(test_buff[i] - 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, bufftest);
+                printf("Re-read values:\n");
+                for (i = 0; i < bufftest; ++i) {
+                    printf(" %02X ", (uint8_t)(test_buff[i] - read_buff[i]));
+                    if (i % 16 == 15) {
+                        printf("\n");
+                    }
+                }
+                printf("\n");
+                i = lgw_disconnect();
+                return EXIT_FAILURE;
+            } else {
+                printf("did a %i-bytes R/W on a data buffer with no error\n", bufftest);
+                ++cycle_number;
+            }
+        }
+    } else {
+        MSG("ERROR: invalid test number\n");
+        usage();
+    }
+
+    /* 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 concentrator SPI stress-test program\n");
+    return EXIT_SUCCESS;
+}
+
+/* --- EOF ------------------------------------------------------------------ */
+
diff -r 000000000000 -r 102b50f941d0 util_pkt_logger/Makefile
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/util_pkt_logger/Makefile	Wed Apr 11 14:38:42 2018 +0000
@@ -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 -r 000000000000 -r 102b50f941d0 util_pkt_logger/global_conf.json
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/util_pkt_logger/global_conf.json	Wed Apr 11 14:38:42 2018 +0000
@@ -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 -r 000000000000 -r 102b50f941d0 util_pkt_logger/inc/parson.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/util_pkt_logger/inc/parson.h	Wed Apr 11 14:38:42 2018 +0000
@@ -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 -r 000000000000 -r 102b50f941d0 util_pkt_logger/local_conf.json
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/util_pkt_logger/local_conf.json	Wed Apr 11 14:38:42 2018 +0000
@@ -0,0 +1,5 @@
+{
+    "gateway_conf": {
+        "gateway_ID": "AA555A0000000101"
+    }
+}
diff -r 000000000000 -r 102b50f941d0 util_pkt_logger/readme.md
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/util_pkt_logger/readme.md	Wed Apr 11 14:38:42 2018 +0000
@@ -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 -r 000000000000 -r 102b50f941d0 util_pkt_logger/src/parson.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/util_pkt_logger/src/parson.c	Wed Apr 11 14:38:42 2018 +0000
@@ -0,0 +1,1919 @@
+/*
+ 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 -r 000000000000 -r 102b50f941d0 util_pkt_logger/src/util_pkt_logger.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/util_pkt_logger/src/util_pkt_logger.c	Wed Apr 11 14:38:42 2018 +0000
@@ -0,0 +1,738 @@
+/*
+ / _____)             _              | |
+( (____  _____ ____ _| |_ _____  ____| |__
+ \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+  (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
+*/
+
+
+/* -------------------------------------------------------------------------- */
+/* --- 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"
+#include "loragw_reg.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 CONSTANTS ---------------------------------------------------- */
+
+#define COM_PATH_DEFAULT "/dev/ttyACM0"
+
+/* -------------------------------------------------------------------------- */
+/* --- 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 exit_cleanup(void) {
+    MSG("INFO: Stopping concentrator\n");
+    lgw_stop();
+}
+
+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);
+            } else {
+                rfconf.tx_enable = false;
+            }
+            MSG("INFO: radio %i enabled (type %s), center frequency %u, RSSI offset %f, tx enabled %d\n", i, str, rfconf.freq_hz, rfconf.rssi_offset, rfconf.tx_enable);
+        }
+        /* 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(" -d <path> COM device to be used to access the concentrator board\n");
+    printf("            => default path: " COM_PATH_DEFAULT "\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;
+
+    /* COM interfaces */
+    const char com_path_default[] = COM_PATH_DEFAULT;
+    const char *com_path = com_path_default;
+
+    /* parse command line options */
+    while ((i = getopt (argc, argv, "hr:d:")) != -1) {
+        switch (i) {
+            case 'h':
+                usage();
+                return EXIT_FAILURE;
+                break;
+
+            case 'd':
+                if (optarg != NULL) {
+                    com_path = optarg;
+                }
+                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;
+        }
+    }
+
+    /* register function to be called for exit cleanups */
+    atexit(exit_cleanup);
+
+    /* 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);
+
+    /* Open communication bridge */
+    i = lgw_connect(com_path);
+    if (i == -1) {
+        printf("ERROR: FAIL TO CONNECT BOARD ON %s\n", com_path);
+        exit(EXIT_FAILURE);
+    }
+
+    /* 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);
+        exit(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");
+        exit(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");
+            exit(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");
+    exit(EXIT_SUCCESS);
+}
+
+/* --- EOF ------------------------------------------------------------------ */
diff -r 000000000000 -r 102b50f941d0 util_tx_continuous/Makefile
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/util_tx_continuous/Makefile	Wed Apr 11 14:38:42 2018 +0000
@@ -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 -r 000000000000 -r 102b50f941d0 util_tx_continuous/readme.md
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/util_tx_continuous/readme.md	Wed Apr 11 14:38:42 2018 +0000
@@ -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 -r 000000000000 -r 102b50f941d0 util_tx_continuous/src/util_tx_continuous.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/util_tx_continuous/src/util_tx_continuous.c	Wed Apr 11 14:38:42 2018 +0000
@@ -0,0 +1,462 @@
+/*
+  ______                              _
+ / _____)             _              | |
+( (____  _____ ____ _| |_ _____  ____| |__
+ \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+  (C)2014 Semtech-Cycleo
+
+Description:
+    SX1301 tx continuous utility
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+*/
+
+
+/* -------------------------------------------------------------------------- */
+/* --- 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 COM_PATH_DEFAULT        "/dev/ttyACM0"
+
+/* -------------------------------------------------------------------------- */
+/* --- 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 exit_cleanup(void);
+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},
+        {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;
+
+    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;
+
+    /* COM interfaces */
+    const char com_path_default[] = COM_PATH_DEFAULT;
+    const char *com_path = com_path_default;
+
+    /* Parse command line options */
+    while ((i = getopt_long (argc, argv, "hf:r:d:", long_options, &option_index)) != -1) {
+        switch (i) {
+            case 'h':
+                printf("~~~ Library version string~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n");
+                printf(" %s\n", lgw_version_info());
+                printf("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n");
+                printf(" -d      <path>   COM device to be used to access the concentrator board\n");
+                printf("                    => default path: " COM_PATH_DEFAULT "\n");
+                printf(" -f      <float>  Tx RF frequency in MHz [800:1000]\n");
+                printf(" -r      <int>    Radio type (SX1255:1255, SX1257:1257)\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, "%63s", 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 {
+                    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;
+
+            case 'd':
+                if (optarg != NULL) {
+                    com_path = optarg;
+                }
+                break;
+
+            default:
+                printf("ERROR: argument parsing options. Use -h to print help\n");
+                return EXIT_FAILURE;
+        }
+    }
+
+    /* register function to be called for exit cleanups */
+    atexit(exit_cleanup);
+
+    /* 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 );
+
+    /* Open communication bridge */
+    i = lgw_connect(com_path);
+    if (i == -1) {
+        printf("ERROR: FAIL TO CONNECT BOARD ON %s\n", com_path);
+        exit(EXIT_FAILURE);
+    }
+
+    /* 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;
+    lgw_rxrf_setconf(TX_RF_CHAIN, rfconf);
+
+    /* Tx gain LUT */
+    memset(&txlut, 0, sizeof txlut);
+    txlut.size = 16;
+    int kk;
+    for (kk = 0; kk < 16; kk++) {
+        txlut.lut[kk].dig_gain = g_dig;
+        txlut.lut[kk].pa_gain = g_pa;
+        txlut.lut[kk].dac_gain = g_dac;
+        txlut.lut[kk].mix_gain = g_mix;
+        txlut.lut[kk].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");
+        exit(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");
+                exit(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");
+                exit(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);
+    if (i == -1) {
+        printf("ERROR: FAIL TO START TX...\n");
+        exit(EXIT_FAILURE);
+    }
+
+    /* Recap all settings */
+    printf("SX1301 library version: %s\n", lgw_version_info());
+    if (strcmp(mod, "LORA") == 0) {
+        printf("Modulation: LORA SF:%u BW:%u 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);
+    }
+
+    exit(EXIT_SUCCESS);
+}
+
+/* -------------------------------------------------------------------------- */
+/* --- SUBFUNCTIONS DEFINITION ---------------------------------------------- */
+
+static void exit_cleanup(void) {
+    printf("Stopping concentrator.\n");
+    lgw_stop();
+}
+
+static void sig_handler(int sigio) {
+    if (sigio == SIGQUIT) {
+        quit_sig = 1;
+    } else if((sigio == SIGINT) || (sigio == SIGTERM)) {
+        exit_sig = 1;
+    }
+}
+
+/* --- EOF ------------------------------------------------------------------ */
diff -r 000000000000 -r 102b50f941d0 util_tx_test/Makefile
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/util_tx_test/Makefile	Wed Apr 11 14:38:42 2018 +0000
@@ -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 -r 000000000000 -r 102b50f941d0 util_tx_test/readme.md
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/util_tx_test/readme.md	Wed Apr 11 14:38:42 2018 +0000
@@ -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 -r 000000000000 -r 102b50f941d0 util_tx_test/src/util_tx_test.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/util_tx_test/src/util_tx_test.c	Wed Apr 11 14:38:42 2018 +0000
@@ -0,0 +1,567 @@
+/*
+ / _____)             _              | |
+( (____  _____ ____ _| |_ _____  ____| |__
+ \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+  (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
+*/
+
+
+/* -------------------------------------------------------------------------- */
+/* --- 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 COM_PATH_DEFAULT            "/dev/ttyACM0"
+#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_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 = 0,
+        .rf_power = -2
+    },
+    .lut[1] = {
+        .dig_gain = 0,
+        .pa_gain = 0,
+        .dac_gain = 3,
+        .mix_gain = 5,
+        .rf_power = 8
+    },
+    .lut[2] = {
+        .dig_gain = 0,
+        .pa_gain = 0,
+        .dac_gain = 3,
+        .mix_gain = 10,
+        .rf_power = 18
+    },
+    .lut[3] = {
+        .dig_gain = 0,
+        .pa_gain = 0,
+        .dac_gain = 3,
+        .mix_gain = 11,
+        .rf_power = 20
+    },
+    .lut[4] = {
+        .dig_gain = 0,
+        .pa_gain = 0,
+        .dac_gain = 3,
+        .mix_gain = 12,
+        .rf_power = 21
+    }
+};
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE FUNCTIONS DECLARATION ---------------------------------------- */
+
+static void sig_handler(int sigio);
+
+void usage (void);
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE FUNCTIONS DEFINITION ----------------------------------------- */
+
+static void exit_cleanup(void) {
+    printf("Exiting LoRa concentrator TX test program\n");
+
+    /* clean up before leaving */
+    lgw_stop();
+}
+
+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(" -d         <path>  COM device to be used to access the concentrator board\n");
+    printf("                      => default path: " COM_PATH_DEFAULT "\n");
+    printf(" -r         <int>   radio type (SX1255:1255, SX1257:1257)\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");
+}
+
+/* -------------------------------------------------------------------------- */
+/* --- 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;
+
+    /* 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_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[] = {
+        {0, 0, 0, 0}
+    };
+
+    /* COM interfaces */
+    const char com_path_default[] = COM_PATH_DEFAULT;
+    const char *com_path = com_path_default;
+
+    /* parse command line options */
+    while ((i = getopt_long (argc, argv, "hif:m:b:s:c:p:l:z:t:x:r:k:D:q:d:", long_options, &option_index)) != -1) {
+        switch (i) {
+            case 'h':
+                usage();
+                return EXIT_FAILURE;
+                break;
+
+            case 'd':
+                if (optarg != NULL) {
+                    com_path = optarg;
+                }
+                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 'm': /* <str> Modulation type */
+                i = sscanf(optarg, "%63s", 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;
+        }
+    }
+
+    /* 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);
+    }
+
+    /* register function to be called for exit cleanups */
+    atexit(exit_cleanup);
+
+    /* 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);
+
+    /* Open the communication bridge */
+    i = lgw_connect(com_path);
+    if (i == -1) {
+        printf("ERROR: FAIL TO CONNECT BOARD ON %s\n", com_path);
+        exit(EXIT_FAILURE);
+    }
+
+    /* 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 = 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;
+        } 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");
+        exit(EXIT_FAILURE);
+    }
+
+    /* fill-up payload and parameters */
+    memset(&txpkt, 0, sizeof(txpkt));
+    txpkt.freq_hz = f_target;
+    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");
+                exit(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");
+                exit(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");
+                exit(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 */
+
+        /* 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");
+            exit(EXIT_FAILURE);
+        } 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;
+        }
+    }
+
+    printf("Exiting LoRa concentrator TX test program\n");
+    exit(EXIT_SUCCESS);
+}
+
+/* --- EOF ------------------------------------------------------------------ */